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 000000000000..f499765dc228
Binary files /dev/null and b/sound/effects/sprintactivate.ogg differ
diff --git a/sound/effects/sprintdeactivate.ogg b/sound/effects/sprintdeactivate.ogg
new file mode 100644
index 000000000000..c22587ace000
Binary files /dev/null and b/sound/effects/sprintdeactivate.ogg differ
diff --git a/sound/effects/tank_treads.ogg b/sound/effects/tank_treads.ogg
new file mode 100644
index 000000000000..be4e0ff273be
Binary files /dev/null and b/sound/effects/tank_treads.ogg differ