From b3a4aa501f63afef9fc121489f62f53cf6f064ff Mon Sep 17 00:00:00 2001 From: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:48:18 +0200 Subject: [PATCH] Life changes (#19560) Refactored Life() to receive seconds per tick and times fired as parameters. Life() now cannot be slept in, turned various sleepings into async calls procs. Optimized mob AI subsystems, gave them new priorities levels and flags. Grab upgrades are now elaborated asynchronously, tweaked them to avoid stacking multiple upgrades. Fixed plains tyrants keeping sending messages about stomping even if dead. --- code/__DEFINES/subsystem-priority.dm | 1 - code/__DEFINES/subsystems.dm | 8 + code/controllers/subsystems/mob.dm | 32 +-- code/controllers/subsystems/mob_ai.dm | 25 +- code/controllers/subsystems/mob_fast_ai.dm | 7 + code/defines/procs/hud.dm | 4 +- code/game/objects/items/weapons/tools.dm | 2 +- code/modules/heavy_vehicle/mech_life.dm | 2 +- code/modules/mob/abstract/freelook/life.dm | 2 +- .../modules/mob/abstract/observer/observer.dm | 2 +- code/modules/mob/living/announcer.dm | 3 +- code/modules/mob/living/bot/bot.dm | 7 +- code/modules/mob/living/bot/cleanbot.dm | 8 +- code/modules/mob/living/bot/farmbot.dm | 2 +- .../mob/living/carbon/alien/diona/life.dm | 2 +- code/modules/mob/living/carbon/alien/life.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/living/carbon/human/life.dm | 2 +- code/modules/mob/living/carbon/slime/life.dm | 2 +- code/modules/mob/living/life.dm | 12 +- code/modules/mob/living/silicon/ai/life.dm | 248 +++++++++--------- code/modules/mob/living/silicon/decoy/life.dm | 14 +- code/modules/mob/living/silicon/pai/life.dm | 20 +- code/modules/mob/living/silicon/robot/life.dm | 8 +- .../mob/living/simple_animal/aquatic.dm | 2 +- code/modules/mob/living/simple_animal/bees.dm | 2 +- .../mob/living/simple_animal/borer/borer.dm | 2 +- .../simple_animal/borer/borer_captive.dm | 2 +- .../constructs/constructs/cult_construct.dm | 2 +- .../living/simple_animal/friendly/adhomai.dm | 2 +- .../mob/living/simple_animal/friendly/cat.dm | 2 +- .../simple_animal/friendly/farm_animals.dm | 6 +- .../living/simple_animal/friendly/lizard.dm | 2 +- .../mob/living/simple_animal/friendly/rat.dm | 2 +- .../mob/living/simple_animal/hostile/bat.dm | 2 +- .../simple_animal/hostile/cavern_geist.dm | 2 +- .../simple_animal/hostile/changeling.dm | 7 +- .../living/simple_animal/hostile/creature.dm | 2 +- .../living/simple_animal/hostile/faithless.dm | 2 +- .../simple_animal/hostile/giant_spider.dm | 2 +- .../hostile/hivebots/hivebot_beacon.dm | 2 +- .../simple_animal/hostile/icarus_drone.dm | 2 +- .../living/simple_animal/hostile/moghes.dm | 9 +- .../mob/living/simple_animal/hostile/morph.dm | 2 +- .../hostile/retaliate/aquatic.dm | 2 +- .../simple_animal/hostile/retaliate/cavern.dm | 2 +- .../living/simple_animal/hostile/sarlacc.dm | 2 +- .../simple_animal/hostile/spider_queen.dm | 2 +- .../modules/mob/living/simple_animal/shade.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 2 +- code/modules/mob/living/simple_animal/worm.dm | 4 +- code/modules/mob/mob.dm | 16 +- code/modules/mob/mob_grab.dm | 3 + code/modules/shareddream/brainghost.dm | 2 +- html/changelogs/fluffyghost-lifechanges.yml | 62 +++++ 55 files changed, 350 insertions(+), 222 deletions(-) create mode 100644 html/changelogs/fluffyghost-lifechanges.yml diff --git a/code/__DEFINES/subsystem-priority.dm b/code/__DEFINES/subsystem-priority.dm index c8fc867e158..9a8d183c34f 100644 --- a/code/__DEFINES/subsystem-priority.dm +++ b/code/__DEFINES/subsystem-priority.dm @@ -33,7 +33,6 @@ // Normal #define SS_PRIORITY_TICKER 100 // Gameticker. //#define FIRE_PRIORITY_DEFAULT 50 // This is defined somewhere else. -#define SS_PRIORITY_MOB 40 // Mob Life(). #define SS_PRIORITY_AIR 40 // ZAS processing. #define SS_PRIORITY_STATPANELS 25 // Statpanels. #define SS_PRIORITY_LIGHTING 25 // Queued lighting engine updates. diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index e82fda2684d..5c89a51a997 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -215,6 +215,7 @@ #define INIT_ORDER_SOUNDS 83 #define INIT_ORDER_DISCORD 78 #define INIT_ORDER_JOBS 65 // Must init before atoms, to set up properly the dynamic job lists. +#define INIT_ORDER_AI_CONTROLLERS 55 //So the controller can get the ref #define INIT_ORDER_TICKER 55 #define INIT_ORDER_SEEDS 52 // More aurora snowflake, needs to load before the atoms init as it generates images for seeds that are used #define INIT_ORDER_MISC_FIRST 51 //Another aurora snowflake system? Who would have guessed... Anyways, need to load before mapping or global HUDs are not ready when atoms request them @@ -252,11 +253,14 @@ #define FIRE_PRIORITY_PING 10 #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_ASSETS 20 +#define FIRE_PRIORITY_NPC_MOVEMENT 21 +#define FIRE_PRIORITY_NPC_ACTIONS 22 #define FIRE_PRIORITY_PATHFINDING 23 #define FIRE_PRIORITY_PROCESS 25 #define FIRE_PRIORITY_THROWING 25 #define FIRE_PRIORITY_SPACEDRIFT 30 #define FIRE_PRIORITY_DEFAULT 50 +#define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_STATPANEL 390 #define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_RUNECHAT 410 @@ -273,6 +277,10 @@ */ #define addtimer(args...) _addtimer(args, file = __FILE__, line = __LINE__) +// Subsystem delta times or tickrates, in seconds. I.e, how many seconds in between each process() call for objects being processed by that subsystem. +// Only use these defines if you want to access some other objects processing seconds_per_tick, otherwise use the seconds_per_tick that is sent as a parameter to process() +#define SSMOBS_DT (SSmobs.wait/10) + /* AURORA SHIT */ // Don't display in processes panel. diff --git a/code/controllers/subsystems/mob.dm b/code/controllers/subsystems/mob.dm index f507759b351..64e75f08707 100644 --- a/code/controllers/subsystems/mob.dm +++ b/code/controllers/subsystems/mob.dm @@ -1,10 +1,9 @@ SUBSYSTEM_DEF(mobs) name = "Mobs - Life" - init_order = INIT_ORDER_MISC // doesn't really matter when we init - priority = SS_PRIORITY_MOB - runlevels = RUNLEVELS_PLAYING - - var/list/slept = list() + priority = FIRE_PRIORITY_MOBS + flags = SS_KEEP_TIMING + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + wait = 2 SECONDS var/list/currentrun = list() var/list/processing = list() @@ -70,7 +69,7 @@ SUBSYSTEM_DEF(mobs) return SS_INIT_SUCCESS /datum/controller/subsystem/mobs/stat_entry(msg) - msg = "P:[GLOB.mob_list.len]" + msg = "P:[length(GLOB.mob_list)]" return ..() /datum/controller/subsystem/mobs/fire(resumed = 0) @@ -82,10 +81,12 @@ SUBSYSTEM_DEF(mobs) //the mobs that we didn't in the previous run, hence we have to pay the price of a list subtraction //with &= we say to remove any item in the first list that is not in the second one //of course, if we haven't resumed, this comparison would be useless, hence we skip it - var/list/currentrun = resumed ? (src.currentrun &= GLOB.mob_list) : src.currentrun + var/list/currentrun = resumed ? (src.currentrun &= (GLOB.mob_list + processing)) : src.currentrun - while (currentrun.len) - var/datum/thing = currentrun[currentrun.len] + var/seconds_per_tick = wait / (1 SECONDS) + + while(length(currentrun)) + var/datum/thing = currentrun[length(currentrun)] currentrun.len-- if(!ismob(thing)) if(!QDELETED(thing)) @@ -93,13 +94,13 @@ SUBSYSTEM_DEF(mobs) stop_processing(thing) else processing -= thing - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return continue var/mob/M = thing - if (QDELETED(M)) + if(QDELETED(M)) LOG_DEBUG("SSmobs: QDELETED mob [DEBUG_REF(M)] left in processing list!") // We can just go ahead and remove them from all the mob lists. GLOB.mob_list -= M @@ -110,15 +111,8 @@ SUBSYSTEM_DEF(mobs) return continue - var/time = world.time - if (!M.frozen) - M.Life() - - if (time != world.time && !slept[M.type]) - slept[M.type] = TRUE - var/diff = world.time - time - LOG_DEBUG("SSmobs: Type '[M.type]' slept for [diff] ds in Life()! Suppressing further warnings.") + M.Life(seconds_per_tick, times_fired) if (MC_TICK_CHECK) return diff --git a/code/controllers/subsystems/mob_ai.dm b/code/controllers/subsystems/mob_ai.dm index 631380cad20..fff49cc8e96 100644 --- a/code/controllers/subsystems/mob_ai.dm +++ b/code/controllers/subsystems/mob_ai.dm @@ -1,17 +1,18 @@ SUBSYSTEM_DEF(mob_ai) name = "Mobs - AI" - flags = SS_NO_INIT - priority = SS_PRIORITY_MOB - runlevels = RUNLEVELS_PLAYING + flags = SS_POST_FIRE_TIMING | SS_BACKGROUND | SS_NO_INIT + priority = FIRE_PRIORITY_NPC_MOVEMENT + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + init_order = INIT_ORDER_AI_CONTROLLERS var/list/processing = list() var/list/currentrun = list() ///A list of mutex locks, to avoid reentry and starting new processings on mobs that were already processing from the previous run - var/list/datum/weakref/mutexes = list() //Yes i know they're opinionably not mutexes as there's only one process shut up + VAR_PRIVATE/list/datum/weakref/mutexes = list() //Yes i know they're opinionably not mutexes as there's only one process shut up /datum/controller/subsystem/mob_ai/stat_entry(msg) - msg = "P:[processing.len]" + msg = "P:[length(processing)]" return ..() /datum/controller/subsystem/mob_ai/fire(resumed = FALSE) @@ -21,7 +22,7 @@ SUBSYSTEM_DEF(mob_ai) var/list/currentrun = src.currentrun //Remove the mobs that have a mutex from being reprocessed again, this run - for(var/datum/weakref/locked_mob in mutexes) + for(var/datum/weakref/locked_mob as anything in mutexes) var/mob/possible_locked_mob = locked_mob.resolve() //The mob got QDEL'd, or otherwise somehow disappeared @@ -31,24 +32,24 @@ SUBSYSTEM_DEF(mob_ai) currentrun -= possible_locked_mob - while (currentrun.len) - var/mob/M = currentrun[currentrun.len] + while(length(currentrun)) + var/mob/M = currentrun[length(currentrun)] currentrun.len-- - if (QDELETED(M)) + if(QDELETED(M)) processing -= M continue - if (M.ckey) + if(M.ckey) // cliented mobs are not allowed to think LOG_DEBUG("SSmob_ai: Type '[M.type]' was still thinking despite having a client!") MOB_STOP_THINKING(M) continue - if (!M.frozen && !M.stat) + if(!M.frozen && !M.stat) INVOKE_ASYNC(src, PROC_REF(async_think), M) - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return /** diff --git a/code/controllers/subsystems/mob_fast_ai.dm b/code/controllers/subsystems/mob_fast_ai.dm index bfdaf72577a..42251a839e7 100644 --- a/code/controllers/subsystems/mob_fast_ai.dm +++ b/code/controllers/subsystems/mob_fast_ai.dm @@ -1,3 +1,10 @@ +/** + * This is the fast AI subsystem, used for mobs that are doing something visible and thus have priority over other mobs processing + * + * You should promote mobs to fast thinking if eg. they are fighting players or similar, and de-promote them once they resume their normal routine + */ MOB_AI_SUBSYSTEM_DEF(mob_fast_ai) name = "Mobs - Fast AI" + flags = SS_KEEP_TIMING | SS_BACKGROUND | SS_NO_INIT + priority = FIRE_PRIORITY_NPC_ACTIONS wait = 5 diff --git a/code/defines/procs/hud.dm b/code/defines/procs/hud.dm index a11b2ce9e7e..a51d2aabd22 100644 --- a/code/defines/procs/hud.dm +++ b/code/defines/procs/hud.dm @@ -110,7 +110,9 @@ the HUD updates properly! */ // if(get_dist(H, T) <= client?.view) // viewed += H // return viewed - return get_hearers_in_range(client?.view, T) + + //Some virtual eyes eg. the AI eye doesn't have a client but an owner, select it as preferred if so, otherwise use the mob's client itself + return get_hearers_in_range((src.owner ? src.owner.client?.view : src.client?.view), T) /proc/get_sec_hud_icon(var/mob/living/carbon/human/H)//This function is called from human/life,dm, ~line 1663 var/state diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 593928cd78d..31531ca3d85 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -542,7 +542,7 @@ damtype = DAMAGE_BURN w_class = ITEMSIZE_LARGE welding = TRUE - hitsound = SOUNDS_LASER_MEAT + hitsound = pick(SOUNDS_LASER_MEAT) attack_verb = list("scorched", "burned", "blasted", "blazed") update_icon() set_processing(TRUE) diff --git a/code/modules/heavy_vehicle/mech_life.dm b/code/modules/heavy_vehicle/mech_life.dm index ab0f5759264..7e012dcfffc 100644 --- a/code/modules/heavy_vehicle/mech_life.dm +++ b/code/modules/heavy_vehicle/mech_life.dm @@ -4,7 +4,7 @@ /mob/living/heavy_vehicle/handle_status_effects() return -/mob/living/heavy_vehicle/Life() +/mob/living/heavy_vehicle/Life(seconds_per_tick, times_fired) // Size offsets for large mechs. if(offset_x && pixel_x != offset_x) diff --git a/code/modules/mob/abstract/freelook/life.dm b/code/modules/mob/abstract/freelook/life.dm index 975b266413d..d7b0aaefe7a 100644 --- a/code/modules/mob/abstract/freelook/life.dm +++ b/code/modules/mob/abstract/freelook/life.dm @@ -1,4 +1,4 @@ -/mob/abstract/eye/Life() +/mob/abstract/eye/Life(seconds_per_tick, times_fired) ..() // If we lost our client, reset the list of visible chunks so they update properly on return if(owner == src && !client) diff --git a/code/modules/mob/abstract/observer/observer.dm b/code/modules/mob/abstract/observer/observer.dm index 23384f836e4..594471e51b0 100644 --- a/code/modules/mob/abstract/observer/observer.dm +++ b/code/modules/mob/abstract/observer/observer.dm @@ -145,7 +145,7 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body Works together with spawning an observer, noted above. */ -/mob/abstract/observer/Life() +/mob/abstract/observer/Life(seconds_per_tick, times_fired) ..() if(!loc) return if(!client) return 0 diff --git a/code/modules/mob/living/announcer.dm b/code/modules/mob/living/announcer.dm index 7a6550bcf80..8d6a6121d52 100755 --- a/code/modules/mob/living/announcer.dm +++ b/code/modules/mob/living/announcer.dm @@ -59,7 +59,8 @@ src.voice_name = initial(voice_name) src.accent = initial(accent) -/mob/living/announcer/Life() +/mob/living/announcer/Life(seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) return /mob/living/announcer/Move() diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 11c011e6cc8..bd1f7a92b87 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -55,15 +55,18 @@ if(pAI) . += FONT_SMALL(SPAN_NOTICE("It has a pAI piloting it.")) -/mob/living/bot/Life() +/mob/living/bot/Life(seconds_per_tick, times_fired) ..() if(health <= 0) death() - return + return FALSE + weakened = 0 stunned = 0 paralysis = 0 + return TRUE + /mob/living/bot/movement_delay() return 3 diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index c117a64c43d..cfbb7ee27da 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -144,8 +144,10 @@ GLOBAL_LIST_INIT_TYPED(cleanbot_types, /obj/effect/decal/cleanable, typesof(/obj /mob/living/bot/cleanbot/proc/remove_from_ignore(datum/weakref/thing_to_unignore) ignorelist -= thing_to_unignore -/mob/living/bot/cleanbot/Life() - ..() +/mob/living/bot/cleanbot/Life(seconds_per_tick, times_fired) + if(!..()) + return FALSE + if(!on) ignorelist = list() return @@ -173,6 +175,8 @@ GLOBAL_LIST_INIT_TYPED(cleanbot_types, /obj/effect/decal/cleanable, typesof(/obj ignorelist += gib addtimer(CALLBACK(src, PROC_REF(remove_from_ignore), gib), 600) + return TRUE + /mob/living/bot/cleanbot/think() if(pAI) // no AI if we have a pAI installed return diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm index 836d7ca3d1e..16acd590ef9 100644 --- a/code/modules/mob/living/bot/farmbot.dm +++ b/code/modules/mob/living/bot/farmbot.dm @@ -134,7 +134,7 @@ else icon_state = "farmbot[on]" -/mob/living/bot/farmbot/Life() +/mob/living/bot/farmbot/Life(seconds_per_tick, times_fired) ..() if(emagged && prob(1)) flick("farmbot_broke", src) diff --git a/code/modules/mob/living/carbon/alien/diona/life.dm b/code/modules/mob/living/carbon/alien/diona/life.dm index ecfc609b1fc..2ef54e59d3f 100644 --- a/code/modules/mob/living/carbon/alien/diona/life.dm +++ b/code/modules/mob/living/carbon/alien/diona/life.dm @@ -35,7 +35,7 @@ diona_handle_radiation(DS) -/mob/living/carbon/alien/diona/Life() +/mob/living/carbon/alien/diona/Life(seconds_per_tick, times_fired) if(!detached && gestalt && (gestalt.life_tick % 5 == 0)) // Minimal processing while in stasis updatehealth() check_status_as_organ() diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm index 0b502a90757..afe455ba172 100644 --- a/code/modules/mob/living/carbon/alien/life.dm +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -1,5 +1,5 @@ // Alien larva are quite simple. -/mob/living/carbon/alien/Life() +/mob/living/carbon/alien/Life(seconds_per_tick, times_fired) if (transforming) return if(!loc) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e8d7a9d34e5..d5e2fae967c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -10,7 +10,7 @@ if(species && species.indefinite_sleep) add_verb(src, /verb/toggle_indefinite_sleep) -/mob/living/carbon/Life() +/mob/living/carbon/Life(seconds_per_tick, times_fired) if(!..()) return diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index f0083a39742..90484088239 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -29,7 +29,7 @@ var/pressure_alert = 0 var/temperature_alert = 0 -/mob/living/carbon/human/Life() +/mob/living/carbon/human/Life(seconds_per_tick, times_fired) if (transforming) return diff --git a/code/modules/mob/living/carbon/slime/life.dm b/code/modules/mob/living/carbon/slime/life.dm index fb22866fa37..0c02418339b 100644 --- a/code/modules/mob/living/carbon/slime/life.dm +++ b/code/modules/mob/living/carbon/slime/life.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/slime/Life() +/mob/living/carbon/slime/Life(seconds_per_tick, times_fired) if(src.transforming) return ..() diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 40f3be5e3fb..08a750dca3c 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -1,14 +1,14 @@ -/mob/living/Life() +/mob/living/Life(seconds_per_tick, times_fired) if (QDELETED(src)) // If they're being deleted, why bother? - return + return FALSE ..() - if (transforming) - return + if(transforming) + return FALSE if(!loc) - return + return FALSE var/datum/gas_mixture/gas_environment = loc.return_air() //Handle temperature/pressure differences between body and environment @@ -32,7 +32,7 @@ update_pulling() for(var/obj/item/grab/G in src) - G.process() + INVOKE_ASYNC(G, TYPE_PROC_REF(/datum, process)) handle_actions() diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 90162d02fb0..b1070d4387e 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -1,129 +1,69 @@ -/mob/living/silicon/ai/Life() +/mob/living/silicon/ai/Life(seconds_per_tick, times_fired) + if(!..()) + return FALSE + if (src.stat == DEAD) + return FALSE + + if (src.stat!=CONSCIOUS) + src.cameraFollow = null + src.reset_view(null) + + src.updatehealth() + + if (hardware_integrity() <= 0 || backup_capacitor() <= 0) + death() return - else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist - //Being dead doesn't mean your temperature never changes - var/turf/T = get_turf(src) - if (src.stat!=CONSCIOUS) - src.cameraFollow = null - src.reset_view(null) + // If our powersupply object was destroyed somehow, create new one. + if(!psupply) + create_powersupply() - src.updatehealth() - if (hardware_integrity() <= 0 || backup_capacitor() <= 0) - death() + // Handle power damage (oxy) + if(ai_restore_power_routine != 0 && !APU_power) + // Lose power + adjustOxyLoss(1) + else + // Gain Power + ai_restore_power_routine = 0 // Necessary if AI activated it's APU AFTER losing primary power. + adjustOxyLoss(-1) + + handle_stunned() // Handle EMP-stun + lying = 0 // Handle lying down + + malf_process() + + if(APU_power && (hardware_integrity() < 50)) + to_chat(src, SPAN_NOTICE("APU GENERATOR FAILURE! (System Damaged)")) + stop_apu(1) + + if (!is_blind()) + if (ai_restore_power_routine==2) + to_chat(src, "Alert cancelled. Power has been restored without our assistance.") + ai_restore_power_routine = 0 + clear_fullscreen("blind") + update_icon() return + else if (ai_restore_power_routine==3) + to_chat(src, "Alert cancelled. Power has been restored.") + ai_restore_power_routine = 0 + clear_fullscreen("blind") + update_icon() + return + else if (APU_power) + ai_restore_power_routine = 0 + clear_fullscreen("blind") + update_icon() + return + else + var/area/current_area = get_area(src) - // If our powersupply object was destroyed somehow, create new one. - if(!psupply) - create_powersupply() + if(lacks_power()) + if(ai_restore_power_routine==0) + INVOKE_ASYNC(src, PROC_REF(handle_power_loss), current_area) - // Handle power damage (oxy) - if(ai_restore_power_routine != 0 && !APU_power) - // Lose power - adjustOxyLoss(1) - else - // Gain Power - ai_restore_power_routine = 0 // Necessary if AI activated it's APU AFTER losing primary power. - adjustOxyLoss(-1) - - handle_stunned() // Handle EMP-stun - lying = 0 // Handle lying down - - malf_process() - - if(APU_power && (hardware_integrity() < 50)) - to_chat(src, SPAN_NOTICE("APU GENERATOR FAILURE! (System Damaged)")) - stop_apu(1) - - if (!is_blind()) - if (ai_restore_power_routine==2) - to_chat(src, "Alert cancelled. Power has been restored without our assistance.") - ai_restore_power_routine = 0 - clear_fullscreen("blind") - update_icon() - return - else if (ai_restore_power_routine==3) - to_chat(src, "Alert cancelled. Power has been restored.") - ai_restore_power_routine = 0 - clear_fullscreen("blind") - update_icon() - return - else if (APU_power) - ai_restore_power_routine = 0 - clear_fullscreen("blind") - update_icon() - return - else - var/area/current_area = get_area(src) - - if (lacks_power()) - if (ai_restore_power_routine==0) - ai_restore_power_routine = 1 - - //Now to tell the AI why they're blind and dying slowly. - to_chat(src, "You've lost power!") - - spawn(20) - to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.") - sleep(50) - if (current_area.power_equip) - if (!istype(T, /turf/space)) - to_chat(src, "Alert cancelled. Power has been restored without our assistance.") - ai_restore_power_routine = 0 - clear_fullscreen("blind") - return - to_chat(src, "Fault confirmed: missing external power. Shutting down main control system to save power.") - sleep(20) - to_chat(src, "Emergency control system online. Verifying connection to power network.") - sleep(50) - if (istype(T, /turf/space)) - to_chat(src, "Unable to verify! No power connection detected!") - ai_restore_power_routine = 2 - return - to_chat(src, "Connection verified. Searching for APC in power network.") - sleep(50) - var/obj/machinery/power/apc/theAPC = null - - var/PRP - for (PRP=1, PRP<=4, PRP++) - for (var/obj/machinery/power/apc/APC in current_area) - if (!(APC.stat & BROKEN)) - theAPC = APC - break - if (!theAPC) - switch(PRP) - if (1) to_chat(src, "Unable to locate APC!") - else to_chat(src, "Lost connection with the APC!") - src:ai_restore_power_routine = 2 - return - if (current_area.power_equip) - if (!istype(T, /turf/space)) - to_chat(src, "Alert cancelled. Power has been restored without our assistance.") - ai_restore_power_routine = 0 - clear_fullscreen("blind") - return - switch(PRP) - if (1) to_chat(src, "APC located. Optimizing route to APC to avoid needless power waste.") - if (2) to_chat(src, "Best route identified. Hacking offline APC power port.") - if (3) to_chat(src, "Power port upload access confirmed. Loading control program into APC power port software.") - if (4) - to_chat(src, "Transfer complete. Forcing APC to execute program.") - sleep(50) - to_chat(src, "Receiving control information from APC.") - sleep(2) - theAPC.operating = 1 - theAPC.equipment = 3 - theAPC.update() - ai_restore_power_routine = 3 - to_chat(src, "Here are your current laws:") - show_laws() - update_icon() - sleep(50) - theAPC = null - process_queued_alarms() handle_regular_hud_updates() switch(src.sensor_mode) @@ -132,6 +72,80 @@ if (MED_HUD) process_med_hud(src,0,src.eyeobj) + return TRUE + +/** + * Handles the power loss for the AI + * + * Broken up from the Life() proc so it can be done async, I claim no part in the creation of this abhorrent mess + * apart from copying the code from the aforementioned proc + */ +/mob/living/silicon/ai/proc/handle_power_loss(area/current_area) + ai_restore_power_routine = 1 + + var/turf/T = get_turf(src) + + //Now to tell the AI why they're blind and dying slowly. + to_chat(src, "You've lost power!") + + spawn(20) + to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.") + sleep(50) + if (current_area.power_equip) + if (!istype(T, /turf/space)) + to_chat(src, "Alert cancelled. Power has been restored without our assistance.") + ai_restore_power_routine = 0 + clear_fullscreen("blind") + return + to_chat(src, "Fault confirmed: missing external power. Shutting down main control system to save power.") + sleep(20) + to_chat(src, "Emergency control system online. Verifying connection to power network.") + sleep(50) + if (istype(T, /turf/space)) + to_chat(src, "Unable to verify! No power connection detected!") + ai_restore_power_routine = 2 + return + to_chat(src, "Connection verified. Searching for APC in power network.") + sleep(50) + var/obj/machinery/power/apc/theAPC = null + + var/PRP + for (PRP=1, PRP<=4, PRP++) + for (var/obj/machinery/power/apc/APC in current_area) + if (!(APC.stat & BROKEN)) + theAPC = APC + break + if (!theAPC) + switch(PRP) + if (1) to_chat(src, "Unable to locate APC!") + else to_chat(src, "Lost connection with the APC!") + src:ai_restore_power_routine = 2 + return + if (current_area.power_equip) + if (!istype(T, /turf/space)) + to_chat(src, "Alert cancelled. Power has been restored without our assistance.") + ai_restore_power_routine = 0 + clear_fullscreen("blind") + return + switch(PRP) + if (1) to_chat(src, "APC located. Optimizing route to APC to avoid needless power waste.") + if (2) to_chat(src, "Best route identified. Hacking offline APC power port.") + if (3) to_chat(src, "Power port upload access confirmed. Loading control program into APC power port software.") + if (4) + to_chat(src, "Transfer complete. Forcing APC to execute program.") + sleep(50) + to_chat(src, "Receiving control information from APC.") + sleep(2) + theAPC.operating = 1 + theAPC.equipment = 3 + theAPC.update() + ai_restore_power_routine = 3 + to_chat(src, "Here are your current laws:") + show_laws() + update_icon() + sleep(50) + theAPC = null + /mob/living/silicon/ai/proc/lacks_power() if(APU_power) return 0 diff --git a/code/modules/mob/living/silicon/decoy/life.dm b/code/modules/mob/living/silicon/decoy/life.dm index fe9234dbad3..719169cad96 100644 --- a/code/modules/mob/living/silicon/decoy/life.dm +++ b/code/modules/mob/living/silicon/decoy/life.dm @@ -1,10 +1,14 @@ -/mob/living/silicon/decoy/Life() - if (src.stat == 2) - return +/mob/living/silicon/decoy/Life(seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) + + if (src.stat == DEAD) + return FALSE else - if (src.health <= GLOB.config.health_threshold_dead && src.stat != 2) + if (src.health <= GLOB.config.health_threshold_dead && src.stat != DEAD) death() - return + return FALSE + + return TRUE /mob/living/silicon/decoy/updatehealth() diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 4f01bab0d75..a0354176403 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -1,23 +1,23 @@ -/mob/living/silicon/pai/Life() +/mob/living/silicon/pai/Life(seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) - if (src.stat == 2) - return + if(src.stat == DEAD) + return FALSE if(src.cable) if(get_dist(src, src.cable) > 1) var/turf/T = get_turf_or_move(src.loc) for (var/mob/M in viewers(T)) M.show_message(SPAN_WARNING("The data cable rapidly retracts back into its spool."), 3, SPAN_WARNING("You hear a click and the sound of wire spooling rapidly."), 2) - qdel(src.cable) - src.cable = null + QDEL_NULL(src.cable) handle_regular_hud_updates() - if(src.secHUD == 1) - process_sec_hud(src, 1) + if(src.secHUD) + process_sec_hud(src, TRUE) - if(src.medHUD == 1) - process_med_hud(src, 1) + if(src.medHUD) + process_med_hud(src, TRUE) if(silence_time) if(world.timeofday >= silence_time) @@ -29,6 +29,8 @@ if(health <= 0) death(null,"gives one shrill beep before falling lifeless.") + return TRUE + /mob/living/silicon/pai/updatehealth() if(status_flags & GODMODE) health = maxHealth diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 540e0d8a0d9..0c2613ea011 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -1,4 +1,6 @@ -/mob/living/silicon/robot/Life() +/mob/living/silicon/robot/Life(seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) + if(transforming) return @@ -27,6 +29,8 @@ process_level_restrictions() update_canmove() + return TRUE + /mob/living/silicon/robot/proc/clamp_values() SetParalysis(min(paralysis, 30)) sleeping = FALSE @@ -318,7 +322,7 @@ if(istype(get_area(src), /area/centcom) || istype(get_area(src), /area/shuttle/escape) || istype(get_area(src), /area/shuttle/arrival)) return FALSE if(!self_destructing) - start_self_destruct(TRUE) + INVOKE_ASYNC(src, PROC_REF(start_self_destruct), TRUE) return TRUE /mob/living/silicon/robot/update_fire() diff --git a/code/modules/mob/living/simple_animal/aquatic.dm b/code/modules/mob/living/simple_animal/aquatic.dm index fae99e3324d..fcace16fbf5 100644 --- a/code/modules/mob/living/simple_animal/aquatic.dm +++ b/code/modules/mob/living/simple_animal/aquatic.dm @@ -28,7 +28,7 @@ icon_state = "[icon_state]" return ..()//Proceed as normal. -/mob/living/simple_animal/aquatic/Life() +/mob/living/simple_animal/aquatic/Life(seconds_per_tick, times_fired) var/turf/T = get_turf(src) if (!(is_type_in_list(T,suitable_turf_types))) alpha = 255//Becomes a solid color because it is revealed diff --git a/code/modules/mob/living/simple_animal/bees.dm b/code/modules/mob/living/simple_animal/bees.dm index f66d2b21ceb..9bbb6fbab65 100644 --- a/code/modules/mob/living/simple_animal/bees.dm +++ b/code/modules/mob/living/simple_animal/bees.dm @@ -59,7 +59,7 @@ else ..() -/mob/living/simple_animal/bee/Life() +/mob/living/simple_animal/bee/Life(seconds_per_tick, times_fired) if(!loner && strength && !parent && prob(7-strength)) strength -= 1 diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm index 7bfacebc3b0..2cb0e14610b 100644 --- a/code/modules/mob/living/simple_animal/borer/borer.dm +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -78,7 +78,7 @@ /mob/living/simple_animal/borer/can_name(var/mob/living/M) return FALSE -/mob/living/simple_animal/borer/Life() +/mob/living/simple_animal/borer/Life(seconds_per_tick, times_fired) if(host) if(!stat && host.stat != DEAD) if(chemicals < 250) diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm index cba5969aeda..b04ccd6fef1 100644 --- a/code/modules/mob/living/simple_animal/borer/borer_captive.dm +++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm @@ -28,7 +28,7 @@ QDEL_NULL(resist_bar) return ..() -/mob/living/captive_brain/Life() +/mob/living/captive_brain/Life(seconds_per_tick, times_fired) if(resist_bar) resist_bar.update(world.time - resist_start_time) return ..() diff --git a/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm b/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm index 584ecf48703..3fc85e209d7 100644 --- a/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm +++ b/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm @@ -131,7 +131,7 @@ AddOverlays(glow) set_light(2, -2, l_color = COLOR_WHITE) -/mob/living/simple_animal/construct/Life() +/mob/living/simple_animal/construct/Life(seconds_per_tick, times_fired) . = ..() if(.) var/newstate diff --git a/code/modules/mob/living/simple_animal/friendly/adhomai.dm b/code/modules/mob/living/simple_animal/friendly/adhomai.dm index 9f99fe06c1f..b90d133904f 100644 --- a/code/modules/mob/living/simple_animal/friendly/adhomai.dm +++ b/code/modules/mob/living/simple_animal/friendly/adhomai.dm @@ -40,7 +40,7 @@ else ..() -/mob/living/simple_animal/ice_tunneler/Life() +/mob/living/simple_animal/ice_tunneler/Life(seconds_per_tick, times_fired) . =..() if(!.) return diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 9eec84ecfe1..27b5943836e 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -151,7 +151,7 @@ .=..() set_stat(DEAD) -/mob/living/simple_animal/cat/Life() +/mob/living/simple_animal/cat/Life(seconds_per_tick, times_fired) . = ..() handle_radiation_light() diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 8a84fcf6e36..ffe3b7139d9 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -32,7 +32,7 @@ butchering_products = list(/obj/item/stack/material/animalhide = 3) -/mob/living/simple_animal/hostile/retaliate/goat/Life() +/mob/living/simple_animal/hostile/retaliate/goat/Life(seconds_per_tick, times_fired) . = ..() if(.) if(locate(/obj/effect/plant) in loc) @@ -182,7 +182,7 @@ pixel_x = rand(-6, 6) pixel_y = rand(0, 10) -/mob/living/simple_animal/chick/Life() +/mob/living/simple_animal/chick/Life(seconds_per_tick, times_fired) . =..() if(!.) return @@ -271,7 +271,7 @@ else ..() -/mob/living/simple_animal/chicken/Life() +/mob/living/simple_animal/chicken/Life(seconds_per_tick, times_fired) . =..() if(!.) return diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm index 48e7f53f805..2841c4dea78 100644 --- a/code/modules/mob/living/simple_animal/friendly/lizard.dm +++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm @@ -30,7 +30,7 @@ . = ..() nutrition = rand(max_nutrition*0.25, max_nutrition*0.75) -/mob/living/simple_animal/lizard/Life() +/mob/living/simple_animal/lizard/Life(seconds_per_tick, times_fired) if (!..()) if ((world.time - timeofdeath) > decompose_time) dust() diff --git a/code/modules/mob/living/simple_animal/friendly/rat.dm b/code/modules/mob/living/simple_animal/friendly/rat.dm index 71bf4c20b4e..94144e5755a 100644 --- a/code/modules/mob/living/simple_animal/friendly/rat.dm +++ b/code/modules/mob/living/simple_animal/friendly/rat.dm @@ -57,7 +57,7 @@ kitchen_tag = "rodent" -/mob/living/simple_animal/rat/Life() +/mob/living/simple_animal/rat/Life(seconds_per_tick, times_fired) if(..()) if(client) diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm index 06adef7f2de..8749a22d2fe 100644 --- a/code/modules/mob/living/simple_animal/hostile/bat.dm +++ b/code/modules/mob/living/simple_animal/hostile/bat.dm @@ -80,6 +80,6 @@ /mob/living/simple_animal/hostile/scarybat/cult/cultify() return -/mob/living/simple_animal/hostile/scarybat/cult/Life() +/mob/living/simple_animal/hostile/scarybat/cult/Life(seconds_per_tick, times_fired) ..() check_horde() diff --git a/code/modules/mob/living/simple_animal/hostile/cavern_geist.dm b/code/modules/mob/living/simple_animal/hostile/cavern_geist.dm index d58d79a5643..e44baeca4b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/cavern_geist.dm +++ b/code/modules/mob/living/simple_animal/hostile/cavern_geist.dm @@ -43,7 +43,7 @@ ..() anchored = TRUE -/mob/living/simple_animal/hostile/cavern_geist/Life() +/mob/living/simple_animal/hostile/cavern_geist/Life(seconds_per_tick, times_fired) ..() adjustBruteLoss(-5) diff --git a/code/modules/mob/living/simple_animal/hostile/changeling.dm b/code/modules/mob/living/simple_animal/hostile/changeling.dm index 7fd0e1d69fd..dba3f45b266 100644 --- a/code/modules/mob/living/simple_animal/hostile/changeling.dm +++ b/code/modules/mob/living/simple_animal/hostile/changeling.dm @@ -64,11 +64,14 @@ mind.assigned_role = "Changeling" -/mob/living/simple_animal/hostile/true_changeling/Life() +/mob/living/simple_animal/hostile/true_changeling/Life(seconds_per_tick, times_fired) + if(!..()) + return FALSE + if(prob(10)) custom_emote(VISIBLE_MESSAGE, pick( list("shrieks!","roars!", "screeches!", "snarls!", "bellows!", "screams!") ) ) var/sound = pick(loud_sounds) - playsound(src, sound, 90, 1, 15, pressure_affected = 0) + playsound(src, sound, 90, TRUE, 15, pressure_affected = FALSE) /mob/living/simple_animal/hostile/true_changeling/death(gibbed) diff --git a/code/modules/mob/living/simple_animal/hostile/creature.dm b/code/modules/mob/living/simple_animal/hostile/creature.dm index ee1d85094a1..de3fb3d93b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/creature.dm +++ b/code/modules/mob/living/simple_animal/hostile/creature.dm @@ -37,6 +37,6 @@ /mob/living/simple_animal/hostile/creature/cult/cultify() return -/mob/living/simple_animal/hostile/creature/cult/Life() +/mob/living/simple_animal/hostile/creature/cult/Life(seconds_per_tick, times_fired) ..() check_horde() diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm index 8dd2bb94fdd..2a84a94fa47 100644 --- a/code/modules/mob/living/simple_animal/hostile/faithless.dm +++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm @@ -64,7 +64,7 @@ /mob/living/simple_animal/hostile/faithless/cult/cultify() return -/mob/living/simple_animal/hostile/faithless/cult/Life() +/mob/living/simple_animal/hostile/faithless/cult/Life(seconds_per_tick, times_fired) ..() check_horde() diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 944d071cb71..1c29b38bb73 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -95,7 +95,7 @@ var/playable = TRUE sample_data = list("Genetic markers identified as being linked with stem cell differentiaton", "Cellular structures indicative of high offspring production", "Tissue sample contains high neural cell content") -/mob/living/simple_animal/hostile/giant_spider/nurse/servant/Life() +/mob/living/simple_animal/hostile/giant_spider/nurse/servant/Life(seconds_per_tick, times_fired) ..() adjustBruteLoss(-2) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/hivebot_beacon.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/hivebot_beacon.dm index 0551cae5cbe..21bf1d830a0 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebots/hivebot_beacon.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/hivebot_beacon.dm @@ -326,7 +326,7 @@ return -/mob/living/simple_animal/hostile/hivebotbeacon/Life() +/mob/living/simple_animal/hostile/hivebotbeacon/Life(seconds_per_tick, times_fired) ..() if(wander) wander = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm b/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm index eda5b1b78d3..e4f4c2d47d3 100644 --- a/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/icarus_drone.dm @@ -153,7 +153,7 @@ return TRUE //self repair systems have a chance to bring the drone back to life -/mob/living/simple_animal/hostile/icarus_drone/Life() +/mob/living/simple_animal/hostile/icarus_drone/Life(seconds_per_tick, times_fired) //emps and lots of damage can temporarily shut us down if(disabled > 0) set_stat(UNCONSCIOUS) diff --git a/code/modules/mob/living/simple_animal/hostile/moghes.dm b/code/modules/mob/living/simple_animal/hostile/moghes.dm index 321ff552a48..5cd1c463074 100644 --- a/code/modules/mob/living/simple_animal/hostile/moghes.dm +++ b/code/modules/mob/living/simple_animal/hostile/moghes.dm @@ -51,8 +51,9 @@ ..() anchored = TRUE -/mob/living/simple_animal/hostile/biglizard/Life() - ..() +/mob/living/simple_animal/hostile/biglizard/Life(seconds_per_tick, times_fired) + if(!..()) + return FALSE //It's a predator, supposedly it shouldn't always alert his victims to be nearby //(also saves some processing) @@ -80,7 +81,9 @@ poor_soul_approaching.notify_message(message, 10 SECONDS, key = "biglizard-[REF(src)]") - adjustBruteLoss(-1) + adjustBruteLoss(-0.5 * seconds_per_tick) + + return TRUE /mob/living/simple_animal/hostile/biglizard/verb/devour(mob/living/target as mob in oview()) set category = "Plains Tyrant" diff --git a/code/modules/mob/living/simple_animal/hostile/morph.dm b/code/modules/mob/living/simple_animal/hostile/morph.dm index 6745e0b5091..9587d7d75ca 100644 --- a/code/modules/mob/living/simple_animal/hostile/morph.dm +++ b/code/modules/mob/living/simple_animal/hostile/morph.dm @@ -65,7 +65,7 @@ for(var/spell in morph_spells) add_spell(new spell, "const_spell_ready") -/mob/living/simple_animal/hostile/morph/Life() +/mob/living/simple_animal/hostile/morph/Life(seconds_per_tick, times_fired) . = ..() if(stat == DEAD && healths) healths.icon_state = "health6" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/aquatic.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/aquatic.dm index 5ad2e487bf4..d2349d0b5d1 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/aquatic.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/aquatic.dm @@ -28,7 +28,7 @@ icon_state = "[icon_state]" return ..()//Proceed as normal. -/mob/living/simple_animal/hostile/retaliate/aquatic/Life() +/mob/living/simple_animal/hostile/retaliate/aquatic/Life(seconds_per_tick, times_fired) var/turf/T = get_turf(src) if (!(is_type_in_list(T,suitable_turf_types))) alpha = 255//Becomes a solid color because it is revealed diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm index 2441cc7096b..7584e2382c7 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm @@ -136,7 +136,7 @@ O.forceMove(src.loc) qdel(src) -/mob/living/simple_animal/hostile/retaliate/minedrone/Life() +/mob/living/simple_animal/hostile/retaliate/minedrone/Life(seconds_per_tick, times_fired) ..() if(ore_count<20) FindOre() diff --git a/code/modules/mob/living/simple_animal/hostile/sarlacc.dm b/code/modules/mob/living/simple_animal/hostile/sarlacc.dm index 93deb2f02f2..7c3c7d87bf6 100644 --- a/code/modules/mob/living/simple_animal/hostile/sarlacc.dm +++ b/code/modules/mob/living/simple_animal/hostile/sarlacc.dm @@ -137,7 +137,7 @@ sarlacc = null return ..() -/mob/living/simple_animal/hostile/greatworm/Life() +/mob/living/simple_animal/hostile/greatworm/Life(seconds_per_tick, times_fired) ..() if(!sarlacc) var/obj/item/trap/sarlacc/L = new /obj/item/trap/sarlacc(src.loc) diff --git a/code/modules/mob/living/simple_animal/hostile/spider_queen.dm b/code/modules/mob/living/simple_animal/hostile/spider_queen.dm index 65c3c008623..4fc5697016c 100644 --- a/code/modules/mob/living/simple_animal/hostile/spider_queen.dm +++ b/code/modules/mob/living/simple_animal/hostile/spider_queen.dm @@ -125,6 +125,6 @@ M.apply_effect(6, STUN) return TRUE -/mob/living/simple_animal/hostile/giant_spider/nurse/spider_queen/Life() +/mob/living/simple_animal/hostile/giant_spider/nurse/spider_queen/Life(seconds_per_tick, times_fired) ..() adjustBruteLoss(-3) diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 34cd34d5c9c..3c7c563a107 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -149,7 +149,7 @@ to_chat(src, SPAN_DANGER("You feel yourself begin to fade away!")) ..() -/mob/living/simple_animal/shade/bluespace/Life() +/mob/living/simple_animal/shade/bluespace/Life(seconds_per_tick, times_fired) if(possessive && possessed_body) update_possession() ..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 501f91c6875..460efa13734 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -243,7 +243,7 @@ return FALSE return TRUE -/mob/living/simple_animal/Life() +/mob/living/simple_animal/Life(seconds_per_tick, times_fired) ..() life_tick++ if (stat == DEAD) diff --git a/code/modules/mob/living/simple_animal/worm.dm b/code/modules/mob/living/simple_animal/worm.dm index 80d670e7d09..cb2a1663d0f 100644 --- a/code/modules/mob/living/simple_animal/worm.dm +++ b/code/modules/mob/living/simple_animal/worm.dm @@ -47,7 +47,7 @@ var/atom/currentlyEating //what the worm is currently eating var/eatingDuration = 0 //how long he's been eating it for -/mob/living/simple_animal/space_worm/Life() +/mob/living/simple_animal/space_worm/Life(seconds_per_tick, times_fired) ..() if(next && !(next in view(src,1))) @@ -64,7 +64,7 @@ update_icon() - return + return TRUE /mob/living/simple_animal/space_worm/Destroy() //if a chunk a destroyed, make a new worm out of the split halves if(previous) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 1890191d91e..da79f56d247 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -279,11 +279,25 @@ if(P.buckled || locate(/mob) in P.contents) . += P.slowdown -/mob/proc/Life() +/** + * Handles the biological and general over-time processes of the mob. + * + * + * Arguments: + * - seconds_per_tick: The amount of time that has elapsed since this last fired + * - times_fired: The number of times SSmobs has fired + */ +/mob/proc/Life(seconds_per_tick = SSMOBS_DT, times_fired) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + if(LAZYLEN(spell_masters)) for(var/obj/screen/movable/spell_master/spell_master in spell_masters) spell_master.update_spells(0, src) + if(stat != DEAD) + return TRUE + /mob/proc/buckled_to() // Preliminary work for a future buckle rewrite, // where one might be fully restrained (like an elecrical chair), or merely secured (shuttle chair, keeping you safe but not otherwise restrained from acting) diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 4c77046cf3b..d346a35ad88 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -157,9 +157,12 @@ A.losebreath = max(A.losebreath + 3, 5) A.adjustOxyLoss(3) if(affecting.stat == CONSCIOUS) + state = GRAB_UPGRADING if(do_mob(assailant, affecting, 150)) A.visible_message(SPAN_WARNING("[A] falls unconscious..."), FONT_LARGE(SPAN_DANGER("The world goes dark as you fall unconscious..."))) A.Paralyse(20) + if(state == GRAB_UPGRADING) + state = GRAB_KILL else if(istype(affecting, /mob/living/simple_animal)) if(affecting.stat != DEAD) affecting.health -= 1 diff --git a/code/modules/shareddream/brainghost.dm b/code/modules/shareddream/brainghost.dm index 34c3de0ef4c..26eea0f9602 100644 --- a/code/modules/shareddream/brainghost.dm +++ b/code/modules/shareddream/brainghost.dm @@ -67,7 +67,7 @@ else to_chat(src, SPAN_WARNING("You've already released concentration. Wait to wake up naturally.")) -/mob/living/brain_ghost/Life() +/mob/living/brain_ghost/Life(seconds_per_tick, times_fired) ..() // Out body was probs gibbed or somefin if(!istype(body)) diff --git a/html/changelogs/fluffyghost-lifechanges.yml b/html/changelogs/fluffyghost-lifechanges.yml new file mode 100644 index 00000000000..653cd4b8f5b --- /dev/null +++ b/html/changelogs/fluffyghost-lifechanges.yml @@ -0,0 +1,62 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Refactored Life() to receive seconds per tick and times fired as parameters." + - refactor: "Life() now cannot be slept in, turned various sleepings into async calls procs." + - code_imp: "Optimized mob AI subsystems, gave them new priorities levels and flags." + - code_imp: "Grab upgrades are now elaborated asynchronously, tweaked them to avoid stacking multiple upgrades." + - bugfix: "Fixed plains tyrants keeping sending messages about stomping even if dead."