Files
Aurora.3/code/controllers/subsystems/mob_ai.dm
Fluffy b3a4aa501f 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.
2024-07-08 12:48:18 +00:00

93 lines
2.5 KiB
Plaintext

SUBSYSTEM_DEF(mob_ai)
name = "Mobs - AI"
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_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:[length(processing)]"
return ..()
/datum/controller/subsystem/mob_ai/fire(resumed = FALSE)
if (!resumed)
src.currentrun = processing.Copy()
var/list/currentrun = src.currentrun
//Remove the mobs that have a mutex from being reprocessed again, this run
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
if(!possible_locked_mob)
mutexes -= locked_mob
continue
currentrun -= possible_locked_mob
while(length(currentrun))
var/mob/M = currentrun[length(currentrun)]
currentrun.len--
if(QDELETED(M))
processing -= M
continue
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)
INVOKE_ASYNC(src, PROC_REF(async_think), M)
if(MC_TICK_CHECK)
return
/**
* Invoke .think() on a mob in an asyncronous manner, ensuring to properly set the mutex for it, so it's not reprocessed until it's finished
*
* It's up to the caller to check that the mob does not have a mutex set, before calling this proc
*/
/datum/controller/subsystem/mob_ai/proc/async_think(mob/mob_to_process)
var/datum/weakref/mob_weakref = WEAKREF(mob_to_process)
mutexes += mob_weakref
mob_to_process.think()
mutexes -= mob_weakref
/mob
var/thinking_enabled = FALSE
/**
* Perform AI logic for a mob, called by the AI subsystem
*
* For the love of god, *DO NOT* set a waitfor false or similar things here, this proc is under a mutex and if it returns before having done its work,
* it will mess things up!
*/
/mob/proc/think()
return
/mob/proc/on_think_disabled()
walk_to(src, 0)
QDEL_NULL(move_packet)
/mob/proc/on_think_enabled()
return
/datum/controller/subsystem/mob_ai/ExplosionStart()
can_fire = FALSE
/datum/controller/subsystem/mob_ai/ExplosionEnd()
can_fire = TRUE