Basic mobs now use z-level turnoff instead of simple (#82469)

## About The Pull Request

On one compile of MetaStation, I saw that there's 45 basic mobs on the
station, 256 on lavaland (the number growing from tendrils), and 59 in
all other z levels combined.

While we do expect Lavaland to be visited every round, at least it won't
be running during the times when no one is there, but even more
importantly, space exploration is something not done every round, so we
don't have any reason to waste our resources on AIs that will never be
interacted with.

Simple animals had an easy solution to this:
If no one is on the Z level, their AI turns off
If someone is on the Z level, they are idle unless needed.

The last simple animals that exists right now are bots, megafauna,
geese, gondolas, and some minor ones like mimic, zombie, dark wizard,
soulscythe, etc.
Point is, we're very much nearly done going through all simple animals,
so this code is being wasted just to ensure things like cleanbots won't
work if no one is on the z level, something I doubt happens often, so I
took their code and made it work for basic mobs instead. I could've done
both but I thought it would look very bad, and maybe this is a good
incentivize to get more basic mob conversions.

There's one major change here and it's that we're missing the "Idle"
mode, some basic mobs like the Lavaland village seems to be made with
intent that they'll be running even if players aren't around, so this
sets up a future PR that makes idle AI easier to add, and I want to make
sure those cases are taken into account.

## Why It's Good For The Game

We don't need to always be processing these basic mobs, and sets us in
the future to hopefully also implement idle AIs.

## Changelog

🆑
balance: Basic mob AIs with no mobs on the Z level now stop.
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
John Willard
2024-04-06 15:17:53 -06:00
committed by GitHub
co-authored by san7890
parent 018a267b92
commit a15a1b88ed
21 changed files with 175 additions and 197 deletions
+29 -10
View File
@@ -3,27 +3,32 @@ SUBSYSTEM_DEF(ai_controllers)
name = "AI Controller Ticker"
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND
priority = FIRE_PRIORITY_NPC
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
init_order = INIT_ORDER_AI_CONTROLLERS
wait = 0.5 SECONDS //Plan every half second if required, not great not terrible.
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
///List of all ai_subtree singletons, key is the typepath while assigned value is a newly created instance of the typepath. See setup_subtrees()
var/list/ai_subtrees = list()
///List of all ai controllers currently running
var/list/active_ai_controllers = list()
var/list/datum/ai_planning_subtree/ai_subtrees = list()
///Assoc List of all AI statuses and all AI controllers with that status.
var/list/ai_controllers_by_status = list(
AI_STATUS_ON = list(),
AI_STATUS_OFF = list(),
)
///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off.
var/list/ai_controllers_by_zlevel = list()
/datum/controller/subsystem/ai_controllers/Initialize()
setup_subtrees()
return SS_INIT_SUCCESS
/datum/controller/subsystem/ai_controllers/proc/setup_subtrees()
ai_subtrees = list()
for(var/subtree_type in subtypesof(/datum/ai_planning_subtree))
var/datum/ai_planning_subtree/subtree = new subtree_type
ai_subtrees[subtree_type] = subtree
/datum/controller/subsystem/ai_controllers/stat_entry(msg)
var/list/active_list = ai_controllers_by_status[AI_STATUS_ON]
var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF]
msg = "Active AIs:[length(active_list)]|Inactive:[length(inactive_list)]"
return ..()
/datum/controller/subsystem/ai_controllers/fire(resumed)
for(var/datum/ai_controller/ai_controller as anything in active_ai_controllers)
for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON])
if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown))
continue
@@ -32,3 +37,17 @@ SUBSYSTEM_DEF(ai_controllers)
ai_controller.SelectBehaviors(wait * 0.1)
if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan
COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN)
///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list.
/datum/controller/subsystem/ai_controllers/proc/setup_subtrees()
for(var/subtree_type in subtypesof(/datum/ai_planning_subtree))
var/datum/ai_planning_subtree/subtree = new subtree_type
ai_subtrees[subtree_type] = subtree
///Called when the max Z level was changed, updating our coverage.
/datum/controller/subsystem/ai_controllers/proc/on_max_z_changed()
if (!islist(ai_controllers_by_zlevel))
ai_controllers_by_zlevel = new /list(world.maxz,0)
while (SSai_controllers.ai_controllers_by_zlevel.len < world.maxz)
SSai_controllers.ai_controllers_by_zlevel.len++
SSai_controllers.ai_controllers_by_zlevel[ai_controllers_by_zlevel.len] = list()
-47
View File
@@ -1,47 +0,0 @@
SUBSYSTEM_DEF(idlenpcpool)
name = "Idling NPC Pool"
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
priority = FIRE_PRIORITY_IDLE_NPC
wait = 60
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/currentrun = list()
var/static/list/idle_mobs_by_zlevel[][]
/datum/controller/subsystem/idlenpcpool/stat_entry(msg)
var/list/idlelist = GLOB.simple_animals[AI_IDLE]
var/list/zlist = GLOB.simple_animals[AI_Z_OFF]
msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]"
return ..()
/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged()
if (!islist(idle_mobs_by_zlevel))
idle_mobs_by_zlevel = new /list(world.maxz,0)
while (SSidlenpcpool.idle_mobs_by_zlevel.len < world.maxz)
SSidlenpcpool.idle_mobs_by_zlevel.len++
SSidlenpcpool.idle_mobs_by_zlevel[idle_mobs_by_zlevel.len] = list()
/datum/controller/subsystem/idlenpcpool/fire(resumed = FALSE)
if (!resumed)
var/list/idlelist = GLOB.simple_animals[AI_IDLE]
src.currentrun = idlelist.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
--currentrun.len
if (QDELETED(SA))
GLOB.simple_animals[AI_IDLE] -= SA
stack_trace("Found a null in simple_animals deactive list [SA.type]!")
continue
if(!SA.ckey)
if(SA.stat != DEAD)
SA.handle_automated_movement()
if(SA.stat != DEAD)
SA.consider_wakeup()
if (MC_TICK_CHECK)
return