diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 2a542d85378..504dc89e3a7 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -278,6 +278,8 @@ #define COMSIG_MOVABLE_DISPOSING "movable_disposing" ///called when the movable sucessfully has it's anchored var changed, from base atom/movable/set_anchored(): (value) #define COMSIG_MOVABLE_SET_ANCHORED "movable_set_anchored" +///from base of atom/movable/setGrabState(): (newstate) +#define COMSIG_MOVABLE_SET_GRAB_STATE "living_set_grab_state" // /mob signals @@ -364,6 +366,8 @@ #define COMSIG_LIVING_REVIVE "living_revive" ///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) #define COMSIG_LIVING_REGENERATE_LIMBS "living_regen_limbs" +///from base of mob/living/set_buckled(): (new_buckled) +#define COMSIG_LIVING_SET_BUCKLED "living_set_buckled" ///sent from borg recharge stations: (amount, repairs) #define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 73137890942..60153034da0 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -77,6 +77,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai //mob traits #define TRAIT_KNOCKEDOUT "knockedout" //Forces the user to stay unconscious. +#define TRAIT_IMMOBILIZED "immobilized" //Prevents voluntary movement. #define TRAIT_INCAPACITATED "incapacitated" #define TRAIT_BLIND "blind" #define TRAIT_MUTE "mute" @@ -274,6 +275,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define CRIT_HEALTH_TRAIT "crit_health" #define OXYLOSS_TRAIT "oxyloss" #define TURF_TRAIT "turf" +#define BUCKLED_TRAIT "buckled" //trait associated to being buckled +#define CHOKEHOLD_TRAIT "chokehold" //trait associated to being held in a chokehold +#define RESTING_TRAIT "resting" //trait associated to resting // unique trait sources, still defines #define CLONING_POD_TRAIT "cloning-pod" @@ -316,3 +320,5 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TIMESTOP_TRAIT "timestop" #define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name #define SKILLCHIP_TRAIT "skillchip" +#define PULLED_WHILE_SOFTCRIT_TRAIT "pulled-while-softcrit" +#define LOCKED_BORG_TRAIT "locked-borg" diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index ab000892ba4..680ab83e99a 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -110,8 +110,7 @@ if (isliving(AM)) var/mob/living/L = AM L.notransform = TRUE - L.Stun(200) - L.resting = TRUE + L.Paralyze(20 SECONDS) var/oldtransform = AM.transform var/oldcolor = AM.color diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index a31203acd62..3a13359f572 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -33,19 +33,33 @@ if(!.) return ADD_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id)) + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) /datum/status_effect/incapacitating/stun/on_remove() REMOVE_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id)) + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) return ..() //KNOCKDOWN /datum/status_effect/incapacitating/knockdown id = "knockdown" + //IMMOBILIZED /datum/status_effect/incapacitating/immobilized id = "immobilized" +/datum/status_effect/incapacitating/immobilized/on_apply() + . = ..() + if(!.) + return + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + +/datum/status_effect/incapacitating/immobilized/on_remove() + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + return ..() + + /datum/status_effect/incapacitating/paralyzed id = "paralyzed" @@ -54,9 +68,11 @@ if(!.) return ADD_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id)) + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) /datum/status_effect/incapacitating/paralyzed/on_remove() REMOVE_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id)) + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) return ..() //UNCONSCIOUS @@ -163,12 +179,19 @@ if(.) update_time_of_death() owner.reagents?.end_metabolization(owner, FALSE) - owner.update_mobility() + +/datum/status_effect/grouped/stasis/on_apply() + . = ..() + if(!.) + return + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + owner.update_mobility() /datum/status_effect/grouped/stasis/tick() update_time_of_death() /datum/status_effect/grouped/stasis/on_remove() + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) owner.update_mobility() update_time_of_death() return ..() diff --git a/code/datums/status_effects/gas.dm b/code/datums/status_effects/gas.dm index 454bdb395b6..78ceaf3bd87 100644 --- a/code/datums/status_effects/gas.dm +++ b/code/datums/status_effects/gas.dm @@ -6,6 +6,16 @@ var/icon/cube var/can_melt = TRUE +/datum/status_effect/freon/on_apply() + . = ..() + if(!.) + return + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + +/datum/status_effect/freon/on_remove() + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + return ..() + /obj/screen/alert/status_effect/freon name = "Frozen Solid" desc = "You're frozen inside an ice cube, and cannot move! You can still do stuff, like shooting. Resist out of the cube!" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 3e9eade3782..3d6dcfc3167 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -224,7 +224,7 @@ log_combat(AM, AM.pulledby, "pulled from", src) AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM - AM.pulledby = src + AM.set_pulledby(src) setGrabState(state) if(ismob(AM)) var/mob/M = AM @@ -236,14 +236,23 @@ /atom/movable/proc/stop_pulling() if(pulling) - pulling.pulledby = null + pulling.set_pulledby(null) var/mob/living/ex_pulled = pulling + setGrabState(GRAB_PASSIVE) pulling = null - setGrabState(0) if(isliving(ex_pulled)) var/mob/living/L = ex_pulled L.update_mobility()// mob gets up if it was lyng down in a chokehold + +///Reports the event of the change in value of the pulledby variable. +/atom/movable/proc/set_pulledby(new_pulledby) + if(new_pulledby == pulledby) + return FALSE //null signals there was a change, be sure to return FALSE if none happened here. + . = pulledby + pulledby = new_pulledby + + /atom/movable/proc/Move_Pulled(atom/A) if(!pulling) return @@ -969,7 +978,20 @@ * This exists to act as a hook for behaviour */ /atom/movable/proc/setGrabState(newstate) + if(newstate == grab_state) + return + SEND_SIGNAL(src, COMSIG_MOVABLE_SET_GRAB_STATE, newstate) + . = grab_state grab_state = newstate + switch(.) //Previous state. + if(GRAB_PASSIVE, GRAB_AGGRESSIVE) + if(grab_state >= GRAB_NECK) + ADD_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT) + switch(grab_state) //Current state. + if(GRAB_PASSIVE, GRAB_AGGRESSIVE) + if(. >= GRAB_NECK) + REMOVE_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT) + /obj/item/proc/do_pickup_animation(atom/target) set waitfor = FALSE diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 504bcf37bae..cb5a5879f17 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -94,7 +94,7 @@ M.forceMove(loc) M.buckling = null - M.buckled = src + M.set_buckled(src) M.setDir(dir) buckled_mobs |= M M.update_mobility() @@ -114,7 +114,7 @@ /atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force=FALSE) if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force)) . = buckled_mob - buckled_mob.buckled = null + buckled_mob.set_buckled(null) buckled_mob.set_anchored(initial(buckled_mob.anchored)) buckled_mob.update_mobility() buckled_mob.clear_alert("buckled") diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index f8a3a5f846f..88d18b11c72 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -304,8 +304,7 @@ log_game("[key_name(user)] has put the MMI/posibrain of [key_name(M.brainmob)] into a cyborg shell at [AREACOORD(src)]") if(!locomotion) - O.lockcharge = TRUE - O.update_mobility() + O.set_lockcharge(TRUE) to_chat(O, "Error: Servo motors unresponsive.") else @@ -342,8 +341,7 @@ forceMove(O) O.robot_suit = src if(!locomotion) - O.lockcharge = TRUE - O.update_mobility() + O.set_lockcharge(TRUE) else if(istype(W, /obj/item/pen)) to_chat(user, "You need to use a multitool to name [src]!") diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 72639c20ce0..fbe2fe73096 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -528,11 +528,11 @@ step_towards(user, T2) T1 = get_turf(user) if(T1 == T2) - user.resting = TRUE //so people can jump into crates without slamming the lid on their head + user.set_resting(TRUE) //so people can jump into crates without slamming the lid on their head if(!close(user)) to_chat(user, "You can't get [src] to close!") - user.resting = FALSE + user.set_resting(FALSE) return - user.resting = FALSE + user.set_resting(FALSE) togglelock(user) T1.visible_message("[user] dives into [src]!") diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm index 1f970b121a0..f9486a89776 100644 --- a/code/modules/mining/fulton.dm +++ b/code/modules/mining/fulton.dm @@ -79,7 +79,8 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons) if(isliving(A)) var/mob/living/M = A M.Paralyze(320) // Keep them from moving during the duration of the extraction - M.buckled = 0 // Unbuckle them to prevent anchoring problems + if(M.buckled) + M.buckled.unbuckle_mob(M, TRUE) // Unbuckle them to prevent anchoring problems else A.set_anchored(TRUE) A.density = FALSE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 92f836bae15..aa09f11d51b 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -267,7 +267,7 @@ AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM - AM.pulledby = src + AM.set_pulledby(src) SEND_SIGNAL(src, COMSIG_LIVING_START_PULL, AM, state, force) @@ -451,19 +451,26 @@ else to_chat(src, "You fail to get up!") + +///Proc to hook behavior to the change of value in the resting variable. /mob/living/proc/set_resting(rest, silent = TRUE) + if(rest == resting) + return if(!silent) if(rest) to_chat(src, "You are now resting.") else to_chat(src, "You get up.") + . = rest resting = rest update_resting() + /mob/living/proc/update_resting() update_rest_hud_icon() update_mobility() + //Recursive function to find everything a mob is holding. Really shitty proc tbh. /mob/living/get_contents() var/list/ret = list() @@ -1197,10 +1204,9 @@ var/has_legs = get_num_legs() var/has_arms = get_num_arms() var/paralyzed = IsParalyzed() - var/stun = IsStun() var/knockdown = IsKnockdown() var/ignore_legs = get_leg_ignore() - var/canmove = !IsImmobilized() && !stun && stat_conscious && !paralyzed && !buckled && (!stat_softcrit || !pulledby) && !chokehold && !IsFrozen() && !IS_IN_STASIS(src) && (has_arms || ignore_legs || has_legs) + var/canmove = !HAS_TRAIT(src, TRAIT_IMMOBILIZED) && (has_arms || ignore_legs || has_legs) if(canmove) mobility_flags |= MOBILITY_MOVE else @@ -1231,7 +1237,7 @@ - var/canitem = !paralyzed && !stun && stat_conscious && !chokehold && !restrained && has_arms + var/canitem = !paralyzed && !IsStun() && stat_conscious && !chokehold && !restrained && has_arms if(canitem) mobility_flags |= (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE) else @@ -1627,12 +1633,54 @@ if(isnull(.)) return switch(.) //Previous stat. + if(CONSCIOUS) + if(stat >= UNCONSCIOUS) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) + if(SOFT_CRIT) + if(stat >= UNCONSCIOUS) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates + if(pulledby) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) if(UNCONSCIOUS) cure_blind(UNCONSCIOUS_BLIND) switch(stat) //Current stat. + if(CONSCIOUS) + if(. >= UNCONSCIOUS) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) + if(SOFT_CRIT) + if(pulledby) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) //adding trait sources should come before removing to avoid unnecessary updates + if(. >= UNCONSCIOUS) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) if(UNCONSCIOUS) become_blind(UNCONSCIOUS_BLIND) + +///Reports the event of the change in value of the buckled variable. +/mob/living/proc/set_buckled(new_buckled) + if(new_buckled == buckled) + return + SEND_SIGNAL(src, COMSIG_LIVING_SET_BUCKLED, new_buckled) + . = buckled + buckled = new_buckled + if(buckled) + if(!.) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT) + else if(.) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT) + + +/mob/living/set_pulledby(new_pulledby) + . = ..() + if(. == FALSE) //null is a valid value here, we only want to return if FALSE is explicitly passed. + return + if(pulledby) + if(!. && stat == SOFT_CRIT) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) + else if(. && stat == SOFT_CRIT) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) + + /// Only defined for carbons who can wear masks and helmets, we just assume other mobs have visible faces /mob/living/proc/is_face_visible() return TRUE diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index afad167f231..d51a332655c 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -93,7 +93,7 @@ cut_overlay(fire_overlay) /mob/living/silicon/robot/update_mobility() - if(stat || buckled || lockcharge) + if(HAS_TRAIT(src, TRAIT_IMMOBILIZED)) mobility_flags &= ~MOBILITY_MOVE else mobility_flags = MOBILITY_FLAGS_DEFAULT diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 70f46207645..5132a310251 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -464,8 +464,7 @@ connected_ai.connected_robots -= src src.connected_ai = null lawupdate = FALSE - lockcharge = FALSE - mobility_flags |= MOBILITY_FLAGS_DEFAULT + set_lockcharge(FALSE) scrambledcodes = TRUE //Disconnect it's camera so it's not so easily tracked. if(!QDELETED(builtInCamera)) @@ -487,17 +486,31 @@ W.attack_self(src) -/mob/living/silicon/robot/proc/SetLockdown(state = 1) +/mob/living/silicon/robot/proc/SetLockdown(state = TRUE) // They stay locked down if their wire is cut. if(wires.is_cut(WIRE_LOCKDOWN)) - state = 1 + state = TRUE if(state) throw_alert("locked", /obj/screen/alert/locked) else clear_alert("locked") - lockcharge = state + set_lockcharge(state) + + +///Reports the event of the change in value of the lockcharge variable. +/mob/living/silicon/robot/proc/set_lockcharge(new_lockcharge) + if(new_lockcharge == lockcharge) + return + . = lockcharge + lockcharge = new_lockcharge + if(lockcharge) + if(!.) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT) + else if(.) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT) update_mobility() + /mob/living/silicon/robot/proc/SetEmagged(new_state) emagged = new_state module.rebuild_modules() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 78e282f15c9..9afe35bc144 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -527,8 +527,17 @@ else ..() + +/mob/living/simple_animal/update_resting() + if(resting) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, RESTING_TRAIT) + else + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, RESTING_TRAIT) + return ..() + + /mob/living/simple_animal/update_mobility(value_otherwise = TRUE) - if(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsParalyzed() || IsStun() || IsKnockdown() || IsParalyzed() || stat || resting) + if(HAS_TRAIT_NOT_FROM(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT)) drop_all_held_items() mobility_flags = NONE else if(buckled)