Skip to content

Commit

Permalink
Merge pull request #3429 from MistakeNot4892/spawning
Browse files Browse the repository at this point in the history
Spawning tweaks.
  • Loading branch information
out-of-phaze authored Oct 29, 2023
2 parents cf1c573 + 57ece29 commit 41b4f62
Show file tree
Hide file tree
Showing 34 changed files with 259 additions and 175 deletions.
8 changes: 8 additions & 0 deletions code/__defines/spawn.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// Allows the spawn point to be used for observers spawning.
#define SPAWN_FLAG_GHOSTS_CAN_SPAWN BITFLAG(0)
/// Allows admin prison releases to use this spawn point.
#define SPAWN_FLAG_PRISONERS_CAN_SPAWN BITFLAG(1)
/// Allows general job latejoining to use this spawn point.
#define SPAWN_FLAG_JOBS_CAN_SPAWN BITFLAG(2)
/// Allows persistence decls (currently just bookcases) to use this spawn point.
#define SPAWN_FLAG_PERSISTENCE_CAN_SPAWN BITFLAG(3)
2 changes: 1 addition & 1 deletion code/controllers/subsystems/jobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ SUBSYSTEM_DEF(jobs)
H.forceMove(S.loc)
else
var/decl/spawnpoint/spawnpoint = job.get_spawnpoint(H.client)
H.forceMove(pick(spawnpoint.turfs))
H.forceMove(DEFAULTPICK(spawnpoint.get_spawn_turfs(H), get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN)))
spawnpoint.after_join(H)

// Moving wheelchair if they have one
Expand Down
16 changes: 16 additions & 0 deletions code/datums/repositories/decls.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ var/global/repository/decls/decls_repository = new
RETURN_TYPE(/decl)
. = get_decl(fetched_decl_ids[decl_id], validate_decl_type)

// This proc and get_decl_by_id_or_var() are being added solely to grandfather in decls saved to player saves under name
// rather than UID. They should be considered deprecated for this purpose - uid and get_decl_by_id() should be used instead.
/repository/decls/proc/get_decl_by_var(var/decl_value, var/decl_prototype, var/check_var = "name")
var/list/all_decls = get_decls_of_type(decl_prototype)
var/decl/prototype = all_decls[all_decls[1]] // Can't just grab the prototype as it may be abstract
if(!(check_var in prototype.vars))
CRASH("Attempted to retrieve a decl by a var that does not exist on the decl type ('[check_var]')")
for(var/decl_type in all_decls)
var/decl/decl = all_decls[decl_type]
if(decl.vars[check_var] == decl_value)
return decl

/repository/decls/proc/get_decl_by_id_or_var(var/decl_id, var/decl_prototype, var/check_var = "name")
RETURN_TYPE(/decl)
return get_decl_by_id(decl_id, validate_decl_type = FALSE) || get_decl_by_var(decl_id, decl_prototype, check_var)

/repository/decls/proc/get_decl_path_by_id(decl_id)
. = fetched_decl_ids[decl_id]

Expand Down
2 changes: 1 addition & 1 deletion code/game/jobs/job/_job.dm
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@
spawnpos = null
if(!spawnpos)
// Step through all spawnpoints and pick first appropriate for job
for(var/decl/spawnpoint/candidate as anything in global.using_map.allowed_spawns)
for(var/decl/spawnpoint/candidate as anything in global.using_map.allowed_latejoin_spawns)
if(candidate?.check_job_spawning(src))
spawnpos = candidate
break
Expand Down
22 changes: 4 additions & 18 deletions code/game/objects/effects/landmarks_latejoin.dm
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
var/global/list/latejoin_locations = list()
var/global/list/latejoin_cryo_locations = list()
var/global/list/latejoin_cyborg_locations = list()
var/global/list/latejoin_gateway_locations = list()

/obj/abstract/landmark/latejoin
delete_me = TRUE
var/spawn_decl = /decl/spawnpoint/arrivals

