mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-04 14:01:22 +00:00
## About The Pull Request At some point we added a new parameter to spawners which randomised the number of mobs they could spawn up to a maximum. For some reason the default value here was set to "2", meaning that every mob spawner in the game would be spawning an average of 1.5 mobs per update instead of 1. As the place it was _intended_ for (mining vents) already provides a value in the constructor, I just set the default back to 1. Additionally, this randomised value did not actually obey the "maximum mobs" parameter of the component and could spawn mobs above what was supposed to be the cap of mobs created by the spawner. This PR fixes those things. ## Changelog 🆑 fix: Mob spawners (such as lavaland tendrils) won't spawn more mobs than they are supposed to, faster than they should. /🆑
122 lines
4.4 KiB
Plaintext
122 lines
4.4 KiB
Plaintext
/datum/component/spawner
|
|
/// Time to wait between spawns
|
|
var/spawn_time
|
|
/// Maximum number of atoms we can have active at one time
|
|
var/max_spawned
|
|
/// Visible message to show when something spawns
|
|
var/spawn_text
|
|
/// List of atom types to spawn, picked randomly
|
|
var/list/spawn_types
|
|
/// Faction to grant to mobs (only applies to mobs)
|
|
var/list/faction
|
|
/// List of weak references to things we have already created
|
|
var/list/spawned_things = list()
|
|
/// How many mobs can we spawn maximum each time we try to spawn? (1 - max)
|
|
var/max_spawn_per_attempt
|
|
/// Distance from the spawner to spawn mobs
|
|
var/spawn_distance
|
|
/// Distance from the spawner to exclude mobs from spawning
|
|
var/spawn_distance_exclude
|
|
COOLDOWN_DECLARE(spawn_delay)
|
|
|
|
/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 1 , faction = list(FACTION_MINING), spawn_text = null, spawn_distance = 1, spawn_distance_exclude = 0)
|
|
if (!islist(spawn_types))
|
|
CRASH("invalid spawn_types to spawn specified for spawner component!")
|
|
src.spawn_time = spawn_time
|
|
src.spawn_types = spawn_types
|
|
src.faction = faction
|
|
src.spawn_text = spawn_text
|
|
src.max_spawned = max_spawned
|
|
src.max_spawn_per_attempt = max_spawn_per_attempt
|
|
src.spawn_distance = spawn_distance
|
|
src.spawn_distance_exclude = spawn_distance_exclude
|
|
|
|
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(stop_spawning))
|
|
RegisterSignal(parent, COMSIG_VENT_WAVE_CONCLUDED, PROC_REF(stop_spawning))
|
|
START_PROCESSING((spawn_time < 2 SECONDS ? SSfastprocess : SSprocessing), src)
|
|
|
|
/datum/component/spawner/process()
|
|
try_spawn_mob()
|
|
|
|
/// Stop spawning mobs
|
|
/datum/component/spawner/proc/stop_spawning(force)
|
|
SIGNAL_HANDLER
|
|
|
|
STOP_PROCESSING(SSprocessing, src)
|
|
spawned_things = list()
|
|
|
|
/// Try to create a new mob
|
|
/datum/component/spawner/proc/try_spawn_mob()
|
|
if(!length(spawn_types))
|
|
return
|
|
if(!COOLDOWN_FINISHED(src, spawn_delay))
|
|
return
|
|
validate_references()
|
|
var/spawned_total = length(spawned_things)
|
|
if(spawned_total >= max_spawned)
|
|
return
|
|
var/atom/spawner = parent
|
|
COOLDOWN_START(src, spawn_delay, spawn_time)
|
|
var/chosen_mob_type = pick(spawn_types)
|
|
var/adjusted_spawn_count = 1
|
|
var/max_spawn_this_attempt = min(max_spawn_per_attempt, max_spawned - spawned_total)
|
|
if (max_spawn_this_attempt > 1)
|
|
adjusted_spawn_count = rand(1, max_spawn_this_attempt)
|
|
for(var/i in 1 to adjusted_spawn_count)
|
|
var/atom/created
|
|
var/turf/picked_spot
|
|
|
|
if(spawn_distance == 1)
|
|
created = new chosen_mob_type(spawner.loc)
|
|
else if(spawn_distance >= 1 && spawn_distance_exclude >= 1)
|
|
picked_spot = pick(turf_peel(spawn_distance, spawn_distance_exclude, spawner.loc, view_based = TRUE))
|
|
if(!picked_spot)
|
|
picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance))
|
|
created = new chosen_mob_type(picked_spot)
|
|
else if (spawn_distance >= 1)
|
|
picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance))
|
|
created = new chosen_mob_type(picked_spot)
|
|
|
|
created.flags_1 |= (spawner.flags_1 & ADMIN_SPAWNED_1)
|
|
spawned_things += WEAKREF(created)
|
|
|
|
if (isliving(created))
|
|
var/mob/living/created_mob = created
|
|
created_mob.faction = src.faction
|
|
RegisterSignal(created, COMSIG_MOB_STATCHANGE, PROC_REF(mob_stat_changed))
|
|
|
|
SEND_SIGNAL(src, COMSIG_SPAWNER_SPAWNED, created)
|
|
RegisterSignal(created, COMSIG_QDELETING, PROC_REF(on_deleted))
|
|
|
|
|
|
if (spawn_text)
|
|
spawner.visible_message(span_danger("A creature [spawn_text] [spawner]."))
|
|
|
|
|
|
|
|
/// Remove weakrefs to atoms which have been killed or deleted without us picking it up somehow
|
|
/datum/component/spawner/proc/validate_references()
|
|
for (var/datum/weakref/weak_thing as anything in spawned_things)
|
|
var/atom/previously_spawned = weak_thing?.resolve()
|
|
if (!previously_spawned)
|
|
spawned_things -= weak_thing
|
|
continue
|
|
if (!isliving(previously_spawned))
|
|
continue
|
|
var/mob/living/spawned_mob = previously_spawned
|
|
if (spawned_mob.stat != DEAD)
|
|
continue
|
|
spawned_things -= weak_thing
|
|
|
|
/// Called when an atom we spawned is deleted, remove it from the list
|
|
/datum/component/spawner/proc/on_deleted(atom/source)
|
|
SIGNAL_HANDLER
|
|
spawned_things -= 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_things -= WEAKREF(source)
|
|
UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_MOB_STATCHANGE))
|