Skip to content
Draft
3 changes: 3 additions & 0 deletions code/__DEFINES/layers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

//#define AREA_LAYER 1

#define UNDER_WATER_TURF_LAYER 1.96
#define UNDER_WATER_MOB_LAYER 1.98

#define UNDER_TURF_LAYER 1.99

#define TURF_LAYER 2
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
#define SS_INIT_STICKY -30
#define SS_INIT_OBJECTIVES -32
#define SS_INIT_MINIMAP -34
#define SS_INIT_WATEROVERLAYS -40
#define SS_INIT_STATPANELS -98
#define SS_INIT_CHAT -100 //Should be last to ensure chat remains smooth during init.

Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/turf_flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#define TURF_BURNT (1<<6)
#define TURF_BREAKABLE (1<<7)
#define TURF_BROKEN (1<<8)
#define TURF_FULL_WATER (1<<9)
#define TURF_COASTLINE (1<<10)

//ChangeTurf options to change its behavior
#define CHANGETURF_DEFER_CHANGE (1<<0)
Expand Down
11 changes: 11 additions & 0 deletions code/__DEFINES/wateroverlays.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Wateroverlay global status
#define WATEROVERLAY_STATUS_STANDBY 0
#define WATEROVERLAY_STATUS_RUNNING 1
#define WATEROVERLAY_STATUS_DONE 2

#define DEPTH_LAND 0
#define DEPTH_COAST_SHALLOW -2
#define DEPTH_COAST_INTERMEDIATE -4
#define DEPTH_SHALLOW -8
#define DEPTH_INTERMEDIATE -12
#define DEPTH_DEEP -18
99 changes: 99 additions & 0 deletions code/__HELPERS/water_overlay_effects.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/proc/is_full_water(turf/potential_water)
if(!isturf(potential_water))
return FALSE
if(istype(potential_water, /turf/open))
var/turf/open/potential_open_water = potential_water
if(potential_open_water.covered)
return FALSE
return (potential_water.turf_flags & TURF_FULL_WATER)

/proc/is_coastline(turf/potential_coastline)
if(!isturf(potential_coastline))
return FALSE
if(istype(potential_coastline, /turf/open))
var/turf/open/potential_open_coastline = potential_coastline
if(potential_open_coastline.covered)
return FALSE
return (potential_coastline.turf_flags & TURF_COASTLINE)

/proc/is_water(turf/T)
return (is_full_water(T) || is_coastline(T))

/proc/handle_get_icon(recieved_icon, toxic) //I love Toxic code!!!
var/return_icon = recieved_icon
if(recieved_icon == 'icons/turf/floors/desert_water.dmi')
if(toxic == 1)
return_icon ='icons/turf/floors/desert_water_toxic.dmi'
else if(toxic == -1)
return_icon = 'icons/turf/floors/desert_water_transition.dmi'
return return_icon

/proc/handle_toxic_states(turf/in_turf) //adds duplicate states for toxic water turfs so we can handle toxic states
var/list/return_list = list(in_turf.type)
if(ispath(in_turf, /turf/open/gm/river/desert) || ispath(in_turf, /turf/open/desert/desert_shore))
return_list += in_turf.type
return_list += in_turf.type
return return_list

/* ////////////////////////// GENERATING ICONS TO BE USED IN WATER OVERLAYS /////////////////////////// generate_water_display_icons()
water turfs are hardcoded to only have certain depths, but the shorelines take from their fulltile varients ---> turf/open var/water_type
so for each water turf we generate a water overlay for each size mobs' textures can have: 32, 48, 64, and 88 ---> texture_sizes
in addition to those for extra deep water turfs we also generate an icon that will cover the mob completely
some mobs look weird with just the default overlay, so for those we generate additional overlays using unique culling masks ---> water_overlay_special
and lastly 2 more overlays for resting humans per waterturf. and there, all the overlays we'll every need all in one neat list :0) */

//currently it generates icons only for turfs on loaded maps, not counting nightmares
//which could concievably be lowered by having coasts of the same depth reroute to the same overlay... oh god, just imagining it hurts

