Skip to content

Water Overlay Effects - Redux - #12918

Draft
kugamo wants to merge 17 commits into
cmss13-devs:masterfrom
kugamo:Soggy
Draft

Water Overlay Effects - Redux#12918
kugamo wants to merge 17 commits into
cmss13-devs:masterfrom
kugamo:Soggy

Conversation

@kugamo

@kugamo kugamo commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

About the pull request

Sequel to : #1593

This PR adds an efffect on mobs when they enter water which displays an overlay on them, the result being they look like they've entered the water. This is better I think than just walking and standing atop waters' surface. Applies to Humans, Xenos, Yautja, you name it.

This effect is further accentuated by moving affected mobs "down" into the water by dynamically changing the mob's pixel_y values, as well as also having some splash sprites that animate with the mob's movement.

Waters now will have depths, starting from 2 and 4 for the coasts, down to 8 for the shallow full water tiles (like LV 624's river), then down to 12 for underwater slopes leading further down to 18 for the deepest water turfs

dreamseeker_QORakF4oHd dreamseeker_BExlb1ngyW dreamseeker_lQYyt0gWKd dreamseeker_YYUZfbTTeW dreamseeker_ajDg1koM8v

Water overlays will display on resting humans, but not resting xenos (would require custom culling masks be made for each xeno type twice... and then also maintained). Very deep water will completely cover resting mobs and if the mob is alive they'll have a stream of bubbles (seemed out of scope to add making them drown, but the potential is there)

Camouflaged mobs will make their splashes invisible, but still give off sound (technical limitation, I tried making their splashes visible. Problem with how humans' sprites are constructed IG)

I also added some sounds for when moving through water, and giving them off can be avoided by walking when moving through water.

Under the hood:

Open turfs when created will check their depth (new variable) and if they have any will start registering signals for when something enters them. This signal will create a water overlay effect on the mob, which if it already exists just inherits data from the turf trying to place it on the mob. this effect once it exists starts registering signals for when its mob moves, and if the mob moves to a tile with no depth the effect gets removed.

Having a water overlay for every water turf in the game is a monumental task, not to mention some turfs use the same icon and are coded to behave differently... Instead of spriting each manually for each mob type and turf type, and creating a huge maintenance overhead I opted to create a subsystem that generates these overlays before the game begins. Creating about 1300 icons in a big list. (this could be further tuned down by only generating overlays for mapped in water turfs, but we'd have to include nightmare water turfs too, and pasted in map sections wouldnt get overlays idk.) It generates an icon for each mob texture size for each water turf type, as well as some special icons (like humans resting), and if the turf is deep enough a full water overlay.

At roundstart this subsystem also changes the layer of some turfs near water, this is to prevent mobs in water from visually clipping below this turfs if standing south of them while in water, since we actually DO want turfs south of mobs in water to clip over them, to achieve the mobs looking visually below the edge of those turfs. (I briefly considered having the effect change the layerings of nearby turfs, but that seemed extremely expensive)

I had to add in a ton of fiddly stuff to get the effects to update upon their mob resting, or buckled, or hauled etc

Explain why it's good for the game

It adds deeper immersion to maps and the setting by more accurately simulating water. It does away with the visually ugly and inexplicable bars of water that water turfs used to have but have since been broken for like 5 years.

This is a huge PR, with almost 60 changed files... and I am back from a rather long hiatus from coding for CM so my style is probably out of date, and or many little stupid mistakes. This is all to say I appreciate deeply anyone willing to lend their time for a review of this monster.

Some things to note: this doesnt affect obj at all, so things like roller beds and vehicles still move atop water which can kinda look silly. I plan to make follow up PR to this one for those things if this one goes through.

Humans
dreamseeker_nXjJO667oQ
dreamseeker_k3UKyuqz8Y

Xenos
dreamseeker_r7n81avLrd
dreamseeker_ti5JNyqowy

Also recorded some videos, so you all can hear the sounds

Humans in waters
https://youtu.be/iz4-UHSBAdE

Demoing no splash sounds when walking
https://youtu.be/LdYO1WTsPS8

Xeno in water
https://youtu.be/2mIfjGF-Gcw?si=zVQuuvgjt8GVc0m2

Demoing overlay changing upon Trijent water changing
https://youtu.be/GR_JWQkwHWk

Changelog

🆑
add: Added water overlay effect
code: Water overlay effect code, and subsystem
imageadd: Added splash sprites for mobs in water
imagedel: Removed depreciated and broken water overlays
soundadd: Splashes and such for moving through water
/:cl:

@kugamo
kugamo requested a review from fira as a code owner August 13, 2026 11:40
@github-project-automation github-project-automation Bot moved this to Awaiting Review in Review Backlog Aug 13, 2026
@cmss13-ci cmss13-ci Bot added Sprites Remove the soul from the game. Sound Blast 5 minutes of bass boosted music to our players Feature Feature coder badge Code Improvement Make the code longer labels Aug 13, 2026
@cmss13-ci cmss13-ci Bot added the size/XL Denotes a PR that changes 799-1999 lines, ignoring generated files. label Aug 13, 2026

@Drulikar Drulikar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a full review but I was interested in seeing what was causing the failures.

Comment thread code/datums/effects/_effects.dm Outdated
Comment thread code/datums/components/footstep.dm
Comment thread code/controllers/subsystem/water_overlays.dm Outdated
Comment thread code/controllers/subsystem/water_overlays.dm Outdated
Comment thread code/controllers/subsystem/water_overlays.dm Outdated
Comment thread code/game/turfs/open.dm Outdated
Comment thread code/modules/movement/launching/launching.dm Outdated
Comment thread code/modules/mob/living/living.dm Outdated
Comment thread code/game/atoms_movable.dm Outdated
Comment thread code/game/turfs/open.dm Outdated
@github-project-automation github-project-automation Bot moved this from Awaiting Review to Changes Requested in Review Backlog Aug 14, 2026
@Drulikar
Drulikar marked this pull request as draft August 14, 2026 05:22
@kugamo

kugamo commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Maybe I ought to add the effect on_enter even if buckled or tossed, and just make it invisible. Then have the effect catch COMSIG_MOVABLE_UNBUCKLE and check for if its being tossed every COMSIG_MOVABLE_MOVED. This instead of the flakey TURF_ENTERED signal sends im currently using for those scenarios.

But that still leaves nothing to use in the tossed scenario, since the throwing var isnt unset until after that signal is sent

Comment thread code/game/turfs/open.dm
Comment on lines +568 to +569
/mob/living/proc/get_lying_angle()
return lying_angle

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a proc? Would save us from the proc overhead if the var was just directly accessed since there is no other behavior going on here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mob's lying_angle is a protected value, and theres no other reliable way to tell which way a mob is resting without this. this is critical to know since we're adding an overlay which changes its appearance dependent on this

Comment thread code/modules/mob/living/carbon/xenomorph/update_icons.dm Outdated
Comment thread code/game/atoms_movable.dm Outdated
Comment thread code/game/turfs/turf.dm Outdated
Comment thread code/game/turfs/turf.dm Outdated
Comment thread code/game/turfs/turf.dm Outdated
Comment thread code/game/turfs/open.dm

RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), PROC_REF(play_simplestep))

/datum/component/footstep/InheritComponent(datum/component/C, i_am_originalsteps_ = 2, volume_ = 50, range_ = null, falloff_ = 1, footstep_sounds_ = "alien_footstep_large", drag_sounds_ = 'sound/effects/alien_dragsound_large.ogg', vary_ = rand(20000, 25000))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a typo here in the arguments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see it, sorry. can you tell me where exactly? :O

addtimer(CALLBACK(src, PROC_REF(destroy_effect)), lifetime)

/obj/effect/water_splash/proc/destroy_effect()
Destroy()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want qdel(src) here, don't call Destroy!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright, but thought it was best practice to let the inherit the destroy of its parents

return // Wait for completion
log_debug("Nightmare setup finished")

// shamelessly copying nightmare setup to run water overlay subsystems layering changes, and CRITICALLY: !!!AFTER nightmares!!!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally you should just hook this on the nightmare finished signal

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the nightmare finished signal" I couldnt find one.. I found COMSIG_NIGHTMARE_APPLYING_NODE but that from a glance seemed to be called everytime an individual nightmare was finished? idk nightmare code is an enigma to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Code Improvement Make the code longer Feature Feature coder badge size/XL Denotes a PR that changes 799-1999 lines, ignoring generated files. Sound Blast 5 minutes of bass boosted music to our players Sprites Remove the soul from the game.

Projects

Status: Changes Requested

Development

Successfully merging this pull request may close these issues.

5 participants