diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index a8af2cc5c66..70642a4d6b4 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -167,7 +167,7 @@ /// Return to skip oxyloss and similar effects from blood level #define HANDLE_BLOOD_NO_OXYLOSS (1<<2) -/// from /datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced) iodk where it should go +/// from /datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced): (var/obj/item/bodypart/limping_leg) #define COMSIG_CARBON_LIMPING "mob_limp_check" #define COMPONENT_CANCEL_LIMP (1<<0) diff --git a/code/datums/components/walking_aid.dm b/code/datums/components/walking_aid.dm new file mode 100644 index 00000000000..7a869661f2d --- /dev/null +++ b/code/datums/components/walking_aid.dm @@ -0,0 +1,161 @@ +/** + * Walking Aid Component + * + * Add this to an item to allow it to act as a cane (or crutch) while held. + * Items with this component will help mobs avoid limping from broken + * leg bones, and lessen the slowdown caused by missing legs. + * + * Used by canes, crutches, and pole-like items such as spears and staffs. + */ +/datum/component/walking_aid + dupe_mode = COMPONENT_DUPE_UNIQUE + /// Causes a mob to waddle (wiggle) while walking when holding this object + var/waddling = FALSE + /// If set, the parent item must have this trait for the support to function + var/required_trait + /// Weakref to the mob currently being supported + var/datum/weakref/current_user_ref + /// The amount of slowdown to reduce for a limbless leg + var/limbless_slowdown_modifier = 0.6 // reduces slowdown by 40% + +/datum/component/walking_aid/Initialize(limbless_slowdown_modifier = 0.6, required_trait = null, waddling = FALSE) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.waddling = waddling + src.required_trait = required_trait + src.limbless_slowdown_modifier = limbless_slowdown_modifier + +/datum/component/walking_aid/Destroy(force) + remove_support() + return ..() + +/datum/component/walking_aid/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE_TAGS, PROC_REF(get_examine_tags)) + RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_WIELDED), PROC_REF(update_legs)) + RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_WIELDED), PROC_REF(update_legs)) + RegisterSignal(parent, SIGNAL_ADDTRAIT(required_trait), PROC_REF(update_legs)) + RegisterSignal(parent, SIGNAL_REMOVETRAIT(required_trait), PROC_REF(update_legs)) + +/datum/component/walking_aid/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_ITEM_EQUIPPED, + COMSIG_ITEM_DROPPED, + COMSIG_ATOM_EXAMINE_TAGS, + SIGNAL_ADDTRAIT(TRAIT_WIELDED), + SIGNAL_REMOVETRAIT(TRAIT_WIELDED), + SIGNAL_ADDTRAIT(required_trait), + SIGNAL_REMOVETRAIT(required_trait), + )) + remove_support() + +/datum/component/walking_aid/proc/on_equip(datum/source, mob/equipper, slot) + SIGNAL_HANDLER + + remove_support() + if(!(slot & ITEM_SLOT_HANDS)) + return + if(!isliving(equipper)) + return + + apply_support(equipper) + +/datum/component/walking_aid/proc/on_drop(datum/source, mob/user) + SIGNAL_HANDLER + remove_support() + +/datum/component/walking_aid/proc/get_examine_tags(atom/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + examine_list["walking-aid"] = "It can help lessen the slowdown caused from a missing or injured leg, when held on the same side as the injury." + +// Updates our leg status when wielded/unwielded a two handed walking aid like a spear +/datum/component/walking_aid/proc/update_legs(atom/source) + SIGNAL_HANDLER + + var/mob/living/user = current_user_ref?.resolve() + user?.update_usable_leg_status() + +/datum/component/walking_aid/proc/apply_support(mob/living/user) + if(current_user_ref) + remove_support() + + current_user_ref = WEAKREF(user) + RegisterSignal(user, COMSIG_CARBON_LIMPING, PROC_REF(handle_limping)) + RegisterSignal(user, COMSIG_LIVING_LIMBLESS_SLOWDOWN, PROC_REF(handle_slowdown)) + user.update_usable_leg_status() + + if(waddling) + user.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling) + +/datum/component/walking_aid/proc/remove_support() + var/mob/living/user = current_user_ref?.resolve() + current_user_ref = null + if(isnull(user)) + return + UnregisterSignal(user, list(COMSIG_CARBON_LIMPING, COMSIG_LIVING_LIMBLESS_SLOWDOWN)) + user.update_usable_leg_status() + + if(waddling) + REMOVE_TRAIT(user, TRAIT_WADDLING, REF(src)) + +/datum/component/walking_aid/proc/is_active() + // if both hands are holding it, then it is not being used for support + if(HAS_TRAIT(parent, TRAIT_WIELDED)) + return FALSE + + if(isnull(required_trait)) + return TRUE + + return HAS_TRAIT(parent, required_trait) + +/datum/component/walking_aid/proc/handle_limping(mob/living/user, obj/item/bodypart/limping_leg) + SIGNAL_HANDLER + + if(!is_active()) + return NONE + if(isnull(limping_leg)) + return NONE + + var/supported_zone = get_supported_leg_zone(user) + if(isnull(supported_zone)) + return NONE + if(limping_leg.body_zone != supported_zone) + return NONE + + return COMPONENT_CANCEL_LIMP + +/datum/component/walking_aid/proc/handle_slowdown(mob/living/user, limbless_slowdown, list/slowdown_mods) + SIGNAL_HANDLER + + if(!is_active()) + return + if(!iscarbon(user)) + return + var/mob/living/carbon/carbon_user = user + var/leg_amount = carbon_user.usable_legs + if(leg_amount >= carbon_user.default_num_legs) + return + if(!leg_amount) // someday support dual-wielding crutches but for now they are destined to waddle + return + + var/supported_zone = get_supported_leg_zone(user) + if(isnull(supported_zone)) + return + if(carbon_user.get_bodypart(supported_zone)) // make sure their leg is actually missing + return + + slowdown_mods += limbless_slowdown_modifier + +/datum/component/walking_aid/proc/get_supported_leg_zone(mob/living/user) + var/held_hand_zone = user.get_hand_zone_of_item(parent) + + switch(held_hand_zone) + if(BODY_ZONE_R_ARM) + return BODY_ZONE_R_LEG + if(BODY_ZONE_L_ARM) + return BODY_ZONE_L_LEG + else + return null diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index 5ea0be0b256..6b10d609778 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -79,18 +79,21 @@ // less limping while we have determination still var/determined_mod = owner.has_status_effect(/datum/status_effect/determined) ? 0.5 : 1 + var/obj/item/bodypart/leg_about_to_limp var/limp_chance var/limp_slowdown if(next_leg == left) + leg_about_to_limp = left limp_chance = limp_chance_left limp_slowdown = slowdown_left next_leg = right else + leg_about_to_limp = right limp_chance = limp_chance_right limp_slowdown = slowdown_right next_leg = left - if(SEND_SIGNAL(owner, COMSIG_CARBON_LIMPING) & COMPONENT_CANCEL_LIMP) + if(SEND_SIGNAL(owner, COMSIG_CARBON_LIMPING, leg_about_to_limp) & COMPONENT_CANCEL_LIMP) return if(prob(limp_chance * determined_mod)) diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index 591dd127411..35f4e267530 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -36,6 +36,7 @@ /obj/item/mop/Initialize(mapload) . = ..() AddComponent(/datum/component/cleaner, mopspeed, pre_clean_callback=CALLBACK(src, PROC_REF(should_clean)), on_cleaned_callback=CALLBACK(src, PROC_REF(apply_reagents))) + AddComponent(/datum/component/walking_aid) create_reagents(max_reagent_volume) GLOB.janitor_devices += src diff --git a/code/game/objects/items/pitchfork.dm b/code/game/objects/items/pitchfork.dm index 99f714f09f3..497e213acba 100644 --- a/code/game/objects/items/pitchfork.dm +++ b/code/game/objects/items/pitchfork.dm @@ -32,6 +32,7 @@ . = ..() AddComponent(/datum/component/jousting) AddComponent(/datum/component/two_handed, force_unwielded=7, force_wielded=15, icon_wielded="[base_icon_state]1") + AddComponent(/datum/component/walking_aid) /obj/item/pitchfork/update_icon_state() icon_state = "[base_icon_state]0" diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index 0e96116ed3d..a087dfeb897 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -337,6 +337,10 @@ var/staffcooldown = 0 var/staffwait = 30 +/obj/item/godstaff/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + /obj/item/godstaff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) return NONE diff --git a/code/game/objects/items/tools/janitorial/broom.dm b/code/game/objects/items/tools/janitorial/broom.dm index 970bb5a5526..e34e0044b08 100644 --- a/code/game/objects/items/tools/janitorial/broom.dm +++ b/code/game/objects/items/tools/janitorial/broom.dm @@ -29,6 +29,7 @@ wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ ) + AddComponent(/datum/component/walking_aid) /obj/item/pushbroom/update_icon_state() icon_state = "[base_icon_state]0" diff --git a/code/game/objects/items/tools/medical/cane.dm b/code/game/objects/items/tools/medical/cane.dm index 132f03a9b37..ca9de8325b7 100644 --- a/code/game/objects/items/tools/medical/cane.dm +++ b/code/game/objects/items/tools/medical/cane.dm @@ -13,32 +13,18 @@ custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5) attack_verb_continuous = list("bludgeons", "whacks", "disciplines", "thrashes") attack_verb_simple = list("bludgeon", "whack", "discipline", "thrash") + /// The amount of slowdown to reduce for a limbless leg + var/limbless_slowdown_modifier = 0.6 // reduces slowdown by 40% + /// Does this cause waddling when held + var/causes_waddling = FALSE -/obj/item/cane/examine(mob/user, thats) +/obj/item/cane/Initialize(mapload) . = ..() - . += span_notice("This item can be used to support your weight, preventing limping from any broken bones on your legs you may have.") + AddComponent(/datum/component/walking_aid, limbless_slowdown_modifier, get_walking_aid_required_trait(), causes_waddling) -/obj/item/cane/equipped(mob/living/user, slot, initial) - ..() - if(!(slot & ITEM_SLOT_HANDS)) - return - movement_support_add(user) - -/obj/item/cane/dropped(mob/living/user, silent = FALSE) - . = ..() - movement_support_del(user) - -/obj/item/cane/proc/movement_support_add(mob/living/user) - RegisterSignal(user, COMSIG_CARBON_LIMPING, PROC_REF(handle_limping)) - return TRUE - -/obj/item/cane/proc/movement_support_del(mob/living/user) - UnregisterSignal(user, list(COMSIG_CARBON_LIMPING)) - return TRUE - -/obj/item/cane/proc/handle_limping(mob/living/user) - SIGNAL_HANDLER - return COMPONENT_CANCEL_LIMP +/// Determines if a trait is required to be used as a walking aid (ex. foldable canes) +/obj/item/cane/proc/get_walking_aid_required_trait() + return null /obj/item/cane/crutch name = "medical crutch" @@ -55,42 +41,13 @@ custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5) attack_verb_continuous = list("bludgeons", "whacks", "thrashes") attack_verb_simple = list("bludgeon", "whack", "thrash") + limbless_slowdown_modifier = 0.4 // reduces slowdown by 60% + causes_waddling = TRUE /obj/item/cane/crutch/Initialize(mapload) . = ..() AddElement(/datum/element/cuffable_item) -/obj/item/cane/crutch/examine(mob/user, thats) - . = ..() - // tacked on after the cane string - . += span_notice("As a crutch, it can also help lessen the slowdown incurred by missing a leg.") - -/obj/item/cane/crutch/movement_support_add(mob/living/user) - . = ..() - if(!.) - return - RegisterSignal(user, COMSIG_LIVING_LIMBLESS_SLOWDOWN, PROC_REF(handle_slowdown)) - user.update_usable_leg_status() - user.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling) - -/obj/item/cane/crutch/movement_support_del(mob/living/user) - . = ..() - if(!.) - return - UnregisterSignal(user, list(COMSIG_LIVING_LIMBLESS_SLOWDOWN, COMSIG_CARBON_LIMPING)) - user.update_usable_leg_status() - REMOVE_TRAIT(user, TRAIT_WADDLING, REF(src)) - -/obj/item/cane/crutch/proc/handle_slowdown(mob/living/user, limbless_slowdown, list/slowdown_mods) - SIGNAL_HANDLER - var/leg_amount = user.usable_legs - // Don't do anything if the number is equal (or higher) to the usual. - if(leg_amount >= user.default_num_legs) - return - // If we have at least one leg and it's less than the default, reduce slowdown by 60%. - if(leg_amount && (leg_amount < user.default_num_legs)) - slowdown_mods += 0.4 - /obj/item/cane/crutch/wood name = "wooden crutch" desc = "A handmade crutch. Also makes a decent bludgeon if you need it." @@ -124,15 +81,16 @@ ) RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) -/obj/item/cane/white/handle_limping(mob/living/user) - return HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? COMPONENT_CANCEL_LIMP : NONE +// White canes only provide support while extended +/obj/item/cane/white/get_walking_aid_required_trait() + return TRAIT_TRANSFORM_ACTIVE /* * Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM]. * * Gives feedback to the user and makes it show up inhand. */ -/obj/item/cane/white/proc/on_transform(obj/item/source, mob/user, active) +/obj/item/cane/white/proc/on_transform(obj/item/source, mob/living/user, active) SIGNAL_HANDLER if(user) diff --git a/code/game/objects/items/weaponry/melee/misc.dm b/code/game/objects/items/weaponry/melee/misc.dm index b79ff035f20..35f3151987e 100644 --- a/code/game/objects/items/weaponry/melee/misc.dm +++ b/code/game/objects/items/weaponry/melee/misc.dm @@ -386,6 +386,7 @@ force_unwielded = 10, \ force_wielded = 14, \ ) + AddComponent(/datum/component/walking_aid) /obj/item/bambostaff/update_icon_state() icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" @@ -414,6 +415,10 @@ attack_verb_simple = list("bludgeon", "whack", "discipline") resistance_flags = FLAMMABLE +/obj/item/staff/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + /obj/item/staff/broom name = "broom" desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." diff --git a/code/game/objects/items/weaponry/melee/soulscythe.dm b/code/game/objects/items/weaponry/melee/soulscythe.dm index 596166d14e0..c7dabc9d44d 100644 --- a/code/game/objects/items/weaponry/melee/soulscythe.dm +++ b/code/game/objects/items/weaponry/melee/soulscythe.dm @@ -39,6 +39,7 @@ RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED_SECONDARY, PROC_REF(on_secondary_attack)) RegisterSignal(src, COMSIG_ATOM_INTEGRITY_CHANGED, PROC_REF(on_integrity_change)) AddComponent(/datum/component/bane, affected_biotypes = MOB_PLANT, damage_multiplier = 1.5) + AddComponent(/datum/component/walking_aid) /obj/item/soulscythe/examine(mob/user) . = ..() diff --git a/code/game/objects/items/weaponry/melee/spear.dm b/code/game/objects/items/weaponry/melee/spear.dm index 39ca04c5017..6fc5634c7c0 100644 --- a/code/game/objects/items/weaponry/melee/spear.dm +++ b/code/game/objects/items/weaponry/melee/spear.dm @@ -70,6 +70,7 @@ wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ ) + AddComponent(/datum/component/walking_aid) add_headpike_component() update_appearance() diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index a35b938fcf6..1eb888dc1cd 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -174,6 +174,7 @@ . = ..() AddComponent(/datum/component/butchering, speed = 9 SECONDS, effectiveness = 105) AddComponent(/datum/component/bane, affected_biotypes = MOB_PLANT, damage_multiplier = 1.5) + AddComponent(/datum/component/walking_aid) /obj/item/scythe/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index 5e67c8de35b..f73ab5f588c 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -340,6 +340,10 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) /// The icon which appears over the mob holding the item var/shield_icon = "shield-red" +/obj/item/nullrod/staff/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + /obj/item/nullrod/staff/worn_overlays(mutable_appearance/standing, isinhands) . = ..() if(isinhands) @@ -629,6 +633,7 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) force_unwielded = 14, \ force_wielded = 18, \ ) + AddComponent(/datum/component/walking_aid) /obj/item/nullrod/bostaff/update_icon_state() icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" @@ -703,6 +708,10 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) sharpness = SHARP_EDGED menu_description = "A sharp pitchfork. Can be worn on the back." +/obj/item/nullrod/pitchfork/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + // Egyptian Staff - Used as a tool for making mummy wraps. /obj/item/nullrod/egyptian @@ -720,6 +729,11 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) attack_verb_simple = list("bash", "smack", "whack") menu_description = "A staff. Can be used as a tool to craft exclusive egyptian items. Easily stored. Can be worn on the back." + +/obj/item/nullrod/egyptian/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + // Hypertool - It does brain damage rather than normal damage. /obj/item/nullrod/hypertool @@ -760,6 +774,10 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) hitsound = 'sound/items/weapons/bladeslice.ogg' menu_description = "A pointy spear which penetrates armor a little. Can be worn only on the belt." +/obj/item/nullrod/spear/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + // Unholy version of above, since the gamemode is dead in the water /obj/item/brass_spear @@ -783,6 +801,10 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) attack_verb_simple = list("stab", "poke", "slash", "clock") hitsound = 'sound/items/weapons/bladeslice.ogg' +/obj/item/brass_spear/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + // Nullblade - For when you really want to feel like rolling dice during combat /obj/item/nullrod/nullblade diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index c06f8993b53..e94ad0d9762 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -81,6 +81,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and AddElement(/datum/element/nullrod_core, chaplain_spawnable = FALSE, rune_remove_line = "TO DUST WITH YE!! AWAY!!") // The implant is the actual item the chappie can select AddComponent(/datum/component/bane, affected_biotypes = MOB_PLANT, damage_multiplier = 1.5) //also good at killing plants AddComponent(/datum/component/butchering, speed = 3 SECONDS, effectiveness = 125) + AddComponent(/datum/component/walking_aid) /obj/item/vorpalscythe/attack(mob/living/target, mob/living/user, list/modifiers, list/attack_modifiers) if(ismonkey(target) && !target.mind) //Don't empower from hitting monkeys. Hit a corgi or something, I don't know. diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 3615616f4f3..ccaed1a6996 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -11,6 +11,10 @@ /// If FALSE, only wizards or survivalists can use the staff to its full potential - If TRUE, anyone can var/allow_intruder_use = FALSE +/obj/item/gun/magic/staff/Initialize(mapload) + . = ..() + AddComponent(/datum/component/walking_aid) + /obj/item/gun/magic/staff/proc/is_wizard_or_friend(mob/user) if(!HAS_MIND_TRAIT(user, TRAIT_MAGICALLY_GIFTED) && !allow_intruder_use) return FALSE diff --git a/tgstation.dme b/tgstation.dme index 7575b8fdc36..00cc6b2f93b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1396,6 +1396,7 @@ #include "code\datums\components\usb_port.dm" #include "code\datums\components\vacuum.dm" #include "code\datums\components\vision_hurting.dm" +#include "code\datums\components\walking_aid.dm" #include "code\datums\components\wearertargeting.dm" #include "code\datums\components\weatherannouncer.dm" #include "code\datums\components\wet_floor.dm"