Skip to content

Commit 4d84314

Browse files
authored
Refactors jobspawning (#1180)
* jobspawn code * cleanup SendToLatejoin * ai qol * fix * removes all but the clown and cyborg landmarks * forgot 1 commit
1 parent 867c5e2 commit 4d84314

File tree

10 files changed

+133
-285
lines changed

10 files changed

+133
-285
lines changed

_maps/map_files/Theseus/Theseus.dmm

+31-233
Large diffs are not rendered by default.

code/__DEFINES/jobs.dm

+7
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,10 @@
139139

140140
#define FACTION_NONE "None"
141141
#define FACTION_STATION "Station"
142+
143+
/// Spawn point is always fixed.
144+
#define JOBSPAWN_FORCE_FIXED 0
145+
/// Spawn point prefers a fixed spawnpoint, but can be a latejoin one.
146+
#define JOBSPAWN_ALLOW_RANDOM 1
147+
/// Spawn point is always a random spawnpoint.
148+
#define JOBSPAWN_FORCE_RANDOM 2

code/controllers/subsystem/job.dm

+5-3
Original file line numberDiff line numberDiff line change
@@ -758,21 +758,23 @@ SUBSYSTEM_DEF(job)
758758
if(buckle && isliving(joining_mob))
759759
buckle_mob(joining_mob, FALSE, FALSE)
760760

761+
/// Send an existing mob to their latejoin spawnpoint. Returns FALSE if it couldn't find a proper one, and resorted to the last resort.
761762
/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE)
762763
var/atom/destination
763764

764-
if(M.mind && !is_unassigned_job(M.mind.assigned_role) && length(GLOB.high_priority_spawns)) //We're doing something special today.
765-
destination = pick(GLOB.high_priority_spawns[M.mind.assigned_role.title])
765+
if(M.mind?.assigned_role && !is_unassigned_job(M.mind.assigned_role)) //We're doing something special today.
766+
destination = M.mind.assigned_role.get_latejoin_spawn_point()
766767
destination.JoinPlayerHere(M, FALSE)
767768
return TRUE
768769

769-
if(latejoin_trackers.len)
770+
if(length(latejoin_trackers))
770771
destination = pick(latejoin_trackers)
771772
destination.JoinPlayerHere(M, buckle)
772773
return TRUE
773774

774775
destination = get_last_resort_spawn_points()
775776
destination.JoinPlayerHere(M, buckle)
777+
return FALSE
776778

777779

778780
/datum/controller/subsystem/job/proc/get_last_resort_spawn_points()

code/controllers/subsystem/ticker.dm

+11-10
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,6 @@ SUBSYSTEM_DEF(ticker)
357357
qdel(bomb)
358358

359359
/datum/controller/subsystem/ticker/proc/create_characters()
360-
var/list/spawn_spots = SSjob.latejoin_trackers.Copy()
361-
var/list/spawn_spots_reload = spawn_spots.Copy() //In case we run out, we need something to reload from.
362360
for(var/mob/dead/new_player/player as anything in GLOB.new_player_list)
363361
if(!player.mind)
364362
//New player has logged out.
@@ -371,21 +369,24 @@ SUBSYSTEM_DEF(ticker)
371369
if(PLAYER_READY_TO_PLAY)
372370
GLOB.joined_player_list += player.ckey
373371
var/atom/spawn_loc = player.mind.assigned_role.get_roundstart_spawn_point()
374-
if(spawn_loc) //If we've been given an override, just take it and get out of here.
375-
player.create_character(spawn_loc)
372+
player.create_character(spawn_loc)
376373

377-
else //We haven't been passed an override destination. Give us the usual treatment.
378-
if(!length(spawn_spots))
379-
spawn_spots = spawn_spots_reload.Copy()
380-
381-
spawn_loc = pick_n_take(spawn_spots)
382-
player.create_character(spawn_loc)
383374
else //PLAYER_NOT_READY
384375
//Reload their player panel so they see latejoin instead of ready.
385376
player.npp.update()
386377

387378
CHECK_TICK
388379

380+
/// Returns a (probably) unused latejoin spawn point. Used by roundstart code to spread players out.
381+
/datum/controller/subsystem/ticker/proc/get_random_spawnpoint()
382+
var/static/list/spawnpoints
383+
if(!length(spawnpoints))
384+
if(length(SSjob.latejoin_trackers))
385+
spawnpoints = SSjob.latejoin_trackers.Copy()
386+
else
387+
return SSjob.get_last_resort_spawn_points()
388+
return pick_n_take(spawnpoints)
389+
389390
/datum/controller/subsystem/ticker/proc/collect_minds()
390391
for(var/i in GLOB.new_player_list)
391392
var/mob/dead/new_player/P = i

code/modules/jobs/job_types/_job.dm