/proc/generate_water_display_icons()
for(var/starting_type in SSwater_overlays.found_waters)
var/turf/open/starting_open_turf = starting_type //if theres a water turf thats not an open turf subtype someones messed up
if(starting_open_turf.depth == DEPTH_LAND)
continue //some turfs are water turfs, but have no depth... meaning no need for an overlay
var/toxic = -1
for(var/found_type in handle_toxic_states(starting_open_turf)) //if the water turf can be toxic, we need to add overlays for each possiblity
toxic++
var/usable_tox = toxic == 0 ? 0 : (toxic == 1 ? 1 : -1)
var/working_type = starting_open_turf.water_type ? starting_open_turf.water_type : found_type //handle rerouting
var/turf/open/working_T = working_type
for(var/texture_size in SSwater_overlays.texture_sizes)
// V V V V construct water texture V V V V
var/icon/sized_water_texture = icon(SSwater_overlays.water_overlay_icon_paths["[texture_size]"],"empty") //this is what will eventually be our water texture
var/icon/turf_texture = icon(handle_get_icon(working_T.icon, usable_tox), working_T.icon_state) //this is the actual texture we'll use to create the water texture
var/icon/subtraction_texture = icon(SSwater_overlays.water_overlay_icon_paths["[texture_size]"], "culling_mask") //this is the part of it we'll keep, rest will become "air"
var/texture_width = sized_water_texture.Width()
var/pieces = round(texture_width / 32) + (texture_width / 32 > round(texture_width / 32) ? 1 : 0) //since mobs wont always be 32x32 the water texture will need be build out of 32x32 parts
for(var/i=0, i<pieces, i++)
for(var/j=0, j<pieces, j++)
sized_water_texture.Blend(turf_texture, ICON_OVERLAY, (i*32)+1, (j*32)+1) //place our 32x32 textures on our water texture every 32 pixels
if(starting_open_turf.depth == DEPTH_DEEP)
SSwater_overlays.water_overlay_icons["[texture_size]_[found_type][usable_tox]_u"] = icon(sized_water_texture) // for the full water overlay

// V V V V construct depthed overlay for mob texture size V V V V
var/icon/culled_water = icon(sized_water_texture)
var/texture_hieght = sized_water_texture.Height()
subtraction_texture.Shift(SOUTH, (texture_hieght - abs(starting_open_turf.depth)-3), FALSE) //we move it down to "water level" if we're not using a custom mob culling mask
culled_water.AddAlphaMask(subtraction_texture)
SSwater_overlays.water_overlay_icons["[texture_size]_[found_type][usable_tox]"] = culled_water //this is the default overlays, made according to depth

// V V V V specialized water overlays V V V V
var/list/special_mob_masks = SSwater_overlays.water_overlay_special["[texture_size]"]
for(var/mob_type in special_mob_masks)
// * HUMANS RESTING * <-- this could be expanded later if someone wants to sprite 2 culling masks for every mob you want them on...
if(mob_type == /mob/living/carbon/human)
var/resting_key = starting_open_turf.depth >= -4 ? "coast" : "float"
var/icon/resting_east = icon(sized_water_texture)
var/icon/resting_west = icon(sized_water_texture)
resting_east.AddAlphaMask(icon(SSwater_overlays.water_overlay_icon_paths["[texture_size]"], "culling_[resting_key]_rest_e"))
resting_west.AddAlphaMask(icon(SSwater_overlays.water_overlay_icon_paths["[texture_size]"], "culling_[resting_key]_rest_w"))
SSwater_overlays.water_overlay_icons["32_[found_type][usable_tox]_[mob_type]_e"] = resting_east
SSwater_overlays.water_overlay_icons["32_[found_type][usable_tox]_[mob_type]_w"] = resting_west

// * water_overlay_special * these mobs look weird with the default overlays, we use special culling masks for them
if(special_mob_masks[mob_type])
var/icon/special_icon = icon(sized_water_texture)
var/icon/special_mask = icon(SSwater_overlays.water_overlay_icon_paths["[texture_size]"], special_mob_masks[mob_type])
special_icon.AddAlphaMask(special_mask)
SSwater_overlays.water_overlay_icons["[texture_size]_[found_type][usable_tox]_[mob_type]"] = special_icon

