[MIRROR] Adds two new helper procs for finding a maintenance/space spawn turf [MDB IGNORE] (#20536)

* Adds two new helper procs for finding a maintenance/space spawn turf (#74598)

## About The Pull Request

Adds two new global helper procs, find_maintenance_spawn and
find_space_spawn. These check the list of maintenance/space carp spawn
landmarks, and return the turf of a random one.

The find_maintenance_spawn helper has two arguments, for atmos safety
checks and making sure the spawn is properly shrouded in darkness.

This also includes some tidiness changes to the ghost_role event file,
because the helper was originally just going to be a proc on ghost role
events.

**Stuff moved to find_maintenance_spawn:**

- Spiders
- Nightmares
- Fugitives
- Paradox clones
- Morph

**Stuff moved to find_space_spawn:**

- Space Dragon
- Loneop
- Ninja
- Slaughter Demon
- Revenant backup spawn location

If we ignore all of the autodocing, this should remove about a dozen or
two lines of code.
## Why It's Good For The Game

Reduces an amount of duplicated code. Also makes future implementation a
bit easier and less copy-pastey.
## Changelog
🆑 Rhials
code: Adds two new super-duper helpful helper procs for finding a
maintenance/space spawn location, for all of your
event/midround/whatever needs!
code: Moves all midrounds/ghost_role events that hinged on
maintenance/space carp spawns to the aforementioned helpers.
code: The ghost_role event module file is now autodoced.
/🆑

* Adds two new helper procs for finding a maintenance/space spawn turf

---------

Co-authored-by: Rhials <Datguy33456@gmail.com>
This commit is contained in:
SkyratBot
2023-04-14 14:25:16 +01:00
committed by GitHub
co-authored by Rhials
parent a40759ad1b
commit abefbb0d64
13 changed files with 129 additions and 106 deletions
+52
View File
@@ -0,0 +1,52 @@
#define UNLIT_AREA_BRIGHTNESS 0.2
/**
* Finds us a generic maintenance spawn location.
*
* Goes through the list of the generic mainteance landmark locations, checking for atmos safety if required, and returns
* a valid turf. Returns MAP_ERROR if no valid locations are present.
* Returns nothing and alerts admins if no valid points are found. Keep this in mind
* when using this helper.
*/
/proc/find_maintenance_spawn(atmos_sensitive = FALSE, require_darkness = FALSE)
var/list/possible_spawns = list()
for(var/spawn_location in GLOB.generic_maintenance_landmarks)
var/turf/spawn_turf = get_turf(spawn_location)
if(atmos_sensitive && !is_safe_turf(spawn_turf))
continue
if(require_darkness && spawn_turf.get_lumcount() > UNLIT_AREA_BRIGHTNESS)
continue
possible_spawns += spawn_turf
if(!length(possible_spawns))
message_admins("No valid generic_maintenance_landmark landmarks found, aborting...")
return null
return pick(possible_spawns)
/**
* Finds us a generic spawn location in space.
*
* Goes through the list of the space carp spawn locations, picks from the list, and
* returns that turf. Returns MAP_ERROR if no landmarks are found.
*/
/proc/find_space_spawn()
var/list/possible_spawns = list()
for(var/obj/effect/landmark/carpspawn/spawn_location in GLOB.landmarks_list)
if(!isturf(spawn_location.loc))
stack_trace("Carp spawn found not on a turf: [spawn_location.type] on [isnull(spawn_location.loc) ? "null" : spawn_location.loc.type]")
continue
possible_spawns += get_turf(spawn_location)
if(!length(possible_spawns))
message_admins("No valid carpspawn landmarks found, aborting...")
return null
return pick(possible_spawns)
#undef UNLIT_AREA_BRIGHTNESS
@@ -525,14 +525,10 @@
var/list/spawn_locs = list()
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/acceptable(population=0, threat=0)
for(var/X in GLOB.generic_maintenance_landmarks)
var/turf/T = X
var/light_amount = T.get_lumcount()
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
spawn_locs += T
if(!spawn_locs.len)
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE) //Checks if there's a single safe, dark tile on station.
if(!spawn_loc)
return FALSE
. = ..()
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant)
var/datum/mind/player_mind = new /datum/mind(applicant.key)
@@ -863,11 +859,8 @@
var/list/possible_spawns = list() ///places the antag can spawn
/datum/dynamic_ruleset/midround/from_ghosts/paradox_clone/execute()
for(var/turf/warp_point in GLOB.generic_maintenance_landmarks)
if(istype(warp_point.loc, /area/station/maintenance) && is_safe_turf(warp_point))
possible_spawns += warp_point
possible_spawns += find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE)
if(!possible_spawns.len)
message_admins("No valid spawn locations found for Paradox Clone event, aborting...")
return MAP_ERROR
return ..()
+43 -16
View File
@@ -2,19 +2,31 @@
/datum/round_event/ghost_role
// We expect 0 or more /clients (or things with .key) in this list
var/list/priority_candidates = list()
var/minimum_required = 1
var/role_name = "debug rat with cancer" // Q U A L I T Y M E M E S
var/list/spawned_mobs = list()
var/status
var/cached_announcement_chance
fakeable = FALSE
/// Members of this list will be placed at the front of the candicacy list, in front of the (shuffled) normal candidates.
var/list/priority_candidates = list() //expected to contain 0 or more /clients (or things with .key)
/// The minimum number of signups required for the event to continue past the polling period
var/minimum_required = 1
/// The name of the role, to be displayed in logs/polls/etc.
var/role_name = "debug rat with cancer" // Q U A L I T Y M E M E S
/// A list of mobs generated by this event.
var/list/spawned_mobs = list()
/// Used to communicate the progress of the event firing, and whether or not the event was successfuly run.
var/status
/// A stored value of the event's announcement chance. Cached and not immediately used to prevent announcements for a failed event roll.
var/cached_announcement_chance
/datum/round_event/ghost_role/start()
try_spawning()
/datum/round_event/ghost_role/proc/try_spawning(sanity = 0, retry = 0)
/**
* Attempts to spawn the role, and cancels the event if it fails.
*
* Pauses the event right as it begins, and waits for setup/polling to end.
* If successful, continues running the rest of the event and notifies ghosts.
*/
/datum/round_event/ghost_role/proc/try_spawning()
// The event does not run until the spawning has been attempted
// to prevent us from getting gc'd halfway through
processing = FALSE
@@ -24,15 +36,16 @@
cached_announcement_chance = announce_chance //only announce once we've finished the spawning loop.
announce_chance = (status == SUCCESSFUL_SPAWN ? cached_announcement_chance : 0)
if((status == WAITING_FOR_SOMETHING))
if(retry >= MAX_SPAWN_ATTEMPT)
var/retry_count = 0
if(retry_count >= MAX_SPAWN_ATTEMPT)
message_admins("[role_name] event has exceeded maximum spawn attempts. Aborting and refunding.")
if(control && control.occurrences > 0) //Don't refund if it hasn't
control.occurrences--
return
var/waittime = 300 * (2**retry)
var/waittime = 300 * (2**retry_count)
message_admins("The event will not spawn a [role_name] until certain \
conditions are met. Waiting [waittime/10]s and then retrying.")
addtimer(CALLBACK(src, PROC_REF(try_spawning), 0, ++retry), waittime)
addtimer(CALLBACK(src, PROC_REF(try_spawning), 0, ++retry_count), waittime)
return
if(!status)
@@ -60,15 +73,29 @@
processing = TRUE
/**
* Performs the spawning of our role. Entirely specific to the event itself.
*
* Should return SUCCESSFUL_SPAWN if role was successfully spawned,
* return NOT_ENOUGH_PLAYERS if less than mimimum_required was found,
* and return MAP_ERROR if a spawn location could not be found.
*/
/datum/round_event/ghost_role/proc/spawn_role()
// Return true if role was successfully spawned, false if insufficent
// players could be found, and just runtime if anything else happens
return FALSE
/**
* Gathers the candidates to select our ghost roles from.
*
* Returns a list of candidates in priority order, with candidates from
* `priority_candidates` first, and ghost roles randomly shuffled and
* appended after.
*
* jobban - The jobban flag to exclude players from the polling pool with.
* be_special - The "special role" flag for the ghost candidacy poll.
*/
/datum/round_event/ghost_role/proc/get_candidates(jobban, be_special)
// Returns a list of candidates in priority order, with candidates from
// `priority_candidates` first, and ghost roles randomly shuffled and
// appended after
var/list/mob/dead/observer/regular_candidates
// don't get their hopes up
if(priority_candidates.len < minimum_required)
@@ -16,14 +16,9 @@
fakeable = FALSE
/datum/round_event/ghost_role/fugitives/spawn_role()
var/list/possible_spawns = list()//Some xeno spawns are in some spots that will instantly kill the refugees, like atmos
for(var/turf/spawn_turf in GLOB.generic_maintenance_landmarks)
if(istype(get_area(spawn_turf), /area/station/maintenance) && is_safe_turf(spawn_turf))
possible_spawns += spawn_turf
if(!possible_spawns.len)
message_admins("No valid spawn locations found, aborting...")
var/turf/landing_turf = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE)
if(isnull(landing_turf))
return MAP_ERROR
var/turf/landing_turf = pick(possible_spawns)
var/list/possible_backstories = list()
var/list/candidates = get_candidates(ROLE_FUGITIVE, ROLE_FUGITIVE)
@@ -22,17 +22,11 @@
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = TRUE
var/list/spawn_locs = list()
for(var/spawn_area in GLOB.generic_maintenance_landmarks)
var/turf/spawn_turf = get_turf(spawn_area)
if(is_safe_turf(spawn_turf))
spawn_locs += spawn_turf
if(!length(spawn_locs))
message_admins("No valid spawn locations found, aborting...")
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE)
if(isnull(spawn_loc))
return MAP_ERROR
var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(spawn_locs))
var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(spawn_loc)
player_mind.transfer_to(S)
player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/morph))
player_mind.special_role = ROLE_MORPH
+3 -10
View File
@@ -24,18 +24,11 @@
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = TRUE
var/list/spawn_locs = list()
for(var/spawn_area in GLOB.generic_maintenance_landmarks)
var/turf/spawn_turf = get_turf(spawn_area)
var/light_amount = spawn_turf.get_lumcount()
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD && is_safe_turf(spawn_turf))
spawn_locs += spawn_turf
if(!spawn_locs.len)
message_admins("No valid spawn locations found, aborting...")
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE)
if(isnull(spawn_loc))
return MAP_ERROR
var/mob/living/carbon/human/S = new ((pick(spawn_locs)))
var/mob/living/carbon/human/S = new (spawn_loc)
player_mind.transfer_to(S)
player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nightmare))
player_mind.special_role = ROLE_NIGHTMARE
+3 -5
View File
@@ -18,13 +18,11 @@
var/mob/dead/selected = pick_n_take(candidates)
var/list/spawn_locs = list()
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
spawn_locs += L.loc
if(!spawn_locs.len)
var/spawn_location = find_space_spawn()
if(isnull(spawn_location))
return MAP_ERROR
var/mob/living/carbon/human/operative = new(pick(spawn_locs))
var/mob/living/carbon/human/operative = new(spawn_location)
operative.randomize_human_appearance(~RANDOMIZE_SPECIES)
operative.dna.update_dna_identity()
var/datum/mind/Mind = new /datum/mind(selected.key)
@@ -48,9 +48,7 @@
if(T && is_station_level(T.z))
spawn_locs += T
if(!spawn_locs.len) //If we can't find any valid spawnpoints, try the carp spawns
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
spawn_locs += find_space_spawn()
if(!spawn_locs.len) //If we can't find either, just spawn the revenant at the player's location
spawn_locs += get_turf(selected)
if(!spawn_locs.len) //If we can't find THAT, then just give up and cry
@@ -25,18 +25,11 @@
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = TRUE
var/list/spawn_locs = list()
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
if(!spawn_locs)
message_admins("No valid spawn locations found, aborting...")
return MAP_ERROR
var/turf/chosen = pick(spawn_locs)
var/mob/living/simple_animal/hostile/imp/slaughter/S = new(chosen)
new /obj/effect/dummy/phased_mob(chosen, S)
var/spawn_location = find_space_spawn()
if(!spawn_location)
return MAP_ERROR //This sends an error message further up.
var/mob/living/simple_animal/hostile/imp/slaughter/S = new(spawn_location)
new /obj/effect/dummy/phased_mob(spawn_location, S)
player_mind.transfer_to(S)
player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/slaughter_demon))
+5 -10
View File
@@ -19,15 +19,6 @@
priority_announce("A large organic energy flux has been recorded near [station_name()], please stand by.", "Lifesign Alert")
/datum/round_event/ghost_role/space_dragon/spawn_role()
var/list/spawn_locs = list()
for(var/obj/effect/landmark/carpspawn/carp_spawn in GLOB.landmarks_list)
if(!isturf(carp_spawn.loc))
stack_trace("Carp spawn found not on a turf: [carp_spawn.type] on [isnull(carp_spawn.loc) ? "null" : carp_spawn.loc.type]")
continue
spawn_locs += carp_spawn.loc
if(!spawn_locs.len)
message_admins("No valid spawn locations found, aborting...")
return MAP_ERROR
var/list/candidates = get_candidates(ROLE_SPACE_DRAGON, ROLE_SPACE_DRAGON)
if(!candidates.len)
@@ -36,7 +27,11 @@
var/mob/dead/selected = pick(candidates)
var/key = selected.key
var/mob/living/simple_animal/hostile/space_dragon/dragon = new (pick(spawn_locs))
var/spawn_location = find_space_spawn()
if(isnull(spawn_location))
return MAP_ERROR
var/mob/living/simple_animal/hostile/space_dragon/dragon = new (spawn_location)
dragon.key = key
dragon.mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon))
dragon.mind.special_role = ROLE_SPACE_DRAGON
@@ -14,14 +14,8 @@
role_name = "Space Ninja"
/datum/round_event/ghost_role/space_ninja/spawn_role()
var/list/spawn_locs = list()
for(var/obj/effect/landmark/carpspawn/carp_spawn in GLOB.landmarks_list)
if(!isturf(carp_spawn.loc))
stack_trace("Carp spawn found not on a turf: [carp_spawn.type] on [isnull(carp_spawn.loc) ? "null" : carp_spawn.loc.type]")
continue
spawn_locs += carp_spawn.loc
if(!spawn_locs.len)
message_admins("No valid spawn locations found, aborting...")
var/spawn_location = find_space_spawn()
if(isnull(spawn_location))
return MAP_ERROR
//selecting a candidate player
@@ -33,7 +27,7 @@
var/key = selected_candidate.key
//spawn the ninja and assign the candidate
var/mob/living/carbon/human/ninja = create_space_ninja(pick(spawn_locs))
var/mob/living/carbon/human/ninja = create_space_ninja(spawn_location)
ninja.key = key
ninja.mind.add_antag_datum(/datum/antagonist/ninja)
spawned_mobs += ninja
+4 -14
View File
@@ -24,21 +24,11 @@
create_midwife_eggs(spawncount)
/proc/create_midwife_eggs(amount)
var/list/spawn_locs = list()
for(var/x in GLOB.generic_maintenance_landmarks)
var/turf/spawn_turf = x
var/light_amount = spawn_turf.get_lumcount()
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD && is_safe_turf(spawn_turf))
spawn_locs += spawn_turf
if(!length(spawn_locs))
message_admins("No valid spawn locations found in GLOB.generic_maintenance_landmarks, aborting spider spawning...")
return MAP_ERROR
while(amount > 0)
var/turf/spawn_loc = pick_n_take(spawn_locs)
if(!spawn_loc)
message_admins("Midwife egg creation ran out of locations to spawn at. Terminating egg spawn with [amount] spawns remaining.")
break
var/obj/effect/mob_spawn/ghost_role/spider/midwife/new_eggs = new /obj/effect/mob_spawn/ghost_role/spider/midwife(spawn_loc)
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE)
if(isnull(spawn_loc))
return //Admins will have already been notified of the spawning failure at this point
var/obj/effect/mob_spawn/ghost_role/spider/midwife/new_eggs = new (spawn_loc)
new_eggs.amount_grown = 98
amount--
log_game("Midwife spider eggs were spawned via an event.")
+1
View File
@@ -436,6 +436,7 @@
#include "code\__HELPERS\dna.dm"
#include "code\__HELPERS\duplicating.dm"
#include "code\__HELPERS\dynamic_human_icon_gen.dm"
#include "code\__HELPERS\events.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\filters.dm"
#include "code\__HELPERS\forensics.dm"