/obj/abstract/landmark/latejoin/Initialize()
add_loc()
if(spawn_decl)
var/decl/spawnpoint/spawn_instance = GET_DECL(spawn_decl)
spawn_instance.add_spawn_turf(get_turf(src))
. = ..()

/obj/abstract/landmark/latejoin/proc/add_loc()
global.latejoin_locations |= get_turf(src)

/obj/abstract/landmark/latejoin/gateway/add_loc()
global.latejoin_gateway_locations |= get_turf(src)

/obj/abstract/landmark/latejoin/cryo/add_loc()
global.latejoin_cryo_locations |= get_turf(src)

/obj/abstract/landmark/latejoin/cyborg/add_loc()
global.latejoin_cyborg_locations |= get_turf(src)
2 changes: 1 addition & 1 deletion code/modules/admin/admin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ var/global/floorIsLava = 0
set name = "Unprison"
if (isAdminLevel(M.z))
if (config.allow_admin_jump)
M.forceMove(pick(global.latejoin_locations))
M.forceMove(get_random_spawn_turf(SPAWN_FLAG_PRISONERS_CAN_SPAWN))
message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]", 1)
log_admin("[key_name(usr)] has unprisoned [key_name(M)]")
else
Expand Down
3 changes: 1 addition & 2 deletions code/modules/admin/verbs/randomverbs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
to_chat(usr, SPAN_WARNING("There is no active key like that in the game or the person is not currently a ghost."))
return

var/mob/living/carbon/human/new_character = new(pick(global.latejoin_locations))//The mob being spawned.

