Files
Wildkins 538fd914bb Lag War Day 5: Hard Dels and Status Displays (#21888)
- status displays no longer delete 50 overlays a second
- fauna spawners no longer cause carp harddels
- ammo piles and rocket launchers no longer cause harddels
2026-02-27 00:35:50 +00:00

232 lines
7.8 KiB
Plaintext

/obj/effect/fauna_spawner
name = "Mob spawner"
desc = "A mob spawner you're not supposed to see"
icon = 'icons/effects/map_effects.dmi'
icon_state = "ghostspawpoint"
anchored = 1
unacidable = 1
simulated = 0
invisibility = 101
var/first_spawn_done = FALSE // Keeping this false will make it so that it always spawns the first mob on the list first
var/spawning_enabled = FALSE
var/list/active_mobs = list()
var/max_active_mobs = 5
var/list/mob_choices = list() // List of mobs it'll spawn
/// Cooldown for spawning mobs. A value between min and max will be defined as seconds.
var/min_spawn_cooldown = 5
var/max_spawn_cooldown = 10
var/obj/effect/landmark/mob_waypoint/waypoint = null // The spawner automatically detects a waypoint on the same z-level, no need to set this manually
/obj/effect/fauna_spawner/Initialize()
. = ..()
var/obj/effect/landmark/mob_waypoint/W = locate(/obj/effect/landmark/mob_waypoint) in world
RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(mob_died))
if (W && W.z == src.z)
waypoint = W
if(!islist(GLOB.fauna_spawners))
GLOB.fauna_spawners = list()
GLOB.fauna_spawners |= src
return INITIALIZE_HINT_LATELOAD
/obj/effect/fauna_spawner/LateInitialize()
waypoint = LAZYACCESS(GLOB.mob_waypoints, z)
if(!istype(waypoint))
qdel(src)
/obj/effect/fauna_spawner/Destroy()
UnregisterSignal(GLOB, COMSIG_GLOB_MOB_DEATH, PROC_REF(mob_died))
for(var/mob/m in active_mobs)
UnregisterSignal(m, COMSIG_QDELETING)
active_mobs.Cut()
if(islist(GLOB.fauna_spawners))
GLOB.fauna_spawners -= src
return ..()
/obj/effect/fauna_spawner/proc/start_spawning()
if (spawning_enabled)
return
spawning_enabled = TRUE
spawn()
while (spawning_enabled && src)
for (var/i = length(active_mobs); i >= 1; i--)
var/mob/living/M = active_mobs[i]
if (!M || QDELETED(M) || M.stat == DEAD)
active_mobs.Cut(i, i+1)
if (length(active_mobs) < max_active_mobs)
spawn_mob()
sleep(rand(min_spawn_cooldown, max_spawn_cooldown) SECONDS)
/obj/effect/fauna_spawner/proc/spawn_mob()
if (!mob_choices || !length(mob_choices))
return
var/mob_type
var/move_speed = 5
var/choice
if (!first_spawn_done)
choice = mob_choices[1]
first_spawn_done = TRUE
else
choice = pick(mob_choices)
if (islist(choice))
mob_type = choice["type"]
move_speed = choice["speed"]
else
mob_type = choice
var/mob/living/new_mob = new mob_type(src.loc)
if (!new_mob)
return
active_mobs += new_mob
RegisterSignal(new_mob, COMSIG_QDELETING, PROC_REF(mob_died))
if (src.waypoint && istype(new_mob, /mob/living/simple_animal/hostile))
var/mob/living/simple_animal/hostile/H = new_mob
H.target_waypoint = src.waypoint
spawn()
if (isturf(src.waypoint.loc))
GLOB.move_manager.move_towards(H, src.waypoint.loc, move_speed, TRUE)
/obj/effect/fauna_spawner/proc/mob_died(var/mob/living/mob_ref, gibbed)
SIGNAL_HANDLER
UnregisterSignal(mob_ref, COMSIG_QDELETING)
for (var/i = length(active_mobs); i >= 1; i--)
var/mob/living/M = active_mobs[i]
if (!M || QDELETED(M) || M.stat == DEAD)
active_mobs.Cut(i, i+1)
if (mob_ref in active_mobs)
active_mobs -= mob_ref
/obj/effect/fauna_spawner/proc/stop_spawning()
spawning_enabled = FALSE
/proc/activate_fauna_spawners(var/z)
if(!islist(GLOB.fauna_spawners) || !length(GLOB.fauna_spawners))
return
for(var/obj/effect/fauna_spawner/S in GLOB.fauna_spawners)
if(S?.loc?.z == z)
S.start_spawning()
//Make your subtypes here
/obj/effect/fauna_spawner/phoron_deposit
name = "Phoron Deposit Spawner"
mob_choices = list(
list(type = /mob/living/simple_animal/hostile/carp/shark/reaver/eel/phoron_deposit, speed = 5), //Speed refers only to the speed that the mobs will move to the waypoint at. Lower values = faster
list(type = /mob/living/simple_animal/hostile/carp/shark/phoron_deposit, speed = 4),
list(type = /mob/living/simple_animal/hostile/carp/shark/reaver/phoron_deposit, speed = 5),
list(type = /mob/living/simple_animal/hostile/gnat/phoron_deposit, speed = 1),
list(type = /mob/living/simple_animal/hostile/carp, speed = 2)
)
/**
* Opposed to `fauna_spawner`, this spawner allows further customization and checks over spawned mobs, such as:
* * Having multiple spawn points, randomly chosen to spawn mobs.
* * Keeping track of total mob counts inside a single object.
*
* How does it work?
* * This type serves as a single spawner, it detects the spawn points in the same Z level and randomly chooses
*/
/obj/effect/fauna_spawner/organized
name = "Organized mob spawner"
desc = "You are not supposed to see this!"
icon_state = "master_spawner"
anchored = TRUE
unacidable = TRUE
simulated = FALSE
invisibility = 101
min_spawn_cooldown = 20
max_spawn_cooldown = 25
max_active_mobs = 15
/// Integer, fixed number of mobs that'll be spawned before spawner enters cooldown.
var/spawn_points_to_pick
/// The number range of mobs that can spawn before spawner enters cooldown. Ignored if 'spawn_points_to_pick' isn't null.
var/min_spawn = 2
var/max_spawn = 3
/// If true, object will avoid spawning multiple mobs on the same point.
var/one_spawn_per_point = FALSE
/obj/effect/fauna_spawner/organized/spawn_mob()
if (!mob_choices || !length(mob_choices))
return
var/obj/effect/landmark/organized_spawn_point/SP
var/list/available_points = GLOB.organized_spawn_points.Copy() // we make a copy so 'pick_n_take()' doesn't get rid of instances in global list
var/list/chosen_group = list()
if(LAZYLEN(available_points))
var/loop_amount
var/obj/effect/spawn_point
loop_amount = !spawn_points_to_pick ? rand(min_spawn, max_spawn) : spawn_points_to_pick // if no value is set we will randomly pick a number for each spawn time
for(var/i in 1 to loop_amount)
spawn_point = one_spawn_per_point ? pick_n_take(available_points) : pick(available_points)
if(spawn_point.z == src.z)
chosen_group += spawn_point
for(SP in chosen_group) //---- spawning mobs on chosen points
if(length(active_mobs) >= max_active_mobs) // double check if we exceeded the threshold
return
var/turf/T = get_turf(SP)
var/mob_type
var/move_speed = 5
var/choice
choice = pick(mob_choices)
if (islist(choice))
mob_type = choice["type"]
move_speed = choice["speed"]
else
mob_type = choice
var/mob/living/new_mob = new mob_type(T)
active_mobs += new_mob
RegisterSignal(new_mob, COMSIG_QDELETING, PROC_REF(mob_died))
if(src.waypoint && istype(new_mob, /mob/living/simple_animal/hostile))
var/mob/living/simple_animal/hostile/H = new_mob
H.target_waypoint = src.waypoint
INVOKE_ASYNC(src, PROC_REF(lead_the_mob), H, waypoint, move_speed)
/obj/effect/fauna_spawner/organized/proc/lead_the_mob(H, waypoint, move_speed)
if(isturf(src.waypoint.loc))
GLOB.move_manager.move_towards(H, src.waypoint.loc, move_speed, TRUE)
// ---- Put your subtypes here
/obj/effect/fauna_spawner/organized/quarantined_outpost
name = "Quarantined Outpost Spawner"
mob_choices = list(
list(type = /mob/living/simple_animal/hostile/revivable/husked_creature/quarantined_outpost/horde, speed = 5),
list(type = /mob/living/simple_animal/hostile/revivable/abomination/quarantined_outpost/horde, speed = 5)
)
one_spawn_per_point = TRUE
/obj/effect/landmark/organized_spawn_point
name = "spawn point"
icon = 'icons/effects/map_effects.dmi'
icon_state = "spawner_spawnpoint"
/obj/effect/landmark/organized_spawn_point/Initialize()
. = ..()
GLOB.organized_spawn_points += src
/obj/effect/landmark/organized_spawn_point/Destroy()
GLOB.organized_spawn_points -= src
return ..()
/obj/effect/landmark/mob_waypoint
name = "mob waypoint"
/obj/effect/landmark/mob_waypoint/Initialize(mapload)
. = ..()
var/list/z_levels = GetConnectedZlevels(z)
for(var/i in z_levels)
LAZYADDASSOCLIST(GLOB.mob_waypoints, "[i]", src)
/obj/effect/landmark/mob_waypoint/Destroy()
var/list/z_levels = GetConnectedZlevels(z)
for(var/i in z_levels)
LAZYREMOVEASSOC(GLOB.mob_waypoints, "[i]", src)
return ..()