CHECK_TICK
11 changes: 11 additions & 0 deletions code/controllers/subsystem/ticker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ SUBSYSTEM_DEF(ticker)
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

if(SSwater_overlays.stat != WATEROVERLAY_STATUS_DONE)
if(SSwater_overlays.start_time && (world.time - SSwater_overlays.start_time) > 30 SECONDS)
SSwater_overlays.stat = WATEROVERLAY_STATUS_DONE
log_admin("Wateroverlay setup was cancelled as it took more than 30 seconds! Mobs might visually clip under turfs!")
else
var/ret = INVOKE_ASYNC(SSwater_overlays, TYPE_PROC_REF(/datum/controller/subsystem/water_overlays, gamestart_process))
if(!ret)
return // Wait for completion
log_debug("Wateroverlay turf layering changes finished")

if(current_state != GAME_STATE_PREGAME)
return
current_state = GAME_STATE_SETTING_UP
Expand Down
52 changes: 52 additions & 0 deletions code/controllers/subsystem/water_overlays.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
SUBSYSTEM_DEF(water_overlays)
name = "Water Overlays"
init_order = SS_INIT_WATEROVERLAYS
flags = SS_NO_FIRE
var/stat = WATEROVERLAY_STATUS_STANDBY
var/start_time = 0
var/list/turfs_to_process = list()
var/list/texture_sizes = list(32, 48, 64, 88)
var/list/found_waters = list()
var/list/water_overlay_icons = list()
var/list/water_overlay_special = list(
"32" = list(
/mob/living/carbon/human = null,
/mob/living/carbon/xenomorph/larva = "culling_larva",
),
"48" = list(
/mob/living/carbon/xenomorph/facehugger = "culling_facehugger",
),
"64" = list(),
"88" = list()
)
var/list/water_overlay_icon_paths = list(
"32" = 'icons/effects/water_overlay_effects/_32.dmi', //humans, etc
"48" = 'icons/effects/water_overlay_effects/_48.dmi', //facehugger, drone
"64" = 'icons/effects/water_overlay_effects/_64.dmi', //most xenos
"88" = 'icons/effects/water_overlay_effects/_88.dmi', //queen
)

/datum/controller/subsystem/water_overlays/Initialize()
return SS_INIT_SUCCESS

/datum/controller/subsystem/water_overlays/proc/gamestart_process()
start_time = world.time
stat = WATEROVERLAY_STATUS_RUNNING
for(var/turf/T in GLOB.turfs)
if(is_water(T))
found_waters |= T
for(var/direction in GLOB.alldirs)
var/turf/found_turf = get_step(T, direction)
if(found_turf && !is_water(found_turf))
turfs_to_process |= found_turf

generate_water_display_icons()

var/list/altered_turfs = list()
for(var/turf/current_turf in turfs_to_process)
if(current_turf in altered_turfs)
continue
altered_turfs |= current_turf.fix_water_clipping_layers(altered_turfs)
for(var/turf/current_turf in altered_turfs)
current_turf.fix_water_clipping_layers_final()
stat = WATEROVERLAY_STATUS_DONE
6 changes: 5 additions & 1 deletion code/datums/components/footstep.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

///Footstep component. Plays footsteps at parents location when it is appropriate.
/datum/component/footstep
dupe_mode = COMPONENT_DUPE_HIGHLANDER
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
///how many steps before the footstep sound is played
var/steps = 0
///volume of soundfile see playsound()
Expand All @@ -29,6 +29,10 @@

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

. = ..()
footstep_sounds = footstep_sounds_
Comment thread
kugamo marked this conversation as resolved.

/datum/component/footstep/proc/prepare_step()
var/turf/open/T = get_turf(parent)
if(!istype(T))
Expand Down
73 changes: 73 additions & 0 deletions code/datums/components/water_overlay_effect.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
///water_overlay_effect component. adds and removes
/datum/component/water_overlay_effect
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/datum/effects/water_overlay_effect/my_water_overlay_effect
var/turf_type //! Turf type the effect applies to


