From ca0e0983c7eafedb36929f435cc4d3a5a4672464 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 10 Mar 2023 07:08:35 +0100 Subject: [PATCH] [MIRROR] Refactor mob spawner component so that it is independent [MDB IGNORE] (#19560) Refactor mob spawner component so that it is independent Co-authored-by: Jacquerel Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> --- code/datums/components/spawner.dm | 71 +++++++++++++------ .../hostile/megafauna/_megafauna.dm | 9 --- .../hostile/mining_mobs/hivelord.dm | 9 ++- .../mob/living/simple_animal/simple_animal.dm | 9 --- 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index 9f9bb3eb74d..951aa95b17a 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -1,11 +1,18 @@ /datum/component/spawner - var/mob_types = list(/mob/living/basic/carp) - var/spawn_time = 300 //30 seconds default + /// Time to wait between spawns + var/spawn_time + /// Maximum number of mobs we can have active at one time + var/max_mobs + /// Visible message to show when a mob spawns + var/spawn_text + /// List of mob types to spawn, picked randomly + var/list/mob_types + /// Faction to grant to mobs + var/list/faction + /// List of weak references to mobs we have already created var/list/spawned_mobs = list() - var/spawn_delay = 0 - var/max_mobs = 5 - var/spawn_text = "emerges from" - var/list/faction = list("mining") + /// Time until we next spawn + COOLDOWN_DECLARE(spawn_delay) /datum/component/spawner/Initialize(mob_types = list(), spawn_time = 30 SECONDS, max_mobs = 5, faction = list(FACTION_MINING), spawn_text = "emerges from") if (!length(mob_types)) @@ -22,27 +29,49 @@ /datum/component/spawner/process() try_spawn_mob() - +/// Stop spawning mobs /datum/component/spawner/proc/stop_spawning(force) SIGNAL_HANDLER STOP_PROCESSING(SSprocessing, src) - for(var/mob/living/simple_animal/L in spawned_mobs) - if(L.nest == src) - L.nest = null - spawned_mobs = null + spawned_mobs = list() +/// Try to create a new mob /datum/component/spawner/proc/try_spawn_mob() - var/atom/P = parent - if(spawned_mobs.len >= max_mobs) + if(!COOLDOWN_FINISHED(src, spawn_delay)) return - if(spawn_delay > world.time) + validate_references() + if(length(spawned_mobs) >= max_mobs) return - spawn_delay = world.time + spawn_time + var/atom/spawner = parent + COOLDOWN_START(src, spawn_delay, spawn_time) + var/chosen_mob_type = pick(mob_types) - var/mob/living/simple_animal/L = new chosen_mob_type(P.loc) - L.flags_1 |= (P.flags_1 & ADMIN_SPAWNED_1) - spawned_mobs += L - L.nest = src - L.faction = src.faction - P.visible_message(span_danger("[L] [spawn_text] [P].")) + var/mob/living/created = new chosen_mob_type(spawner.loc) + created.flags_1 |= (spawner.flags_1 & ADMIN_SPAWNED_1) + spawned_mobs += WEAKREF(created) + created.faction = src.faction + spawner.visible_message(span_danger("[created] [spawn_text] [spawner].")) + + RegisterSignal(created, COMSIG_PARENT_QDELETING, PROC_REF(mob_deleted)) + RegisterSignal(created, COMSIG_MOB_STATCHANGE, PROC_REF(mob_stat_changed)) + +/// Remove weakrefs to mobs which have been killed or deleted without us picking it up somehow +/datum/component/spawner/proc/validate_references() + for (var/datum/weakref/weak_mob as anything in spawned_mobs) + var/mob/living/previously_spawned = weak_mob.resolve() + if (previously_spawned && previously_spawned.stat != DEAD) + continue + spawned_mobs -= weak_mob + +/// Called when a mob we spawned is deleted, remove it from the list +/datum/component/spawner/proc/mob_deleted(mob/living/source) + SIGNAL_HANDLER + spawned_mobs -= WEAKREF(source) + +/// Called when a mob we spawned dies, remove it from the list and unregister signals +/datum/component/spawner/proc/mob_stat_changed(mob/living/source) + if (source.stat != DEAD) + return + spawned_mobs -= WEAKREF(source) + UnregisterSignal(source, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_STATCHANGE)) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index c9455fdbea7..68d2de73bc2 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -46,8 +46,6 @@ var/recovery_time = 0 /// If this is a megafauna that is real (has achievements, gps signal) var/true_spawn = TRUE - /// Range the megafauna can move from their nest (if they have one - var/nest_range = 10 /// The chosen attack by the megafauna var/chosen_attack = 1 /// Attack actions, sets chosen_attack to the number in the action @@ -74,13 +72,6 @@ //Safety check if(!loc) return ..() - if(nest && nest.parent && get_dist(nest.parent, src) > nest_range) - var/turf/closest = get_turf(nest.parent) - for(var/i = 1 to nest_range) - closest = get_step(closest, get_dir(closest, src)) - forceMove(closest) // someone teleported out probably and the megafauna kept chasing them - LoseTarget() - return return ..() /mob/living/simple_animal/hostile/megafauna/death(gibbed, list/force_grant) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index 1e0f4c65b7d..9999747601a 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -282,7 +282,14 @@ /mob/living/simple_animal/hostile/big_legion/Initialize(mapload) .=..() - AddComponent(/datum/component/spawner, list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion), 200, faction, "peels itself off from", 3) + AddComponent(\ + /datum/component/spawner,\ + mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion),\ + spawn_time = 20 SECONDS,\ + max_mobs = 3,\ + spawn_text = "peels itself off from",\ + faction = faction,\ + ) // Snow Legion diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 5676c6e960d..10dabd378eb 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -123,8 +123,6 @@ ///If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood. var/gold_core_spawnable = NO_SPAWN - var/datum/component/spawner/nest - ///Sentience type, for slime potions. var/sentience_type = SENTIENCE_ORGANIC @@ -221,10 +219,6 @@ GLOB.simple_animals[AIStatus] -= src SSnpcpool.currentrun -= src - if(nest) - nest.spawned_mobs -= src - nest = null - var/turf/T = get_turf(src) if (T && AIStatus == AI_Z_OFF) SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src @@ -455,9 +449,6 @@ new i(loc) /mob/living/simple_animal/death(gibbed) - if(nest) - nest.spawned_mobs -= src - nest = null drop_loot() if(dextrous) drop_all_held_items()