From 0a5dfd1217981b35b22f8a0fd529c1469caab7e5 Mon Sep 17 00:00:00 2001 From: thgvr Date: Fri, 6 Sep 2024 14:55:21 -0700 Subject: [PATCH] Footsteps element + Sprinting --- code/__DEFINES/footsteps.dm | 3 + code/datums/components/footstep.dm | 125 -------------- code/datums/elements/footstep.dm | 156 ++++++++++++++++++ code/datums/keybinding/mob.dm | 4 +- code/datums/traits/good.dm | 6 - .../living/carbon/alien/humanoid/humanoid.dm | 3 +- .../mob/living/carbon/carbon_defense.dm | 11 +- .../mob/living/carbon/carbon_movement.dm | 11 ++ code/modules/mob/living/carbon/human/human.dm | 4 +- .../mob/living/carbon/monkey/monkey.dm | 2 +- .../mob/living/simple_animal/hostile/alien.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 2 +- .../mob/living/simple_animal/slime/slime.dm | 2 +- code/modules/mob/living/sprint.dm | 96 +++++++++++ config/game_options.txt | 2 +- shiptest.dme | 3 +- sound/effects/sprintactivate.ogg | Bin 0 -> 5486 bytes sound/effects/sprintdeactivate.ogg | Bin 0 -> 5156 bytes sound/effects/tank_treads.ogg | Bin 0 -> 22864 bytes 19 files changed, 283 insertions(+), 149 deletions(-) delete mode 100644 code/datums/components/footstep.dm create mode 100644 code/datums/elements/footstep.dm create mode 100644 code/modules/mob/living/sprint.dm create mode 100644 sound/effects/sprintactivate.ogg create mode 100644 sound/effects/sprintdeactivate.ogg create mode 100644 sound/effects/tank_treads.ogg diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm index 189ac6fd0b53..a1711a1d415f 100644 --- a/code/__DEFINES/footsteps.dm +++ b/code/__DEFINES/footsteps.dm @@ -27,6 +27,9 @@ #define FOOTSTEP_MOB_SHOE 4 #define FOOTSTEP_MOB_HUMAN 5 //Warning: Only works on /mob/living/carbon/human #define FOOTSTEP_MOB_SLIME 6 +#define FOOTSTEP_MOB_SLIME 6 +#define FOOTSTEP_OBJ_MACHINE 7 +#define FOOTSTEP_OBJ_ROBOT 8 /* diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm deleted file mode 100644 index 2e5533023ac8..000000000000 --- a/code/datums/components/footstep.dm +++ /dev/null @@ -1,125 +0,0 @@ -#define SHOULD_DISABLE_FOOTSTEPS(source) ((SSlag_switch.measures[DISABLE_FOOTSTEPS] && !(HAS_TRAIT(source, TRAIT_BYPASS_MEASURES))) || HAS_TRAIT(source, TRAIT_SILENT_FOOTSTEPS)) - -///Footstep component. Plays footsteps at parents location when it is appropriate. -/datum/component/footstep - ///How many steps the parent has taken since the last time a footstep was played. - var/steps = 0 - ///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one. - var/volume - ///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value. - var/e_range - ///footstep_type is a define which determines what kind of sounds should get chosen. - var/footstep_type - ///This can be a list OR a soundfile OR null. Determines whatever sound gets played. - var/footstep_sounds - -/datum/component/footstep/Initialize(footstep_type_ = FOOTSTEP_MOB_BAREFOOT, volume_ = 0.5, e_range_ = -8) - if(!isliving(parent)) - return COMPONENT_INCOMPATIBLE - volume = volume_ - e_range = e_range_ - footstep_type = footstep_type_ - switch(footstep_type) - if(FOOTSTEP_MOB_HUMAN) - if(!ishuman(parent)) - return COMPONENT_INCOMPATIBLE - RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), PROC_REF(play_humanstep)) - return - if(FOOTSTEP_MOB_CLAW) - footstep_sounds = GLOB.clawfootstep - if(FOOTSTEP_MOB_BAREFOOT) - footstep_sounds = GLOB.barefootstep - if(FOOTSTEP_MOB_HEAVY) - footstep_sounds = GLOB.heavyfootstep - if(FOOTSTEP_MOB_SHOE) - footstep_sounds = GLOB.footstep - if(FOOTSTEP_MOB_SLIME) - footstep_sounds = 'sound/effects/footstep/slime1.ogg' - RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), PROC_REF(play_simplestep)) //Note that this doesn't get called for humans. - -///Prepares a footstep. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open -/datum/component/footstep/proc/prepare_step() - var/turf/open/T = get_turf(parent) - if(!istype(T)) - return - - var/mob/living/LM = parent - - if(!T.footstep || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING) || HAS_TRAIT(LM, TRAIT_IMMOBILIZED)) - return - - if(LM.body_position == LYING_DOWN) //play crawling sound if we're lying - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume, falloff_distance = 1) - return - - if(iscarbon(LM)) - var/mob/living/carbon/C = LM - if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG)) - return - if(C.m_intent == MOVE_INTENT_WALK) - return// stealth - steps++ - - if(steps >= 6) - steps = 0 - - if(steps % 2) - return - - if(steps != 0 && !LM.has_gravity(T)) // don't need to step as often when you hop around - return - return T - -/datum/component/footstep/proc/play_simplestep() - SIGNAL_HANDLER - - if (SHOULD_DISABLE_FOOTSTEPS(parent)) - return - - var/turf/open/T = prepare_step() - if(!T) - return - if(isfile(footstep_sounds) || istext(footstep_sounds)) - playsound(T, footstep_sounds, volume, falloff_distance = 1) - return - var/turf_footstep - switch(footstep_type) - if(FOOTSTEP_MOB_CLAW) - turf_footstep = T.clawfootstep - if(FOOTSTEP_MOB_BAREFOOT) - turf_footstep = T.barefootstep - if(FOOTSTEP_MOB_HEAVY) - turf_footstep = T.heavyfootstep - if(FOOTSTEP_MOB_SHOE) - turf_footstep = T.footstep - if(!turf_footstep) - return - playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1) - -/datum/component/footstep/proc/play_humanstep() - SIGNAL_HANDLER - - if (SHOULD_DISABLE_FOOTSTEPS(parent)) - return - - var/turf/open/T = prepare_step() - if(!T) - return - var/mob/living/carbon/human/H = parent - var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET)) - - if(H.shoes || feetCover) //are we wearing shoes - playsound(T, pick(GLOB.footstep[T.footstep][1]), - GLOB.footstep[T.footstep][2] * volume, - TRUE, - GLOB.footstep[T.footstep][3] + e_range, falloff_distance = 1) - else - if(H.dna.species.special_step_sounds) - playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1) - else - playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]), - GLOB.barefootstep[T.barefootstep][2] * volume, - TRUE, - GLOB.barefootstep[T.barefootstep][3] + e_range, falloff_distance = 1) - -#undef SHOULD_DISABLE_FOOTSTEPS diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm new file mode 100644 index 000000000000..6d58a27270d1 --- /dev/null +++ b/code/datums/elements/footstep.dm @@ -0,0 +1,156 @@ +///Footstep element. Plays footsteps at parents location when it is appropriate. +/datum/element/footstep + element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE + id_arg_index = 2 + ///A list containing living mobs and the number of steps they have taken since the last time their footsteps were played. + var/list/steps_for_living = list() + ///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one. + var/volume + ///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value. + var/e_range + ///footstep_type is a define which determines what kind of sounds should get chosen. + var/footstep_type + ///This can be a list OR a soundfile OR null. Determines whatever sound gets played. + var/footstep_sounds + ///Whether or not to add variation to the sounds played + var/sound_vary = FALSE + +/datum/element/footstep/Attach(datum/target, footstep_type = FOOTSTEP_MOB_BAREFOOT, volume = 0.5, e_range = -8, sound_vary = FALSE) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + src.volume = volume + src.e_range = e_range + src.footstep_type = footstep_type + src.sound_vary = sound_vary + switch(footstep_type) + if(FOOTSTEP_MOB_HUMAN) + if(!ishuman(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(play_humanstep)) + steps_for_living[target] = 0 + return + if(FOOTSTEP_MOB_CLAW) + footstep_sounds = GLOB.clawfootstep + if(FOOTSTEP_MOB_BAREFOOT) + footstep_sounds = GLOB.barefootstep + if(FOOTSTEP_MOB_HEAVY) + footstep_sounds = GLOB.heavyfootstep + if(FOOTSTEP_MOB_SHOE) + footstep_sounds = GLOB.footstep + if(FOOTSTEP_MOB_SLIME) + footstep_sounds = 'sound/effects/footstep/slime1.ogg' + if(FOOTSTEP_OBJ_MACHINE) + footstep_sounds = 'sound/effects/bang.ogg' + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(play_simplestep_machine)) + return + if(FOOTSTEP_OBJ_ROBOT) + footstep_sounds = 'sound/effects/tank_treads.ogg' + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(play_simplestep_machine)) + return + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(play_simplestep)) + steps_for_living[target] = 0 + +/datum/element/footstep/Detach(atom/movable/source) + UnregisterSignal(source, COMSIG_MOVABLE_MOVED) + steps_for_living -= source + return ..() + +///Prepares a footstep for living mobs. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open +/datum/element/footstep/proc/prepare_step(mob/living/source) + var/turf/open/turf = get_turf(source) + if(!istype(turf)) + return + + if(!turf.footstep || source.buckled || source.throwing || source.movement_type & (VENTCRAWLING | FLYING)) + return + + if(!(source.mobility_flags & MOBILITY_STAND)) //play crawling sound if we're lying + playsound(source, '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 + + /* todo: stealth mode? + if(carbon_source.m_intent == MOVE_INTENT_WALK) + return// stealth + */ + + steps_for_living[source] += 1 + var/steps = steps_for_living[source] + + if(steps >= 6) + steps_for_living[source] = 0 + steps = 0 + + if(steps % 2) + return + + if(steps != 0 && !source.has_gravity(turf)) // don't need to step as often when you hop around + return + return turf + +/datum/element/footstep/proc/play_simplestep(mob/living/source) + SIGNAL_HANDLER + + var/turf/open/source_loc = prepare_step(source) + if(!source_loc) + return + if(isfile(footstep_sounds) || istext(footstep_sounds)) + playsound(source, footstep_sounds, volume, falloff_distance = 1, vary = sound_vary) + return + var/turf_footstep + switch(footstep_type) + if(FOOTSTEP_MOB_CLAW) + turf_footstep = source_loc.clawfootstep + if(FOOTSTEP_MOB_BAREFOOT) + turf_footstep = source_loc.barefootstep + if(FOOTSTEP_MOB_HEAVY) + turf_footstep = source_loc.heavyfootstep + if(FOOTSTEP_MOB_SHOE) + turf_footstep = source_loc.footstep + if(!turf_footstep) + return + playsound(source, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1, vary = sound_vary) + +/datum/element/footstep/proc/play_humanstep(mob/living/carbon/human/source) + SIGNAL_HANDLER + + var/volume_multiplier = 1 + var/range_adjustment = 0 + + if(HAS_TRAIT(source, TRAIT_LIGHT_STEP)) + volume_multiplier = 0.6 + range_adjustment = -2 + + var/turf/open/source_loc = prepare_step(source) + if(!source_loc) + return + + if ((source.wear_suit?.body_parts_covered | source.w_uniform?.body_parts_covered | source.shoes?.body_parts_covered) & FEET) + // we are wearing shoes + playsound(source, pick(GLOB.footstep[source_loc.footstep][1]), + GLOB.footstep[source_loc.footstep][2] * volume * volume_multiplier, + TRUE, + GLOB.footstep[source_loc.footstep][3] + e_range + range_adjustment, falloff_distance = 1, vary = sound_vary) + else + if(source.dna.species.special_step_sounds) + playsound(source, pick(source.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1, vary = sound_vary) + else + playsound(source, pick(GLOB.barefootstep[source_loc.barefootstep][1]), + GLOB.barefootstep[source_loc.barefootstep][2] * volume * volume_multiplier, + TRUE, + GLOB.barefootstep[source_loc.barefootstep][3] + e_range + range_adjustment, falloff_distance = 1, vary = sound_vary) + + +///Prepares a footstep for machine walking +/datum/element/footstep/proc/play_simplestep_machine(atom/movable/source) + SIGNAL_HANDLER + + var/turf/open/source_loc = get_turf(source) + if(!istype(source_loc)) + return + playsound(source, footstep_sounds, 50, falloff_distance = 1, vary = sound_vary) diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm index 4e88f2c4a613..3c0cf94b50ca 100644 --- a/code/datums/keybinding/mob.dm +++ b/code/datums/keybinding/mob.dm @@ -167,8 +167,8 @@ /datum/keybinding/mob/toggle_move_intent hotkey_keys = list("Alt") name = "toggle_move_intent" - full_name = "Hold to toggle move intent" - description = "Held down to cycle to the other move intent, release to cycle back" + full_name = "Hold to toggle sprint" + description = "Hold down to enable sprinting. Releasing will return you to walk." keybind_signal = COMSIG_KB_MOB_TOGGLEMOVEINTENT_DOWN /datum/keybinding/mob/toggle_move_intent/down(client/user) diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 574c35f60beb..22c3027cc2af 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -122,12 +122,6 @@ lose_text = "You start tromping around like a barbarian." medical_record_text = "Patient's dexterity belies a strong capacity for stealth." -/datum/quirk/light_step/on_spawn() - var/datum/component/footstep/C = quirk_holder.GetComponent(/datum/component/footstep) - if(C) - C.volume *= 0.6 - C.e_range -= 2 - /datum/quirk/musician name = "Musician" desc = "You can tune handheld musical instruments to play melodies that clear certain negative effects and soothe the soul." diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index dcb44af19cca..646f5656f48a 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -31,8 +31,7 @@ /mob/living/carbon/alien/humanoid/Initialize() . = ..() - AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW, 0.5, -11) - + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW, 0.5, -11) /mob/living/carbon/alien/humanoid/show_inv(mob/user) user.set_machine(src) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 5330ee1841f6..89440a66f607 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -526,7 +526,6 @@ return embeds - /mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES) if(!eyes) //can't flash what can't see! @@ -574,7 +573,6 @@ if(prob(20)) to_chat(src, "Something bright flashes in the corner of your vision!") - /mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15) var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist) @@ -603,7 +601,6 @@ SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250)) return effect_amount //how soundbanged we are - /mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone) if(damage_type != BRUTE && damage_type != BURN) return @@ -625,7 +622,6 @@ if(istype(ears) && !ears.deaf) . = TRUE - /mob/living/carbon/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE) . = ..() if(isnull(.)) @@ -636,7 +632,6 @@ else if(getOxyLoss() <= 50) REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT) - /mob/living/carbon/setOxyLoss(amount, updating_health = TRUE, forced = FALSE) . = ..() if(isnull(.)) @@ -648,18 +643,20 @@ REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT) /mob/living/carbon/bullet_act(obj/projectile/P, def_zone, piercing_hit = FALSE) - var/mob/living/carbon/human/current_user = src //is this a good idea? who can say? var/armor = run_armor_check(def_zone, P.flag, P.armour_penetration, silent = TRUE) var/on_hit_state = P.on_hit(src, armor, piercing_hit) + if(!P.nodamage && on_hit_state != BULLET_ACT_BLOCK && !QDELETED(src)) //QDELETED literally just for the instagib rifle. Yeah. apply_damage(P.damage, P.damage_type, def_zone, armor, sharpness = TRUE) + if(P.damage-armor >= 15 && P.damage_type == BRUTE && (!armor || prob(40) || P.damage-armor >= 25)) spray_blood(get_dir(P.starting,src), (P.damage-armor)/5) - var/obj/item/bodypart/targeted_bodypart = null bleed((P.damage-armor)/2) recoil_camera(src, clamp((P.damage-armor)/4,0.5,10), clamp((P.damage-armor)/4,0.5,10), P.damage/8, P.Angle) apply_effects(P.stun, P.knockdown, P.unconscious, P.irradiate, P.slur, P.stutter, P.eyeblur, P.drowsy, armor, P.stamina, P.jitter, P.paralyze, P.immobilize) + if(P.dismemberment) check_projectile_dismemberment(P, def_zone) + return on_hit_state ? BULLET_ACT_HIT : BULLET_ACT_BLOCK diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 7f65b79ddca1..3e9e455569e8 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -31,6 +31,17 @@ if(m_intent == MOVE_INTENT_RUN) adjust_nutrition(-(HUNGER_FACTOR/10)) + if(m_intent == MOVE_INTENT_RUN && !(movement_type & FLYING) && (mobility_flags & (MOBILITY_MOVE|MOBILITY_STAND)) && !pulledby) + drain_sprint() + if(momentum_dir & direct) + momentum_distance++ + if(!has_momentum && momentum_distance >= 4 && add_movespeed_modifier(/datum/movespeed_modifier/momentum)) + has_momentum = TRUE + else + momentum_dir = direct + momentum_distance = 0 + if(has_momentum && remove_movespeed_modifier(/datum/movespeed_modifier/momentum)) + has_momentum = FALSE /mob/living/carbon/set_usable_legs(new_value) . = ..() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 27fa569de7cd..a5ce76114ee1 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -23,8 +23,10 @@ RegisterSignal(src, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(clean_face)) AddComponent(/datum/component/personal_crafting) - AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) AddComponent(/datum/component/bloodysoles/feet) + + AddElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) + GLOB.human_list += src /mob/living/carbon/human/proc/setup_human_dna() diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 755c674a107d..0b5daa91d262 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -51,7 +51,7 @@ create_dna(src) dna.initialize_dna(random_blood_type()) - AddComponent(/datum/component/footstep, FOOTSTEP_MOB_BAREFOOT, 1, -6) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT, 1, -6) AddComponent(/datum/component/bloodysoles/feet) /mob/living/carbon/monkey/Destroy() diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index ec7c76f5ca61..0565c6c1fc1d 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -39,7 +39,7 @@ /mob/living/simple_animal/hostile/alien/Initialize() . = ..() - AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) /mob/living/simple_animal/hostile/alien/drone name = "alien drone" diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 3670e14a6405..e120bd62aefd 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -155,7 +155,7 @@ if(dextrous) AddComponent(/datum/component/personal_crafting) if(footstep_type) - AddComponent(/datum/component/footstep, footstep_type) + AddElement(/datum/element/footstep, footstep_type) /mob/living/simple_animal/Destroy() GLOB.simple_animals[AIStatus] -= src diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index cb4b76983563..05f3150b0efb 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -104,7 +104,7 @@ set_colour(new_colour) . = ..() set_nutrition(700) - AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 0) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_SLIME, 0) /mob/living/simple_animal/slime/Destroy() for (var/A in actions) diff --git a/code/modules/mob/living/sprint.dm b/code/modules/mob/living/sprint.dm new file mode 100644 index 000000000000..22a545a6f09a --- /dev/null +++ b/code/modules/mob/living/sprint.dm @@ -0,0 +1,96 @@ +/atom/movable/screen/mov_intent + var/mutable_appearance/sprint_bar + +/atom/movable/screen/mov_intent/update_overlays() + . = ..() + if(!ishuman(hud?.mymob)) + return + + if(isnull(sprint_bar)) + sprint_bar = mutable_appearance( + icon = 'icons/effects/progressbar.dmi', + icon_state = "prog_bar_100", + ) + sprint_bar.pixel_y -= 2 + + var/mob/living/carbon/human/runner = hud.mymob + sprint_bar.icon_state = "prog_bar_[round(((runner.sprint_length / runner.sprint_length_max) * 100), 5)]" + . += sprint_bar + +/datum/movespeed_modifier/momentum + movetypes = GROUND + flags = IGNORE_NOSLOW + multiplicative_slowdown = -0.1 + +/mob/living/carbon + /// If TRUE, we are being affected by run momentum + var/has_momentum = FALSE + /// Our last move direction, used for tracking momentum + var/momentum_dir = NONE + /// How many tiles we've moved in the momentum direction + var/momentum_distance = 0 + +/mob/living/carbon/human + m_intent = MOVE_INTENT_WALK + /// How many tiles left in your sprint + var/sprint_length = 100 + /// How many tiles you can sprint before spending stamina + var/sprint_length_max = 100 + /// How many tiles you get back per second + var/sprint_regen_per_second = 0.75 + +/mob/living/carbon/human/toggle_move_intent() + . = ..() + if(m_intent == MOVE_INTENT_RUN) + playsound_local(get_turf(src), 'sound/effects/sprintactivate.ogg', 75, vary = FALSE, pressure_affected = FALSE) + else + playsound_local(get_turf(src), 'sound/effects/sprintdeactivate.ogg', 75, vary = FALSE, pressure_affected = FALSE) + +/mob/living/carbon/human/Life(seconds_per_tick, times_fired) + . = ..() + if(!.) + return + if(m_intent == MOVE_INTENT_RUN || sprint_length >= sprint_length_max) + return + + adjust_sprint_left(sprint_regen_per_second * seconds_per_tick * (body_position == LYING_DOWN ? 2 : 1)) + +/mob/living/carbon/proc/adjust_sprint_left(amount) + return + +/mob/living/carbon/human/adjust_sprint_left(amount) + sprint_length = clamp(sprint_length + amount, 0, sprint_length_max) + for(var/atom/movable/screen/mov_intent/selector in hud_used?.static_inventory) + selector.update_appearance(UPDATE_OVERLAYS) + +/mob/living/carbon/proc/drain_sprint() + return + +/mob/living/carbon/human/drain_sprint() + adjust_sprint_left(-1) + // Sprinting when out of sprint will cost stamina + if(sprint_length > 0) + return + + // Okay you're gonna stamcrit yourself, slow your roll + if(getStaminaLoss() >= maxHealth * 0.9) + toggle_move_intent() + return + + adjustStaminaLoss(1) + +/mob/living/carbon/human/fully_heal(heal_flags) + . = ..() + adjust_sprint_left(INFINITY) + +// Minor stamina regeneration effects, such as stimulants, will replenish sprint capacity +/mob/living/carbon/human/adjustStaminaLoss(amount, updating_stamina, forced, required_biotype) + . = ..() + if(amount < 0 && amount >= -20) + adjust_sprint_left(amount * 0.25) + +// Entering stamina critical will drain your sprint capacity entirely +/mob/living/carbon/human/enter_stamcrit() + . = ..() + if(HAS_TRAIT_FROM(src, TRAIT_FLOORED, STAMINA)) + adjust_sprint_left(-INFINITY) diff --git a/config/game_options.txt b/config/game_options.txt index 135123b845ad..423ab5fa0e0b 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -33,7 +33,7 @@ EMOJIS ## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied. RUN_DELAY 1.5 -WALK_DELAY 3 +WALK_DELAY 2.5 ## The variables below affect the movement of specific mob types. THIS AFFECTS ALL SUBTYPES OF THE TYPE YOU CHOOSE! ## Entries completely override all subtypes. Later entries have precedence over earlier entries. diff --git a/shiptest.dme b/shiptest.dme index 55ad11a800d5..d9d28ec476cd 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -503,7 +503,6 @@ #include "code\datums\components\empprotection.dm" #include "code\datums\components\explodable.dm" #include "code\datums\components\fishing_spot.dm" -#include "code\datums\components\footstep.dm" #include "code\datums\components\forensics.dm" #include "code\datums\components\fullauto.dm" #include "code\datums\components\gps.dm" @@ -665,6 +664,7 @@ #include "code\datums\elements\embed.dm" #include "code\datums\elements\empprotection.dm" #include "code\datums\elements\firestacker.dm" +#include "code\datums\elements\footstep.dm" #include "code\datums\elements\forced_gravity.dm" #include "code\datums\elements\lazy_fishing_spot.dm" #include "code\datums\elements\light_blocking.dm" @@ -2505,6 +2505,7 @@ #include "code\modules\mob\living\living_say.dm" #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" +#include "code\modules\mob\living\sprint.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\taste.dm" #include "code\modules\mob\living\ventcrawling.dm" diff --git a/sound/effects/sprintactivate.ogg b/sound/effects/sprintactivate.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f499765dc22824c13d641673a8c42856813f73e5 GIT binary patch literal 5486 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 literal 0 HcmV?d00001 diff --git a/sound/effects/sprintdeactivate.ogg b/sound/effects/sprintdeactivate.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c22587ace0006d105bf8aa6174102c1d0b3d117d GIT binary patch literal 5156 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 literal 0 HcmV?d00001 diff --git a/sound/effects/tank_treads.ogg b/sound/effects/tank_treads.ogg new file mode 100644 index 0000000000000000000000000000000000000000..be4e0ff273beaf3e47d8ad9078993f88cd4f4c61 GIT binary patch literal 22864 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 literal 0 HcmV?d00001