/datum/component/water_overlay_effect/Initialize(turf/input_turf, y_offset)
if(!istype(parent, /atom/movable))
return COMPONENT_INCOMPATIBLE
turf_type = input_turf.type
my_water_overlay_effect = new(parent)
my_water_overlay_effect.pixel_y_offset = y_offset
my_water_overlay_effect.update(get_turf(parent))

/datum/component/water_overlay_effect/Destroy()
. = ..()
my_water_overlay_effect.Destroy()

/datum/component/water_overlay_effect/InheritComponent(datum/component/C, i_am_original, turf/input_turf, y_offset)
. = ..()
var/will_update = FALSE
if(turf_type != input_turf.type)
turf_type = input_turf.type
will_update = TRUE
if(my_water_overlay_effect.pixel_y_offset != y_offset)
my_water_overlay_effect.pixel_y_offset = y_offset
will_update = TRUE
if(will_update)
my_water_overlay_effect.update(get_turf(parent))

/datum/component/water_overlay_effect/proc/handle_affected_mob_move(parent_source, oldloc, direction, forced)
SIGNAL_HANDLER
var/turf/open/gm/moved_to_turf = get_turf(parent_source)
if(moved_to_turf.depth >= DEPTH_LAND || moved_to_turf.covered)
Destroy()
return
var/mob/M = parent_source
if(M.m_intent == MOVE_INTENT_RUN) //walking doesnt make sounds from moving through water
var/soundname = moved_to_turf.depth >= DEPTH_COAST_INTERMEDIATE ? "shallowwading" : (moved_to_turf.depth >= DEPTH_SHALLOW ? "wading":"deepwading")
playsound(moved_to_turf, soundname, 10, 1, 10, falloff=1)

/datum/component/water_overlay_effect/proc/handle_resting_change()
var/turf/laid_on_turf = get_turf(parent)
if(ispath(laid_on_turf.type, /turf/open))
var/turf/open/open_laid_on_turf = laid_on_turf
my_water_overlay_effect.pixel_y_offset = open_laid_on_turf.depth
my_water_overlay_effect.update(laid_on_turf)

/datum/component/water_overlay_effect/proc/update_the_effect()
SIGNAL_HANDLER
var/turf/unbuckled_turf = get_turf(parent)
if(ispath(unbuckled_turf.type, /turf/open))
var/turf/open/open_buckled_turf = unbuckled_turf
my_water_overlay_effect.pixel_y_offset = open_buckled_turf.depth
my_water_overlay_effect.hidden = FALSE
my_water_overlay_effect.update(get_turf(parent))

/datum/component/water_overlay_effect/RegisterWithParent(datum/target)
. = ..()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_affected_mob_move))
RegisterSignal(parent, COMSIG_LIVING_SET_LYING_ANGLE, PROC_REF(handle_resting_change))
RegisterSignal(parent, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(handle_resting_change))
RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, PROC_REF(update_the_effect))
RegisterSignal(parent, COMSIG_MOB_UNHAULED, PROC_REF(update_the_effect))

/datum/component/water_overlay_effect/UnregisterFromParent(datum/source, force)
. = ..()
UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
UnregisterSignal(parent, COMSIG_LIVING_SET_LYING_ANGLE)
UnregisterSignal(parent, COMSIG_LIVING_SET_BODY_POSITION)
UnregisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE)
UnregisterSignal(parent, COMSIG_MOB_UNHAULED)
4 changes: 3 additions & 1 deletion code/datums/effects/_effects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define INF_DURATION 4 //An effect that lasts forever
#define NO_PROCESS_ON_DEATH 8 //Don't process while the mob is dead
#define DEL_ON_UNDEFIBBABLE 16 //Delete the effect when human mob is undefibbable
#define EFFECT_NO_PROCESS 32 // Dont process at all

/datum/effects
var/effect_name = "standard" //Name of the effect
Expand All @@ -42,7 +43,8 @@
if(!validate_atom(thing) || QDELETED(thing))
qdel(src)
return
START_PROCESSING(SSoldeffects, src)
if(!(flags & EFFECT_NO_PROCESS))
START_PROCESSING(SSeffects, src)

affected_atom = thing
LAZYADD(affected_atom.effects_list, src)
Expand Down
Loading
Loading