diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm index 46772087e5e..348ec948b4a 100644 --- a/code/datums/elements/footstep.dm +++ b/code/datums/elements/footstep.dm @@ -80,31 +80,42 @@ playsound(turf, 'sound/effects/footstep/crawl1.ogg', 15 * volume, falloff_distance = 1, vary = sound_vary) return - if(iscarbon(source)) - var/mob/living/carbon/carbon_source = source - if(!carbon_source.get_bodypart(BODY_ZONE_L_LEG) && !carbon_source.get_bodypart(BODY_ZONE_R_LEG)) - return - if(carbon_source.move_intent == MOVE_INTENT_WALK) - return// stealth + if(iscarbon(source) && source.move_intent == MOVE_INTENT_WALK) + return // stealth + steps_for_living[source] += 1 var/steps = steps_for_living[source] - if(steps >= 6) + if(steps >= 24) + // right foot = 0, 4, 8, 12, 16, 20 + // left foot = 2, 6, 10, 14, 18, 22 + // 24 -> return to 0 -> right foot, repeat steps_for_living[source] = 0 steps = 0 if(steps % 2) + // skipping every other step, anyways. gets noisy otherwise return - if(steps != 0 && !source.has_gravity()) // don't need to step as often when you hop around + if(steps % 6 != 0 && !source.has_gravity()) + // don't need to step as often when you hop around return - . = list(FOOTSTEP_MOB_SHOE = turf.footstep, FOOTSTEP_MOB_BAREFOOT = turf.barefootstep, FOOTSTEP_MOB_HEAVY = turf.heavyfootstep, FOOTSTEP_MOB_CLAW = turf.clawfootstep, STEP_SOUND_PRIORITY = STEP_SOUND_NO_PRIORITY) - var/overriden = SEND_SIGNAL(turf, COMSIG_TURF_PREPARE_STEP_SOUND, .) & FOOTSTEP_OVERRIDEN - //The turf has no footstep sound (e.g. open space) and none of the objects on that turf (e.g. catwalks) overrides it - if(!overriden && isnull(turf.footstep)) + var/list/footstep_data = list( + FOOTSTEP_MOB_SHOE = turf.footstep, + FOOTSTEP_MOB_BAREFOOT = turf.barefootstep, + FOOTSTEP_MOB_HEAVY = turf.heavyfootstep, + FOOTSTEP_MOB_CLAW = turf.clawfootstep, + STEP_SOUND_PRIORITY = STEP_SOUND_NO_PRIORITY, + ) + var/sigreturn = SEND_SIGNAL(turf, COMSIG_TURF_PREPARE_STEP_SOUND, footstep_data) + if(sigreturn & FOOTSTEP_OVERRIDEN) + return footstep_data + if(isnull(turf.footstep)) + // The turf has no footstep sound (e.g. open space) + // and none of the objects on that turf (e.g. catwalks) overrides it return null - return . + return footstep_data /datum/element/footstep/proc/play_simplestep(mob/living/source, atom/oldloc, direction, forced, list/old_locs, momentum_change) SIGNAL_HANDLER @@ -137,6 +148,48 @@ if (forced || SHOULD_DISABLE_FOOTSTEPS(source) || !momentum_change) return + var/list/prepared_steps = prepare_step(source) + if(isnull(prepared_steps)) + return + + var/footstep_type = null + var/list/footstep_sounds + var/stepcount = steps_for_living[source] + // any leg covering sounds defaults to shoe sounds + if((source.wear_suit?.body_parts_covered|source.w_uniform?.body_parts_covered|source.shoes?.body_parts_covered) & FEET) + footstep_type = FOOTSTEP_MOB_SHOE + // now pick whether to draw from left foot or right foot sounds + else + var/obj/item/bodypart/leg/left_leg = source.get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/leg/right_leg = source.get_bodypart(BODY_ZONE_R_LEG) + if(stepcount == 2 || stepcount == 6) + footstep_sounds = left_leg?.special_footstep_sounds || right_leg?.special_footstep_sounds + footstep_type = left_leg?.footstep_type || right_leg?.footstep_type + else + footstep_sounds = right_leg?.special_footstep_sounds || left_leg?.special_footstep_sounds + footstep_type = right_leg?.footstep_type || left_leg?.footstep_type + + // allow for snowflake effects to take priority + if(!length(footstep_sounds)) + switch(footstep_type) + if(FOOTSTEP_MOB_CLAW) + footstep_sounds = GLOB.clawfootstep[prepared_steps[footstep_type]] + if(FOOTSTEP_MOB_BAREFOOT) + footstep_sounds = GLOB.barefootstep[prepared_steps[footstep_type]] + if(FOOTSTEP_MOB_HEAVY) + footstep_sounds = GLOB.heavyfootstep[prepared_steps[footstep_type]] + if(FOOTSTEP_MOB_SHOE) + footstep_sounds = GLOB.footstep[prepared_steps[footstep_type]] + if(null) + return + else + // Got an unsupported type, somehow + CRASH("Invalid footstep type for human footstep: \[[footstep_type]\]") + + // no snowflake, and no (found) footstep sounds, nothing to do + if(!length(footstep_sounds)) + return + var/volume_multiplier = 1 var/range_adjustment = 0 @@ -144,37 +197,20 @@ volume_multiplier = 0.6 range_adjustment = -2 - var/list/prepared_steps = prepare_step(source) - if(isnull(prepared_steps)) - return - - //cache for sanic speed (lists are references anyways) - var/footstep_sounds = GLOB.footstep - ///list returned by playsound() filled by client mobs who heard the footstep. given to play_fov_effect() + // list returned by playsound() filled by client mobs who heard the footstep. given to play_fov_effect() var/list/heard_clients + var/picked_sound = pick(footstep_sounds[1]) + var/picked_volume = footstep_sounds[2] * volume * volume_multiplier + var/picked_range = footstep_sounds[3] + e_range + range_adjustment - if((source.wear_suit?.body_parts_covered | source.w_uniform?.body_parts_covered | source.shoes?.body_parts_covered) & FEET) - // we are wearing shoes - - var/shoestep_type = prepared_steps[FOOTSTEP_MOB_SHOE] - if(!isnull(shoestep_type) && footstep_sounds[shoestep_type]) // shoestep type can be null - heard_clients = playsound(source.loc, pick(footstep_sounds[shoestep_type][1]), - footstep_sounds[shoestep_type][2] * volume * volume_multiplier, - TRUE, - footstep_sounds[shoestep_type][3] + e_range + range_adjustment, falloff_distance = 1, vary = sound_vary) - else - // we are barefoot - - if(source.dna.species.special_step_sounds) - heard_clients = playsound(source.loc, pick(source.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1, vary = sound_vary) - else - var/barefoot_type = prepared_steps[FOOTSTEP_MOB_BAREFOOT] - var/bare_footstep_sounds = GLOB.barefootstep - if(!isnull(barefoot_type) && bare_footstep_sounds[barefoot_type]) // barefoot_type can be null - heard_clients = playsound(source.loc, pick(bare_footstep_sounds[barefoot_type][1]), - bare_footstep_sounds[barefoot_type][2] * volume * volume_multiplier, - TRUE, - bare_footstep_sounds[barefoot_type][3] + e_range + range_adjustment, falloff_distance = 1, vary = sound_vary) + heard_clients = playsound( + source = source, + soundin = picked_sound, + vol = picked_volume, + vary = sound_vary, + extrarange = picked_range, + falloff_distance = 1, + ) if(heard_clients) play_fov_effect(source, 5, "footstep", direction, ignore_self = TRUE, override_list = heard_clients) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 1eb48e3d10e..80f3d81d9f8 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -125,8 +125,6 @@ GLOBAL_LIST_EMPTY(features_by_species) var/inert_mutation = /datum/mutation/human/dwarfism ///Used to set the mob's death_sound upon species change var/death_sound - ///Sounds to override barefeet walking - var/list/special_step_sounds ///Special sound for grabbing var/grab_sound /// A path to an outfit that is important for species life e.g. plasmaman outfit diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 992d60142bd..c94bd0db701 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -396,11 +396,31 @@ unarmed_damage_low = 7 unarmed_damage_high = 15 unarmed_effectiveness = 15 + biological_state = BIO_STANDARD_JOINTED /// Datum describing how to offset things worn on the foot of this leg, note that an x offset won't do anything here var/datum/worn_feature_offset/worn_foot_offset /// Used by the bloodysoles component to make footprints var/footprint_sprite = FOOTPRINT_SPRITE_SHOES - biological_state = BIO_STANDARD_JOINTED + /// What does our footsteps (barefoot) sound like? Only BAREFOOT, CLAW, HEAVY, and SHOE (or null, I guess) are valid + var/footstep_type = FOOTSTEP_MOB_BAREFOOT + /// You can set this to a list of sounds to pick from when a footstep is played rather than use the footstep types + /// Requires special formatting: list(list(sounds, go, here), volume, range modifier) + var/list/special_footstep_sounds + +/obj/item/bodypart/leg/Initialize(mapload) + . = ..() + if(PERFORM_ALL_TESTS(focus_only/humanstep_validity)) + // Update this list if more types are suported in the footstep element + var/list/supported_types = list( + null, + FOOTSTEP_MOB_BAREFOOT, + FOOTSTEP_MOB_CLAW, + FOOTSTEP_MOB_HEAVY, + FOOTSTEP_MOB_SHOE, + ) + if(!(footstep_type in supported_types)) + stack_trace("Invalid footstep type set on leg: \[[footstep_type]\] \ + If you want to use this type, you will need to create a global footstep index for it.") /obj/item/bodypart/leg/Destroy() QDEL_NULL(worn_foot_offset) diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 00d71efd840..0f7e2833dc8 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -53,6 +53,7 @@ limb_id = BODYPART_ID_DIGITIGRADE bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE footprint_sprite = FOOTPRINT_SPRITE_CLAWS + footstep_type = FOOTSTEP_MOB_CLAW /obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() @@ -69,6 +70,7 @@ limb_id = BODYPART_ID_DIGITIGRADE bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE footprint_sprite = FOOTPRINT_SPRITE_CLAWS + footstep_type = FOOTSTEP_MOB_CLAW /obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() diff --git a/code/modules/unit_tests/focus_only_tests.dm b/code/modules/unit_tests/focus_only_tests.dm index 31f34d9f2fb..c9bfea88e5e 100644 --- a/code/modules/unit_tests/focus_only_tests.dm +++ b/code/modules/unit_tests/focus_only_tests.dm @@ -50,3 +50,6 @@ /// Ensures only whitelisted planes can have TOPDOWN_LAYERing, and vis versa /datum/unit_test/focus_only/topdown_filtering + +/// Catches any invalid footstep types set for humans +/datum/unit_test/focus_only/humanstep_validity