diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 69f20b7d8f6..2c906a34868 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -515,3 +515,6 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE))) #define ANON_DISABLED "" //so it's falsey #define ANON_RANDOMNAMES "Random Default" #define ANON_EMPLOYEENAMES "Employees" + +/// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled. +#define NO_BUCKLE_LYING -1 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 25d2cd2990c..266b55ce4c4 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -209,6 +209,10 @@ #define SENTIENCE_BOSS 5 //Mob AI Status +#define POWER_RESTORATION_OFF 0 +#define POWER_RESTORATION_START 1 +#define POWER_RESTORATION_SEARCH_APC 2 +#define POWER_RESTORATION_APC_FOUND 3 //Hostile simple animals //If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index bba30c2cb72..4e498c20cd5 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -81,6 +81,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_FLOORED "floored" //Prevents standing or staying up on its own. /// Prevents usage of manipulation appendages (picking, holding or using items, manipulating storage). #define TRAIT_HANDS_BLOCKED "handsblocked" +/// Inability to access UI hud elements. Turned into a trait from [MOBILITY_UI] to be able to track sources. +#define TRAIT_UI_BLOCKED "uiblocked" +/// Inability to pull things. Turned into a trait from [MOBILITY_PULL] to be able to track sources. +#define TRAIT_PULL_BLOCKED "pullblocked" /// Abstract condition that prevents movement if being pulled and might be resisted against. Handcuffs and straight jackets, basically. #define TRAIT_RESTRAINED "restrained" #define TRAIT_INCAPACITATED "incapacitated" @@ -292,6 +296,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define MAPPING_HELPER_TRAIT "mapping-helper" //obtained from mapping helper /// Trait associated to wearing a suit #define SUIT_TRAIT "suit" +/// Trait associated to lying down (having a [lying_angle] of a different value than zero). +#define LYING_DOWN_TRAIT "lying-down" +/// Trait associated to lacking electrical power. +#define POWER_LACK_TRAIT "power-lack" // unique trait sources, still defines #define CLONING_POD_TRAIT "cloning-pod" diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index ded403262ef..f57925ba461 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -230,6 +230,7 @@ if(!.) return ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + ADD_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id)) owner.update_mobility() /datum/status_effect/grouped/stasis/tick() @@ -237,6 +238,7 @@ /datum/status_effect/grouped/stasis/on_remove() REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) + REMOVE_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id)) owner.update_mobility() update_time_of_death() return ..() diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 28d807459a9..bb3db37c6e1 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,6 +1,7 @@ /atom/movable var/can_buckle = FALSE - var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1 + /// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING]. + var/buckle_lying = NO_BUCKLE_LYING var/buckle_requires_restraints = FALSE //require people to be handcuffed before being able to buckle. eg: pipes var/list/mob/living/buckled_mobs = null //list() var/max_buckled_mobs = 1 diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm index 4ca79754e22..be832d087ca 100644 --- a/code/game/objects/structures/manned_turret.dm +++ b/code/game/objects/structures/manned_turret.dm @@ -9,7 +9,7 @@ anchored = FALSE density = TRUE max_integrity = 100 - buckle_lying = FALSE + buckle_lying = 0 layer = ABOVE_MOB_LAYER var/view_range = 2.5 var/cooldown = 0 diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index e2aa6ad4242..5cbb76503b6 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -552,7 +552,7 @@ smoothing_groups = null canSmoothWith = null can_buckle = 1 - buckle_lying = -1 + buckle_lying = NO_BUCKLE_LYING buckle_requires_restraints = TRUE var/mob/living/carbon/human/patient = null var/obj/machinery/computer/operating/computer = null diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index 6f5d5463cfb..35959589b50 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -7,7 +7,7 @@ flags_1 = CONDUCT_1 can_buckle = TRUE max_buckled_mobs = 1 - buckle_lying = FALSE + buckle_lying = 0 var/obj/item/target/pinned_target /obj/structure/target_stake/Destroy() diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm index 5520b640b7e..67f24a3d92d 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm @@ -2,7 +2,7 @@ var/minimum_temperature_difference = 20 var/thermal_conductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT color = "#404040" - buckle_lying = -1 + buckle_lying = NO_BUCKLE_LYING var/icon_temperature = T20C //stop small changes in temperature causing icon refresh resistance_flags = LAVA_PROOF | FIRE_PROOF diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index 558a08b4063..e2889f6a040 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -12,7 +12,7 @@ //Buckling can_buckle = TRUE buckle_requires_restraints = TRUE - buckle_lying = -1 + buckle_lying = NO_BUCKLE_LYING /obj/machinery/atmospherics/pipe/New() add_atom_colour(pipe_color, FIXED_COLOUR_PRIORITY) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index d239ee6459b..e5e052fe995 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -542,12 +542,17 @@ if(dna) dna.real_name = real_name -/mob/living/carbon/update_mobility() + +/mob/living/carbon/set_lying_angle(new_lying) . = ..() - if(!(mobility_flags & MOBILITY_STAND)) - add_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling) - else - remove_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling) + if(isnull(.)) + return + switch(lying_angle) + if(90, 270) + add_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling) + else + remove_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling) + //Updates the mob's health from bodyparts and mob damage variables /mob/living/carbon/updatehealth() @@ -1281,7 +1286,5 @@ if(.) if(!handcuffed) REMOVE_TRAIT(src, TRAIT_RESTRAINED, HANDCUFFED_TRAIT) - REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, HANDCUFFED_TRAIT) else if(handcuffed) ADD_TRAIT(src, TRAIT_RESTRAINED, HANDCUFFED_TRAIT) - ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, HANDCUFFED_TRAIT) diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 7367995a613..7f65b79ddca 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -64,11 +64,22 @@ . = ..() if(isnull(.)) return - if(. & !(FLYING | FLOATING)) + if(!(. & (FLYING | FLOATING))) if(movement_type & (FLYING | FLOATING)) //From not flying to flying. + remove_movespeed_modifier(/datum/movespeed_modifier/limbless) REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - else if(!(movement_type & (FLYING | FLOATING)) && !usable_legs) //From flying to no longer flying. - ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - if(!usable_hands) - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + else if(!(movement_type & (FLYING | FLOATING))) //From flying to no longer flying. + var/limbless_slowdown = 0 + if(usable_legs < default_num_legs) + limbless_slowdown += (default_num_legs - usable_legs) * 3 + if(!usable_legs) + ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + if(usable_hands < default_num_hands) + limbless_slowdown += (default_num_hands - usable_hands) * 3 + if(!usable_hands) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + if(limbless_slowdown) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) + else + remove_movespeed_modifier(/datum/movespeed_modifier/limbless) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index edf9be57b88..1b128824f11 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -149,7 +149,6 @@ update_inv_w_uniform() if(wear_suit.breakouttime) //when equipping a straightjacket ADD_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT) - ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, SUIT_TRAIT) stop_pulling() //can't pull if restrained update_action_buttons_icon() //certain action buttons will no longer be usable. update_inv_wear_suit() @@ -206,7 +205,6 @@ dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit. if(wear_suit.breakouttime) //when unequipping a straightjacket REMOVE_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT) - REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, SUIT_TRAIT) drop_all_held_items() //suit is restraining update_action_buttons_icon() //certain action buttons may be usable again. wear_suit = null diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index dd4c88b3355..586ff858031 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -1,4 +1,4 @@ -///Called on /mob/living/Initialize(), for the mob to register to relevant signals. +/// Called on [/mob/living/Initialize()], for the mob to register to relevant signals. /mob/living/proc/register_init_signals() RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_KNOCKEDOUT), .proc/on_knockedout_trait_gain) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_KNOCKEDOUT), .proc/on_knockedout_trait_loss) @@ -9,9 +9,24 @@ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED), .proc/on_immobilized_trait_gain) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_IMMOBILIZED), .proc/on_immobilized_trait_loss) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_FLOORED), .proc/on_floored_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_FLOORED), .proc/on_floored_trait_loss) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED), .proc/on_handsblocked_trait_gain) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_HANDS_BLOCKED), .proc/on_handsblocked_trait_loss) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UI_BLOCKED), .proc/on_ui_blocked_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_UI_BLOCKED), .proc/on_ui_blocked_trait_loss) + + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_PULL_BLOCKED), .proc/on_pull_blocked_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_PULL_BLOCKED), .proc/on_pull_blocked_trait_loss) + + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED), .proc/on_incapacitated_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_INCAPACITATED), .proc/on_incapacitated_trait_loss) + + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_RESTRAINED), .proc/on_restrained_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_RESTRAINED), .proc/on_restrained_trait_loss) + RegisterSignal(src, list( SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION), SIGNAL_REMOVETRAIT(TRAIT_CRITICAL_CONDITION), @@ -21,48 +36,132 @@ ), .proc/update_succumb_action) -///Called when TRAIT_KNOCKEDOUT is added to the mob. +/// Called when [TRAIT_KNOCKEDOUT] is added to the mob. /mob/living/proc/on_knockedout_trait_gain(datum/source) + SIGNAL_HANDLER if(stat < UNCONSCIOUS) set_stat(UNCONSCIOUS) -///Called when TRAIT_KNOCKEDOUT is removed from the mob. +/// Called when [TRAIT_KNOCKEDOUT] is removed from the mob. /mob/living/proc/on_knockedout_trait_loss(datum/source) + SIGNAL_HANDLER if(stat <= UNCONSCIOUS) update_stat() -///Called when TRAIT_DEATHCOMA is added to the mob. +/// Called when [TRAIT_DEATHCOMA] is added to the mob. /mob/living/proc/on_deathcoma_trait_gain(datum/source) + SIGNAL_HANDLER ADD_TRAIT(src, TRAIT_KNOCKEDOUT, TRAIT_DEATHCOMA) -///Called when TRAIT_DEATHCOMA is removed from the mob. +/// Called when [TRAIT_DEATHCOMA] is removed from the mob. /mob/living/proc/on_deathcoma_trait_loss(datum/source) + SIGNAL_HANDLER REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, TRAIT_DEATHCOMA) -///Called when TRAIT_IMMOBILIZED is added to the mob. +/// Called when [TRAIT_IMMOBILIZED] is added to the mob. /mob/living/proc/on_immobilized_trait_gain(datum/source) + SIGNAL_HANDLER mobility_flags &= ~MOBILITY_MOVE -///Called when TRAIT_IMMOBILIZED is removed from the mob. +/// Called when [TRAIT_IMMOBILIZED] is removed from the mob. /mob/living/proc/on_immobilized_trait_loss(datum/source) + SIGNAL_HANDLER mobility_flags |= MOBILITY_MOVE -///Called when TRAIT_HANDS_BLOCKED is added to the mob. +/// Called when [TRAIT_FLOORED] is added to the mob. +/mob/living/proc/on_floored_trait_gain(datum/source) + SIGNAL_HANDLER + if(buckled && buckled.buckle_lying != NO_BUCKLE_LYING) + return // Handled by the buckle. + mobility_flags &= ~MOBILITY_STAND + if(lying_angle == 0) //force them on the ground + set_lying_angle(pick(90, 270)) + on_fall() + + +/// Called when [TRAIT_FLOORED] is removed from the mob. +/mob/living/proc/on_floored_trait_loss(datum/source) + SIGNAL_HANDLER + mobility_flags |= MOBILITY_STAND + if(!resting) + get_up() + + +/// Called when [TRAIT_HANDS_BLOCKED] is added to the mob. /mob/living/proc/on_handsblocked_trait_gain(datum/source) + SIGNAL_HANDLER mobility_flags &= ~(MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE) drop_all_held_items() + ADD_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_HANDS_BLOCKED) + ADD_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED) -///Called when TRAIT_HANDS_BLOCKED is removed from the mob. +/// Called when [TRAIT_HANDS_BLOCKED] is removed from the mob. /mob/living/proc/on_handsblocked_trait_loss(datum/source) + SIGNAL_HANDLER mobility_flags |= (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE) + REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_HANDS_BLOCKED) + REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED) -/// Called when traits that alter succumbing are added/removed. -/// Will show or hide the succumb alert prompt. +/// Called when [TRAIT_UI_BLOCKED] is added to the mob. +/mob/living/proc/on_ui_blocked_trait_gain(datum/source) + SIGNAL_HANDLER + mobility_flags &= ~(MOBILITY_UI) + unset_machine() + +/// Called when [TRAIT_UI_BLOCKED] is removed from the mob. +/mob/living/proc/on_ui_blocked_trait_loss(datum/source) + SIGNAL_HANDLER + mobility_flags |= MOBILITY_UI + + +/// Called when [TRAIT_PULL_BLOCKED] is added to the mob. +/mob/living/proc/on_pull_blocked_trait_gain(datum/source) + SIGNAL_HANDLER + mobility_flags &= ~(MOBILITY_PULL) + if(pulling) + stop_pulling() + +/// Called when [TRAIT_PULL_BLOCKED] is removed from the mob. +/mob/living/proc/on_pull_blocked_trait_loss(datum/source) + SIGNAL_HANDLER + mobility_flags |= MOBILITY_PULL + + +/// Called when [TRAIT_INCAPACITATED] is added to the mob. +/mob/living/proc/on_incapacitated_trait_gain(datum/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_INCAPACITATED) + ADD_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_INCAPACITATED) + +/// Called when [TRAIT_INCAPACITATED] is removed from the mob. +/mob/living/proc/on_incapacitated_trait_loss(datum/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_INCAPACITATED) + REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_INCAPACITATED) + + +/// Called when [TRAIT_RESTRAINED] is added to the mob. +/mob/living/proc/on_restrained_trait_gain(datum/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED) + +/// Called when [TRAIT_RESTRAINED] is removed from the mob. +/mob/living/proc/on_restrained_trait_loss(datum/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED) + + +/** + * Called when traits that alter succumbing are added/removed. + * + * Will show or hide the succumb alert prompt. + */ /mob/living/proc/update_succumb_action() + SIGNAL_HANDLER if (CAN_SUCCUMB(src)) throw_alert("succumb", /obj/screen/alert/succumb) else diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 589c510eb14..2fe067f0265 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -385,7 +385,7 @@ death() /mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_stasis = FALSE) - if(stat || HAS_TRAIT(src, TRAIT_INCAPACITATED) || (!ignore_restraints && (HAS_TRAIT(src, TRAIT_RESTRAINED) || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))) || (!ignore_stasis && IS_IN_STASIS(src))) + if(HAS_TRAIT(src, TRAIT_INCAPACITATED) || (!ignore_restraints && (HAS_TRAIT(src, TRAIT_RESTRAINED) || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))) || (!ignore_stasis && IS_IN_STASIS(src))) return TRUE /mob/living/canUseStorage() @@ -427,30 +427,43 @@ /mob/proc/get_contents() + /mob/living/proc/lay_down() set name = "Rest" set category = "IC" - if(!resting) - set_resting(TRUE, FALSE) - else - if(do_after(src, 10, target = src)) - set_resting(FALSE, FALSE) - else - to_chat(src, "You fail to get up!") + set_resting(!resting, FALSE) ///Proc to hook behavior to the change of value in the resting variable. -/mob/living/proc/set_resting(rest, silent = TRUE) - if(rest == resting) +/mob/living/proc/set_resting(new_resting, silent = TRUE) + if(new_resting == resting) return - if(!silent) - if(rest) - to_chat(src, "You are now resting.") + . = resting + resting = new_resting + if(new_resting) + if(lying_angle == 90 || lying_angle == 270) + if(!silent) + to_chat(src, "You will now try to stay lying down on the floor.") + else if(buckled && buckled.buckle_lying != NO_BUCKLE_LYING) + if(!silent) + to_chat(src, "You will now lay down as soon as you are able to.") else - to_chat(src, "You get up.") - . = rest - resting = rest + if(!silent) + to_chat(src, "You lay down.") + set_lying_down() + else + if(lying_angle == 0) + if(!silent) + to_chat(src, "You will now try to remain standing up.") + else if(HAS_TRAIT(src, TRAIT_FLOORED) || (buckled && buckled.buckle_lying != NO_BUCKLE_LYING)) + if(!silent) + to_chat(src, "You will now stand up as soon as you are able to.") + else + if(!silent) + to_chat(src, "You stand up.") + get_up() + update_resting() @@ -459,6 +472,31 @@ update_mobility() +/mob/living/proc/get_up() + set waitfor = FALSE + var/static/datum/callback/rest_checks = CALLBACK(src, .proc/rest_checks_callback) + if(!do_mob(src, src, 2 SECONDS, uninterruptible = TRUE, extra_checks = rest_checks)) + return + if(resting || lying_angle == 0 || HAS_TRAIT(src, TRAIT_FLOORED)) + return + set_lying_angle(0) + + +/mob/living/proc/rest_checks_callback() + if(resting || lying_angle == 0 || HAS_TRAIT(src, TRAIT_FLOORED)) + return FALSE + return TRUE + + +/mob/living/proc/set_lying_down(new_lying_angle) + if(buckled && buckled.buckle_lying == 0) + return + if(!new_lying_angle) + set_lying_angle(pick(90, 270)) + else + set_lying_angle(new_lying_angle) + + //Recursive function to find everything a mob is holding. Really shitty proc tbh. /mob/living/get_contents() var/list/ret = list() @@ -1177,53 +1215,9 @@ return ..() && !(buckled && buckled.buckle_prevents_pull) -//Updates lying and icons. Could perhaps do with a rename but I can't think of anything to describe it. -//Robots, animals and brains have their own version so don't worry about them +//Updates lying and icons on robots, animals and brains. Needs to be refactored to use traits and update based on events. /mob/living/proc/update_mobility() - var/canstand_involuntary = !HAS_TRAIT(src, TRAIT_FLOORED) - var/canstand = canstand_involuntary && !resting - - if(buckled && buckled.buckle_lying != -1) - if(buckled.buckle_lying != 0) - mobility_flags &= ~MOBILITY_STAND - else - mobility_flags |= MOBILITY_STAND - set_lying_angle(buckled.buckle_lying) - else if(!canstand) - mobility_flags &= ~MOBILITY_STAND - if(lying_angle == 0) //force them on the ground - set_lying_angle(pick(90, 270)) - if(!canstand_involuntary) - on_fall() - else - mobility_flags |= MOBILITY_STAND - set_lying_angle(0) - - if(lying_angle != 0 || HAS_TRAIT(src, TRAIT_HANDS_BLOCKED) || incapacitated()) - mobility_flags &= ~(MOBILITY_UI|MOBILITY_PULL) - else - mobility_flags |= MOBILITY_UI|MOBILITY_PULL - - if(!(mobility_flags & MOBILITY_PULL)) - if(pulling) - stop_pulling() - if(!(mobility_flags & MOBILITY_UI)) - unset_machine() - - // Movespeed mods based on arms/legs quantity - if(movement_type & (FLYING | FLOATING)) - remove_movespeed_modifier(/datum/movespeed_modifier/limbless) - else - var/limbless_slowdown = 0 - // These checks for <2 should be swapped out for something else if we ever end up with a species with more than 2 - if(usable_legs < default_num_legs) - limbless_slowdown += (default_num_legs * 3) - (usable_legs * 3) - if(!usable_legs && usable_hands < default_num_hands) - limbless_slowdown += (default_num_hands * 3) - (usable_hands * 3) - if(limbless_slowdown) - add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) - else - remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + return ///Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment, through update_mobility() @@ -1437,13 +1431,19 @@ if(lying_angle != 0) //We are not standing up. if(layer == initial(layer)) //to avoid things like hiding larvas. layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs - if(. == 0) //We became prone and were not before. We lose density and stop bumping passable dense things. - density = FALSE + if(. == 0) // We became prone and were not before. + ADD_TRAIT(src, TRAIT_UI_BLOCKED, LYING_DOWN_TRAIT) + ADD_TRAIT(src, TRAIT_PULL_BLOCKED, LYING_DOWN_TRAIT) + density = FALSE // We lose density and stop bumping passable dense things. + if(HAS_TRAIT(src, TRAIT_FLOORED) && !(dir & (NORTH|SOUTH))) + setDir(pick(NORTH, SOUTH)) // We are and look helpless. else //We are prone. if(layer == LYING_MOB_LAYER) layer = initial(layer) if(.) //We were prone before, so we become dense and things can bump into us again. density = initial(density) + REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, LYING_DOWN_TRAIT) + REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, LYING_DOWN_TRAIT) /** @@ -1601,6 +1601,7 @@ switch(.) //Previous stat. if(CONSCIOUS) if(stat >= UNCONSCIOUS) + ADD_TRAIT(src, TRAIT_INCAPACITATED, TRAIT_KNOCKEDOUT) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT) ADD_TRAIT(src, TRAIT_FLOORED, UNCONSCIOUS_TRAIT) @@ -1619,6 +1620,7 @@ switch(stat) //Current stat. if(CONSCIOUS) if(. >= UNCONSCIOUS) + REMOVE_TRAIT(src, TRAIT_INCAPACITATED, TRAIT_KNOCKEDOUT) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT) REMOVE_TRAIT(src, TRAIT_FLOORED, UNCONSCIOUS_TRAIT) @@ -1655,11 +1657,21 @@ if(buckled) if(!.) ADD_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT) - if(buckled.buckle_lying) - ADD_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT) - else if(.) + switch(buckled.buckle_lying) + if(NO_BUCKLE_LYING) // The buckle doesn't force a lying angle. + REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT) + return + if(0) // Forcing to a standing position. + REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT) + else // Forcing to a lying position. + ADD_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT) + set_lying_angle(buckled.buckle_lying) + else if(.) // We unbuckled from something. REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT) REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT) + var/atom/movable/old_buckled = . + if(old_buckled.buckle_lying == 0 && resting) // The buckle forced us to stay up (like a chair) and our preference is set to resting... + set_lying_down() // ...so let's drop on the ground. /mob/living/set_pulledby(new_pulledby) @@ -1707,6 +1719,23 @@ . = usable_legs usable_legs = new_value + if(new_value > .) // Gained leg usage. + REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + else if(!(movement_type & (FLYING | FLOATING))) //Lost leg usage, not flying. + if(!usable_legs) + ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + if(!usable_hands) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + + if(usable_legs < default_num_legs) + var/limbless_slowdown = (default_num_legs - usable_legs) * 3 + if(!usable_legs && usable_hands < default_num_hands) + limbless_slowdown += (default_num_hands - usable_hands) * 3 + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) + else + remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + ///Proc to modify the value of num_hands and hook behavior associated to this event. /mob/living/proc/set_num_hands(new_value) @@ -1723,6 +1752,12 @@ . = usable_hands usable_hands = new_value + if(new_value > .) // Gained hand usage. + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + else if(!(movement_type & (FLYING | FLOATING)) && !usable_hands && !usable_legs) //Lost a hand, not flying, no hands left, no legs. + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + + /// Whether or not this mob will escape from storages while being picked up/held. /mob/living/proc/will_escape_storage() return FALSE diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 7ce45c53153..1ef24f3fb43 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -34,7 +34,7 @@ var/list/network = list("ss13") var/obj/machinery/camera/current var/list/connected_robots = list() - var/aiRestorePowerRoutine = 0 + var/aiRestorePowerRoutine = POWER_RESTORATION_OFF var/requires_power = POWER_REQ_ALL var/can_be_carded = TRUE var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list()) @@ -170,6 +170,9 @@ builtInCamera = new (src) builtInCamera.network = list("ss13") + ADD_TRAIT(src, TRAIT_PULL_BLOCKED, ROUNDSTART_TRAIT) + + /mob/living/silicon/ai/key_down(_key, client/user) if(findtext(_key, "numpad")) //if it's a numpad number, we can convert it to just the number _key = _key[7] //strings, lists, same thing really @@ -798,10 +801,6 @@ /mob/living/silicon/ai/can_buckle() return FALSE -/mob/living/silicon/ai/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_stasis = FALSE) - if(aiRestorePowerRoutine) - return TRUE - return ..() /mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) if(control_disabled || incapacitated()) @@ -1032,3 +1031,16 @@ /mob/living/silicon/ai/zMove(dir, feedback = FALSE) . = eyeobj.zMove(dir, feedback) + + +/// Proc to hook behavior to the changes of the value of [aiRestorePowerRoutine]. +/mob/living/silicon/ai/proc/setAiRestorePowerRoutine(new_value) + if(new_value == aiRestorePowerRoutine) + return + . = aiRestorePowerRoutine + aiRestorePowerRoutine = new_value + if(aiRestorePowerRoutine) + if(!.) + ADD_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT) + else if(.) + REMOVE_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT) diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index c40dfd67fd5..1996b816b14 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -1,8 +1,3 @@ -#define POWER_RESTORATION_OFF 0 -#define POWER_RESTORATION_START 1 -#define POWER_RESTORATION_SEARCH_APC 2 -#define POWER_RESTORATION_APC_FOUND 3 - /mob/living/silicon/ai/Life() if (stat == DEAD) return @@ -110,7 +105,7 @@ T = get_turf(src) if(isspaceturf(T)) to_chat(src, "Unable to verify! No power connection detected!") - aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC + setAiRestorePowerRoutine(POWER_RESTORATION_SEARCH_APC) return to_chat(src, "Connection verified. Searching for APC in power network.") sleep(50) @@ -131,7 +126,7 @@ to_chat(src, "Unable to locate APC!") else to_chat(src, "Lost connection with the APC!") - aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC + setAiRestorePowerRoutine(POWER_RESTORATION_SEARCH_APC) return if(AIarea.power_equip) if(!isspaceturf(T)) @@ -152,7 +147,7 @@ apc_override = 1 theAPC.ui_interact(src) apc_override = 0 - aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND + setAiRestorePowerRoutine(POWER_RESTORATION_APC_FOUND) sleep(50) theAPC = null @@ -162,19 +157,14 @@ to_chat(src, "Alert cancelled. Power has been restored.") else to_chat(src, "Alert cancelled. Power has been restored without our assistance.") - aiRestorePowerRoutine = POWER_RESTORATION_OFF + setAiRestorePowerRoutine(POWER_RESTORATION_OFF) set_blindness(0) update_sight() /mob/living/silicon/ai/proc/ai_lose_power() disconnect_shell() - aiRestorePowerRoutine = POWER_RESTORATION_START + setAiRestorePowerRoutine(POWER_RESTORATION_START) blind_eyes(1) update_sight() to_chat(src, "You've lost power!") addtimer(CALLBACK(src, .proc/start_RestorePowerRoutine), 20) - -#undef POWER_RESTORATION_OFF -#undef POWER_RESTORATION_START -#undef POWER_RESTORATION_SEARCH_APC -#undef POWER_RESTORATION_APC_FOUND diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 6f8c212ce8c..78dd47bab20 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -375,7 +375,7 @@ icon_state_on = "protoemitter_+a" icon_state_underpowered = "protoemitter_+u" can_buckle = TRUE - buckle_lying = FALSE + buckle_lying = 0 var/view_range = 4.5 var/datum/action/innate/protoemitter/firing/auto