+36-11
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ GLOBAL_LIST_INIT(job_display_order, list(
135135
/// Should this job be allowed to be picked for the bureaucratic error event?
136136
var/allow_bureaucratic_error = TRUE
137137

138-
///Is this job affected by weird spawns like the ones from station traits
139-
var/random_spawns_possible = TRUE
138+
/// How this job decides where to spawn.
139+
var/spawn_logic = JOBSPAWN_ALLOW_RANDOM
140140

141141
/// List of family heirlooms this job can get with the family heirloom quirk. List of types.
142142
var/list/family_heirlooms
@@ -433,22 +433,45 @@ GLOBAL_LIST_INIT(job_display_order, list(
433433
return "Due to extreme staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!"
434434

435435

436-
/// Returns either an atom the mob should spawn in, or null, if we have no special overrides.
436+
/// Returns either an atom the mob should spawn on.
437437
/datum/job/proc/get_roundstart_spawn_point()
438-
if(random_spawns_possible)
439-
return get_latejoin_spawn_point()
438+
SHOULD_NOT_OVERRIDE(TRUE)
440439

441-
if(length(GLOB.high_priority_spawns[title]))
442-
return pick(GLOB.high_priority_spawns[title])
440+
if(spawn_logic == JOBSPAWN_FORCE_RANDOM)
441+
return get_roundstart_spawn_point_random()
442+
443+
var/atom/spawn_point = get_roundstart_spawn_point_fixed()
444+
if(isnull(spawn_point))
445+
// That's okay, the map may not have any fixed spawnpoints for this job and this job allows that.
446+
if(spawn_logic == JOBSPAWN_ALLOW_RANDOM)
447+
return get_roundstart_spawn_point_random()
448+
449+
else // Something has gone horribly wrong
450+
stack_trace("Something has gone very wrong. [type] could not find a job spawn location.")
451+
return SSjob.get_last_resort_spawn_points()
452+
453+
return spawn_point
454+
455+
456+
/// Returns a fixed spawn location to use. This is probably one of a few job landmarks.
457+
/datum/job/proc/get_roundstart_spawn_point_fixed()
458+
PROTECTED_PROC(TRUE)
459+
return get_jobspawn_landmark()
443460

444-
return null //We don't care where we go. Let Ticker decide for us.
461+
/// Returns a roundstart spawnpoint to use if spawn logic determined it should spawn at a "random" location.
462+
/datum/job/proc/get_roundstart_spawn_point_random()
463+
PROTECTED_PROC(TRUE)
464+
return SSticker.get_random_spawnpoint()
445465

466+
/// Returns an unused jobspawn landmark. You CAN run out of landmarks, please be mindful of this!
467+
/datum/job/proc/get_jobspawn_landmark()
468+
SHOULD_NOT_OVERRIDE(TRUE)
469+
RETURN_TYPE(/obj/effect/landmark/start)
446470

447-
/// Handles finding and picking a valid roundstart effect landmark spawn point, in case no uncommon different spawning events occur.
448-
/datum/job/proc/get_default_roundstart_spawn_point()
449471
var/obj/effect/landmark/start/spawnpoint = get_start_landmark_for(title)
450472
if(!spawnpoint)
451473
log_world("Couldn't find a round start spawn point for [title].")
474+
return
452475

453476
spawnpoint.used = TRUE
454477

@@ -474,7 +497,9 @@ GLOBAL_LIST_INIT(job_display_order, list(
474497
else
475498
spawn_instance = new spawn_type(player_client.mob.loc)
476499
spawn_point.JoinPlayerHere(spawn_instance, TRUE)
500+
477501
spawn_instance.apply_prefs_job(player_client, src)
502+
478503
if(!player_client)
479504
qdel(spawn_instance)
480505
return // Disconnected while checking for the appearance ban.
@@ -483,7 +508,7 @@ GLOBAL_LIST_INIT(job_display_order, list(
483508

484509
/// Applies the preference options to the spawning mob, taking the job into account. Assumes the client has the proper mind.
485510
/mob/living/proc/apply_prefs_job(client/player_client, datum/job/job)
486-
511+
return
487512

488513
/mob/living/carbon/human/apply_prefs_job(client/player_client, datum/job/job)
489514
var/fully_randomize = GLOB.current_anonymous_theme || is_banned_from(player_client.ckey, "Appearance")

code/modules/jobs/job_types/ai.dm

+2-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
/datum/job_department/silicon,
2525
)
2626

27-
random_spawns_possible = FALSE
27+
spawn_logic = JOBSPAWN_FORCE_FIXED
2828
job_flags = JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK
2929
var/do_special_check = TRUE
3030

@@ -39,10 +39,9 @@
3939
ai_spawn.log_current_laws()
4040

4141

42-
/datum/job/ai/get_roundstart_spawn_point()
42+
/datum/job/ai/get_roundstart_spawn_point_fixed()
4343
return get_latejoin_spawn_point()
4444

45-
4645
/datum/job/ai/get_latejoin_spawn_point()
4746
var/list/primary_spawn_points = list() // Ideal locations.
4847
var/list/secondary_spawn_points = list() // Fallback locations.

code/modules/jobs/job_types/antagonists/nuclear_operative.dm

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/datum/job/nuclear_operative
22
title = ROLE_NUCLEAR_OPERATIVE
3+
spawn_logic = JOBSPAWN_FORCE_FIXED
34

45

5-
/datum/job/nuclear_operative/get_roundstart_spawn_point()
6-
return pick(GLOB.nukeop_start)
6+
/datum/job/nuclear_operative/get_roundstart_spawn_point_fixed()
7+
return get_latejoin_spawn_point()
78

89

910
/datum/job/nuclear_operative/get_latejoin_spawn_point()

code/modules/jobs/job_types/cyborg.dm

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
departments_list = list(
2121
/datum/job_department/silicon,
2222
)
23-
random_spawns_possible = FALSE
23+
spawn_logic = JOBSPAWN_FORCE_FIXED
2424
job_flags = JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK
2525

2626

code/modules/mob/living/silicon/ai/ai.dm

+33-21
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@
110110

111111
///Command report cooldown
112112
COOLDOWN_DECLARE(command_report_cd)
113+
/// An image to add to client.images so the AI player can see their own eye sprite.
114+
var/image/sense_of_self
113115

114116
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
115117
. = ..()
@@ -870,32 +872,42 @@
870872
/mob/living/silicon/ai/reset_perspective(atom/new_eye)
871873
if(camera_light_on)
872874
light_cameras()
875+
873876
if(istype(new_eye, /obj/machinery/camera))
874877
current = new_eye
875-
if(client)
876-
if(ismovable(new_eye))
877-
if(new_eye != GLOB.ai_camera_room_landmark)
878-
end_multicam()
879-
client.perspective = EYE_PERSPECTIVE
880-
client.eye = new_eye
881-
else
878+
879+
if(!client)
880+
return
881+
882+
client.images -= sense_of_self
883+
884+
if(ismovable(new_eye))
885+
if(new_eye != GLOB.ai_camera_room_landmark)
882886
end_multicam()
883-
if(isturf(loc))
884-
if(eyeobj)
885-
client.eye = eyeobj
886-
client.perspective = EYE_PERSPECTIVE
887-
else
888-
client.eye = client.mob
889-
client.perspective = MOB_PERSPECTIVE
890-
else
887+
client.perspective = EYE_PERSPECTIVE
888+
client.eye = new_eye
889+
890+
else
891+
end_multicam()
892+
if(isturf(loc))
893+
if(eyeobj)
894+
client.eye = eyeobj
891895
client.perspective = EYE_PERSPECTIVE
892-
client.eye = loc
893-
update_sight()
894-
if(client.eye != src)
895-
var/atom/AT = client.eye
896-
AT.get_remote_view_fullscreens(src)
896+
client.images += sense_of_self
897+
else
898+
client.eye = client.mob
899+
client.perspective = MOB_PERSPECTIVE
897900
else
898-
clear_fullscreen("remote_view", 0)
901+
client.perspective = EYE_PERSPECTIVE
902+
client.eye = loc
903+
904+
update_sight()
905+
906+
if(client.eye != src)
907+
var/atom/AT = client.eye
908+
AT.get_remote_view_fullscreens(src)
909+
else
910+
clear_fullscreen("remote_view", 0)
899911

900912
/mob/living/silicon/ai/revive(full_heal = FALSE, admin_revive = FALSE)
901913
. = ..()

code/modules/mob/living/silicon/ai/freelook/eye.dm

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// AI EYE
22
//
3-
// An invisible (no icon) mob that the AI controls to look around the station with.
3+
// An invisible mob that the AI controls to look around the station with.
44
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
55
/mob/camera/ai_eye
66
name = "Inactive AI Eye"
77

88
icon_state = "ai_camera"
99
icon = 'icons/mob/cameramob.dmi'
10+
plane = ABOVE_LIGHTING_PLANE
1011
invisibility = INVISIBILITY_MAXIMUM
1112
hud_possible = list(
1213
AI_DETECT_HUD = HUD_LIST_LIST
@@ -190,6 +191,8 @@
190191
eyeobj.set_real_name("[name] (AI Eye)")
191192
set_eyeobj_visible(TRUE)
192193

194+
sense_of_self = image(eyeobj.icon, eyeobj, eyeobj.icon_state)
195+
193196
/mob/living/silicon/ai/proc/set_eyeobj_visible(state = TRUE)
194197
if(!eyeobj)
195198
return

0 commit comments

Comments
 (0)