var/mob/living/carbon/human/new_character = new(get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN)) //The mob being spawned.
var/datum/computer_file/report/crew_record/record_found //Referenced to later to either randomize or not randomize the character.
if(G_found.mind && !G_found.mind.active)
record_found = get_crewmember_record(G_found.real_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
if(href_list["toggle_verbose_[token]"])
hidden[token] = !hidden[token]
return TOPIC_REFRESH

var/decl/cultural_info/new_token = href_list["set_token_entry_[token]"]
if(!isnull(new_token))
new_token = locate(new_token)
Expand Down
27 changes: 14 additions & 13 deletions code/modules/client/preference_setup/general/01_basic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,24 @@
pref.bodytype = R.read("bodytype")
pref.real_name = R.read("real_name")
pref.be_random_name = R.read("name_is_always_random")

pref.spawnpoint = R.read("spawnpoint")
for(var/decl/spawnpoint/spawnpoint as anything in global.using_map.allowed_spawns)
if(pref.spawnpoint == spawnpoint.name)
pref.spawnpoint = spawnpoint.type
break
if(!ispath(pref.spawnpoint, /decl/spawnpoint))
var/decl/spawnpoint/loaded_spawnpoint = decls_repository.get_decl_by_id_or_var(R.read("spawnpoint"), /decl/spawnpoint)
if(istype(loaded_spawnpoint) && (loaded_spawnpoint in global.using_map.allowed_latejoin_spawns))
pref.spawnpoint = loaded_spawnpoint.type
else
pref.spawnpoint = global.using_map.default_spawn

/datum/category_item/player_setup_item/physical/basic/save_character(datum/pref_record_writer/W)
W.write("gender", pref.gender)
W.write("bodytype", pref.bodytype)
W.write("real_name", pref.real_name)
W.write("name_is_always_random", pref.be_random_name)

var/decl/spawnpoint/spawnpoint = GET_DECL(pref.spawnpoint)
W.write("spawnpoint", spawnpoint.name)
W.write("spawnpoint", spawnpoint.uid)

/datum/category_item/player_setup_item/physical/basic/sanitize_character()

var/valid_spawn = FALSE
for(var/decl/spawnpoint/spawnpoint as anything in global.using_map.allowed_spawns)
for(var/decl/spawnpoint/spawnpoint as anything in global.using_map.allowed_latejoin_spawns)
if(pref.spawnpoint == spawnpoint.type)
valid_spawn = TRUE
break
Expand Down Expand Up @@ -93,8 +89,13 @@
else
. += "<a href='?src=\ref[src];gender=\ref[G]'>[G.pronoun_string]</a>"

. += "<br><b>Spawnpoint</b>:"
var/decl/spawnpoint/spawnpoint = GET_DECL(pref.spawnpoint)
. += "<br><b>Spawn point</b>: <a href='?src=\ref[src];spawnpoint=1'>[spawnpoint.name]</a>"
for(var/decl/spawnpoint/allowed_spawnpoint in global.using_map.allowed_latejoin_spawns)
if(spawnpoint == allowed_spawnpoint)
. += "<span class='linkOn'>[allowed_spawnpoint.name]</span>"
else
. += "<a href='?src=\ref[src];spawnpoint=\ref[allowed_spawnpoint]'>[allowed_spawnpoint.name]</a>"
. = jointext(.,null)

/datum/category_item/player_setup_item/physical/basic/OnTopic(var/href,var/list/href_list, var/mob/user)
Expand Down Expand Up @@ -146,8 +147,8 @@
return TOPIC_REFRESH_UPDATE_PREVIEW

else if(href_list["spawnpoint"])
var/decl/spawnpoint/choice = input(user, "Where would you like to spawn when late-joining?") as null|anything in global.using_map.allowed_spawns
if(!istype(choice) || !CanUseTopic(user))
var/decl/spawnpoint/choice = locate(href_list["spawnpoint"])
if(!istype(choice) || !CanUseTopic(user) || !(choice in global.using_map.allowed_latejoin_spawns))
return TOPIC_NOACTION
pref.spawnpoint = choice.type
return TOPIC_REFRESH
Expand Down
37 changes: 4 additions & 33 deletions code/modules/client/preference_setup/general/02_body.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,18 @@
pref.bgstate = R.read("bgstate")

// Get h_style type.
var/list/all_sprite_accessories
var/load_h_style = R.read("hair_style_name")
var/decl/h_style_decl = decls_repository.get_decl_by_id(load_h_style, validate_decl_type = FALSE)
// Grandfather in name-based sprite accessories.
if(!istype(h_style_decl) && load_h_style)
all_sprite_accessories = decls_repository.get_decls_of_subtype(/decl/sprite_accessory/hair)
for(var/accessory in all_sprite_accessories)
var/decl/sprite_accessory/sprite = all_sprite_accessories[accessory]
if(sprite.name == load_h_style)
h_style_decl = sprite
break
var/decl/h_style_decl = decls_repository.get_decl_by_id_or_var(R.read("hair_style_name"), /decl/sprite_accessory/hair)
pref.h_style = istype(h_style_decl) ? h_style_decl.type : /decl/sprite_accessory/hair/bald

// Get f_style type.
var/load_f_style = R.read("facial_style_name")
var/decl/f_style_decl = decls_repository.get_decl_by_id(load_f_style, validate_decl_type = FALSE)
// Grandfather in name-based accessories.
if(!istype(f_style_decl) && load_f_style)
all_sprite_accessories = decls_repository.get_decls_of_subtype(/decl/sprite_accessory/facial_hair)
for(var/accessory in all_sprite_accessories)
var/decl/sprite_accessory/sprite = all_sprite_accessories[accessory]
if(sprite.name == load_f_style)
f_style_decl = sprite
break
var/decl/f_style_decl = decls_repository.get_decl_by_id_or_var(R.read("facial_style_name"), /decl/sprite_accessory/facial_hair)
pref.f_style = istype(f_style_decl) ? f_style_decl.type : /decl/sprite_accessory/facial_hair/shaved

// Get markings type.
var/list/load_markings = R.read("body_markings")
pref.body_markings = list()
all_sprite_accessories = decls_repository.get_decls_of_subtype(/decl/sprite_accessory/marking)
if(length(load_markings))
for(var/marking in load_markings)
var/decl/sprite_accessory/marking/loaded_marking = decls_repository.get_decl_by_id(marking, validate_decl_type = FALSE)
// Grandfather in name-based accessories.
if(isnull(loaded_marking))
for(var/accessory in all_sprite_accessories)
var/decl/sprite_accessory/sprite = all_sprite_accessories[accessory]
if(sprite.name == marking)
loaded_marking = pref.body_markings[marking]
break
if(loaded_marking)
var/decl/sprite_accessory/marking/loaded_marking = decls_repository.get_decl_by_id_or_var(marking, /decl/sprite_accessory/marking)
if(istype(loaded_marking))
pref.body_markings[loaded_marking.type] = load_markings[marking]

/datum/category_item/player_setup_item/physical/body/save_character(datum/pref_record_writer/W)
Expand Down
91 changes: 65 additions & 26 deletions code/modules/client/preferences_spawnpoints.dm
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
/decl/spawnpoint
var/name // Name used in preference setup.
var/msg // Message to display on the arrivals computer.
var/list/turfs // List of turfs to spawn on.
// This proc will return a random valid respawn location, defaulting to
// observer spawn points if nothing else is available. Flags can be used to
// filter the spawnpoints considered valid, see code/__defines/spawn.dm.
/proc/get_random_spawn_turf(var/mob/spawning, var/check_flags)
var/list/spawn_locs = list()
var/list/all_spawns = decls_repository.get_decls_of_subtype(/decl/spawnpoint)
for(var/spawn_type in all_spawns)
var/decl/spawnpoint/spawn_data = all_spawns[spawn_type]
if((!check_flags || (spawn_data.spawn_flags & check_flags)))
var/add_spawn_turfs = spawn_data.get_spawn_turfs(spawning)
if(length(add_spawn_turfs))
spawn_locs |= add_spawn_turfs
. = SAFEPICK(spawn_locs)
if(!.)
// Observer spawn is guaranteed by CI to be populated.
var/decl/spawnpoint/observer_spawn = GET_DECL(/decl/spawnpoint/observer)
return pick(observer_spawn.get_spawn_turfs())

/decl/spawnpoint
abstract_type = /decl/spawnpoint
decl_flags = DECL_FLAG_MANDATORY_UID
/// Name displayed in preference setup.
var/name
/// Message to display on the arrivals computer. If null, no message will be sent.
var/spawn_announcement
/// Determines validity for get_random_spawn_turf()
var/spawn_flags = (SPAWN_FLAG_GHOSTS_CAN_SPAWN | SPAWN_FLAG_JOBS_CAN_SPAWN | SPAWN_FLAG_PRISONERS_CAN_SPAWN | SPAWN_FLAG_PERSISTENCE_CAN_SPAWN)
/// List of turfs to spawn on. Retrieved via get_spawn_turfs().
VAR_PRIVATE/list/_spawn_turfs
/// A list of job types that are allowed to use this spawnpoint.
var/list/restrict_job
/// A list of event categories that are allowed to use this spawnpoint (ex. ASSIGNMENT_JANITOR)
var/list/restrict_job_event_categories

/// A list of job types that are not allowed to use this spawnpoint.
var/list/disallow_job
/// A list of event categories that are not allowed to use this spawnpoint (ex. ASSIGNMENT_JANITOR)
var/list/disallow_job_event_categories

// Returns the spawn list. Mob is supplied in case overrides want to check prefs.
/decl/spawnpoint/proc/get_spawn_turfs(var/mob/spawning)
return _spawn_turfs

// Adds to the spawn list. Uses a proc for subtype overrides.
/decl/spawnpoint/proc/add_spawn_turf(var/turf/adding)
LAZYDISTINCTADD(_spawn_turfs, adding)

// Validates that a job is allowed to use this spawn point.
/decl/spawnpoint/proc/check_job_spawning(var/datum/job/job)

if(restrict_job && !(job.type in restrict_job) && !(job.title in restrict_job))
Expand All @@ -33,30 +69,31 @@
/decl/spawnpoint/proc/after_join(mob/victim)
return

/decl/spawnpoint/arrivals
name = "Arrivals"
msg = "has arrived on the station"

/decl/spawnpoint/arrivals/Initialize()
. = ..()
turfs = global.latejoin_locations
// Dummy spawnpoint for ghosts.
/decl/spawnpoint/observer
name = "Observer"
uid = "spawn_observer"
spawn_flags = SPAWN_FLAG_GHOSTS_CAN_SPAWN

/decl/spawnpoint/gateway
name = "Gateway"
msg = "has completed translation from offsite gateway"
/obj/abstract/landmark/latejoin/observer
spawn_decl = /decl/spawnpoint/observer

/decl/spawnpoint/gateway/Initialize()
. = ..()
turfs = global.latejoin_gateway_locations
// The 'default' latejoin spawn location.
/decl/spawnpoint/arrivals
name = "Arrivals"
spawn_announcement = "has arrived on the station"
uid = "spawn_arrivals"

// Spawn the mob inside a cryopod at the spawn loc.
/decl/spawnpoint/cryo
name = "Cryogenic Storage"
msg = "has completed cryogenic revival"
spawn_announcement = "has completed cryogenic revival"
disallow_job_event_categories = list(ASSIGNMENT_ROBOT)
uid = "spawn_cryo"
spawn_flags = (SPAWN_FLAG_GHOSTS_CAN_SPAWN | SPAWN_FLAG_JOBS_CAN_SPAWN)

/decl/spawnpoint/cryo/Initialize()
. = ..()
turfs = global.latejoin_cryo_locations
/obj/abstract/landmark/latejoin/cryo
spawn_decl = /decl/spawnpoint/cryo

/decl/spawnpoint/cryo/after_join(mob/living/carbon/human/victim)
if(!istype(victim) || victim.buckled) // They may have spawned with a wheelchair; don't move them into a pod in that case.
Expand All @@ -79,11 +116,13 @@
to_chat(victim,SPAN_NOTICE("You are slowly waking up from the cryostasis aboard [global.using_map.full_name]. It might take a few seconds."))
return

// Spawnpoint used specifically for robots.
/decl/spawnpoint/cyborg
name = "Robot Storage"
msg = "has been activated from storage"
spawn_announcement = "has been activated from storage"
restrict_job_event_categories = list(ASSIGNMENT_ROBOT)
spawn_flags = SPAWN_FLAG_JOBS_CAN_SPAWN
uid = "spawn_cyborg"

/decl/spawnpoint/cyborg/Initialize()
. = ..()
turfs = global.latejoin_cyborg_locations
/obj/abstract/landmark/latejoin/cyborg
spawn_decl = /decl/spawnpoint/cyborg
8 changes: 4 additions & 4 deletions code/modules/goals/definitions/department_clerical.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@

..()

/datum/goal/department/paperwork/proc/get_spawn_turfs()
/datum/goal/department/paperwork/proc/get_paper_spawn_turfs()
return

/datum/goal/department/paperwork/proc/get_end_areas()
/datum/goal/department/paperwork/proc/get_paper_end_areas()
return

/datum/goal/department/paperwork/try_initialize()

var/list/start_candidates = get_spawn_turfs()
var/list/start_candidates = get_paper_spawn_turfs()
if(!length(start_candidates))
PRINT_STACK_TRACE("Paperwork goal [type] initialized with no spawn landmarks mapped!")
SSgoals.pending_goals -= src
return FALSE

var/list/end_candidates = get_end_areas()
var/list/end_candidates = get_paper_end_areas()
if(!length(end_candidates))
PRINT_STACK_TRACE("Paperwork goal [type] initialized with no end landmarks mapped!")
SSgoals.pending_goals -= src
Expand Down
Loading

0 comments on commit 41b4f62

Please sign in to comment.