From 7b33df5b49921ea1e21e48449cc0c78a1183260a Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Sun, 12 May 2024 20:48:00 -0400
Subject: [PATCH 01/10] refactor
---
_std/defines/jobs.dm | 5 +
code/datums/controllers/job_controls.dm | 137 +++++++++++++++++
code/mob/new_player.dm | 35 +----
code/procs/jobprocs.dm | 196 +++---------------------
4 files changed, 168 insertions(+), 205 deletions(-)
diff --git a/_std/defines/jobs.dm b/_std/defines/jobs.dm
index ba0b4384e338c..85354fdcfd1a7 100644
--- a/_std/defines/jobs.dm
+++ b/_std/defines/jobs.dm
@@ -49,3 +49,8 @@
#define JOB_ENGINEERING "engineering"
#define JOB_CIVILIAN "civilian"
#define JOB_CREATED "created"
+
+// Job categories
+#define STAPLE_JOBS (1<<0)
+#define SPECIAL_JOBS (1<<1)
+#define HIDDEN_JOBS (1<<2)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index d1172fa3f499c..5b7e215eb35bd 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -64,6 +64,143 @@ var/datum/job_controller/job_controls
return 1
return 0
+ /// Returns TRUE if a player is eligible to play a given job
+ proc/check_job_eligibility(mob/new_player/player, datum/job/job, valid_categories = STAPLE_JOBS | SPECIAL_JOBS | HIDDEN_JOBS)
+ if(!player?.client)
+ logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.last_ckey] has no client.")
+ return
+ if (!job)
+ logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested check with invalid job datum arg.")
+ return
+ if ((job.limit >= 0) && (job.assigned >= job.limit))
+ return
+ var/list/valid_jobs = list()
+ if (HAS_FLAG(valid_categories, STAPLE_JOBS))
+ valid_jobs.Add(src.staple_jobs)
+ if (HAS_FLAG(valid_categories, SPECIAL_JOBS))
+ valid_jobs.Add(src.special_jobs)
+ if (HAS_FLAG(valid_categories, HIDDEN_JOBS))
+ valid_jobs.Add(src.hidden_jobs)
+ if (!valid_jobs.Find(job))
+ logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], but it was not found in list of valid jobs! (Flag value: [valid_categories]).")
+ return
+
+ var/datum/preferences/P = player.client.preferences
+ if(player.mind?.is_antagonist())
+ if (istype(ticker?.mode, /datum/game_mode/revolution))
+ if (job.cant_spawn_as_rev || ("loyalist" in P?.traitPreferences.traits_selected)) //Why would an NT Loyalist be a revolutionary?
+ return
+ else if ((istype(ticker?.mode, /datum/game_mode/conspiracy)) && job.cant_spawn_as_con)
+ return
+ if (jobban_isbanned(player, job))
+ logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], but is job banned.")
+ return
+ if (job.mentor_only && !(player.ckey in mentors))
+ logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], a mentor only job.")
+ return
+
+ if (!job.allow_antag_fallthrough && player.antag_fallthrough)
+ return
+
+ // all of the 'serious' check have passed
+ if (global.totally_random_jobs)
+ return TRUE
+
+ if (job.rounds_needed_to_play)
+ var/round_num = player.client.player.get_rounds_participated()
+ if (!isnull(round_num) && round_num < job.rounds_needed_to_play) //they havent played enough rounds!
+ return
+ if (job.needs_college && !player.has_medal("Unlike the director, I went to college"))
+ return
+ if (job.requires_whitelist && !NT.Find(ckey(player.mind.key)))
+ return
+ if (job.requires_supervisor_job && countJob(job.requires_supervisor_job) <= 0)
+ return
+
+ if (P.jobs_unwanted.Find(job.name))
+ return
+
+ return TRUE
+
+ /// Assigns a player a job based on their preferences and job availability
+ proc/allocate_player_to_job_by_preference(mob/new_player/player)
+ RETURN_TYPE(/datum/job)
+ if (!player.client)
+ return
+ var/datum/preferences/player_preferences = player.client.preferences
+ if (!player_preferences)
+ return
+ if (totally_random_jobs)
+ var/datum/job/random_job
+ shuffle_list(staple_jobs)
+ for (var/datum/job/job as anything in src.staple_jobs)
+ if (check_job_eligibility(player, job))
+ random_job = job
+ assign_job(player, job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (random job)")
+ if (!random_job) // what are you like, banned from everything...?
+ random_job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant) // very random
+ return random_job
+
+ // antag fall through flag set check
+ var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
+ if (fav_job)
+ if (!fav_job.allow_traitors && player.mind.special_role || !fav_job.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
+ player.antag_fallthrough = TRUE
+ else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
+ player.antag_fallthrough = TRUE
+
+ if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
+ assign_job(player, fav_job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
+ return fav_job
+
+ // If favorite job isn't available, check medium priority jobs
+ shuffle_list(player_preferences.jobs_med_priority)
+ for(var/job_name in player_preferences.jobs_med_priority)
+ var/datum/job/job = find_job_in_controller_by_string(job_name)
+ if (!job)
+ continue
+ if (check_job_eligibility(player, job, STAPLE_JOBS))
+ assign_job(player, job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (medium priority job)")
+ return job
+
+ // If no medium priority jobs are available or suitable, check low priority jobs
+ shuffle_list(player_preferences.jobs_low_priority)
+ for(var/job_name in player_preferences.jobs_low_priority)
+ var/datum/job/job = find_job_in_controller_by_string(job_name)
+ if (!job)
+ continue
+ if (check_job_eligibility(player, job, STAPLE_JOBS))
+ assign_job(player, job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (low priority job)")
+ return job
+
+ // look, we tried ok? Just be happy you work here at all.
+ var/list/low_priority_jobs = list()
+ for(var/datum/job/job in job_controls.staple_jobs)
+ if (job.low_priority_job)
+ low_priority_jobs += job
+ if (length(low_priority_jobs))
+ var/datum/job/job = pick(low_priority_jobs)
+ assign_job(player, job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Unable to give [player] a preferred job. Assigned [job.name] from the low priority jobs.")
+ return job
+
+ // staffie fallback
+ var/datum/job/fallback_job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant)
+ if(!fallback_job)
+ CRASH("Unable to locate the default fallback job in job controller. [player] has not been assigned a job!")
+ assign_job(player, fallback_job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (emergency fallback job)")
+
+ proc/assign_job(mob/player, datum/job/job)
+ PRIVATE_PROC(TRUE)
+ player.mind.assigned_role = job.name
+ logTheThing(LOG_DEBUG, player, "assigned job: [player.mind.assigned_role]")
+ job.assigned++
+
proc/job_creator()
src.check_user_changed()
var/list/dat = list("
"
dat += {"[J.name] ([J.assigned][J.limit == -1 ? "" : "/[J.limit]"]) "}
diff --git a/code/procs/jobprocs.dm b/code/procs/jobprocs.dm
index 0db3f9105d614..2ca4c5e044ec1 100644
--- a/code/procs/jobprocs.dm
+++ b/code/procs/jobprocs.dm
@@ -22,37 +22,10 @@ var/global/totally_random_jobs = FALSE
if(!J)
CRASH("FindOccupationCandidates called with invalid job name: [job] at level: [level]")
for (var/mob/new_player/player in unassigned)
- if(!player.client || !player.client.preferences) //Well shit.
- continue
- var/datum/preferences/P = player.client.preferences
- if(player.mind?.is_antagonist())
- if (ticker?.mode && istype(ticker.mode, /datum/game_mode/revolution))
- if (J.cant_spawn_as_rev || ("loyalist" in P.traitPreferences.traits_selected)) //Why would an NT Loyalist be a revolutionary?
- continue
- else if((ticker?.mode && istype(ticker.mode, /datum/game_mode/gang)) && (job != "Staff Assistant"))
- continue
- else if ((ticker?.mode && istype(ticker.mode, /datum/game_mode/conspiracy)) && J.cant_spawn_as_con)
- continue
-
- if (jobban_isbanned(player, job))
- continue
- if (!J.allow_traitors && player.mind.special_role || !J.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
- if(set_antag_fallthrough)
- player.antag_fallthrough = TRUE
- continue
- if (!J.allow_antag_fallthrough && player.antag_fallthrough)
- continue
-
- if (global.totally_random_jobs)
- candidates += player
+ if (!job_controls.check_job_eligibility(player, J))
continue
- if (J.needs_college && !player.has_medal("Unlike the director, I went to college"))
- continue
- if (J.requires_whitelist && !NT.Find(ckey(player.mind.key)))
- continue
- if (P.jobs_unwanted.Find(J.name))
- continue
+ var/datum/preferences/P = player.client.preferences
if (level == 1 && P.job_favorite == J.name)
candidates += player
else if (level == 2 && P.jobs_med_priority.Find(J.name))
@@ -100,13 +73,8 @@ else if (istype(JOB, /datum/job/security/security_officer))\
var/list/pick2 = list()
var/list/pick3 = list()
- // Stick all the available jobs into its own list so we can wiggle the fuck outta it
- var/list/available_job_roles = list()
- // Apart from ones in THIS list, which are jobs we want to assign before any others
+ // jobs we want to assign before any others
var/list/high_priority_jobs = list()
- // This list is for jobs like staff assistant which have no limits, or other special-case
- // shit to hand out to people who didn't get one of the main limited slot jobs
- var/list/low_priority_jobs = list()
var/list/medical_staff = list()
var/list/engineering_staff = list()
@@ -120,27 +88,13 @@ else if (istype(JOB, /datum/job/security/security_officer))\
// If it's hi-pri, add it to that list. Simple enough
if (JOB.high_priority_job)
high_priority_jobs.Add(JOB)
- // If we've got a job with the low priority var set or no limit, chuck it in the
- // low-pri list and move onto the next job - if we don't do this, the first time
- // it hits a limitless job it'll get stuck on it and hand it out to everyone then
- // boot the game up resulting in ~WEIRD SHIT~
- else if (JOB.low_priority_job)
- low_priority_jobs += JOB.name
- continue
- // otherwise it's a normal role so it goes in that list instead
- else
- available_job_roles.Add(JOB)
- // Wiggle it like a pissy caterpillar
- shuffle_list(available_job_roles)
// Wiggle the players too so that priority isn't determined by key alphabetization
shuffle_list(unassigned)
//Shuffle them and *then* sort them according to their order priority
sortList(high_priority_jobs, GLOBAL_PROC_REF(cmp_job_order_priority))
- sortList(available_job_roles, GLOBAL_PROC_REF(cmp_job_order_priority))
-
// First we deal with high-priority jobs like Captain or AI which generally will always
// be present on the station - we want these assigned first just to be sure
// Though we don't want to do this in sandbox mode where it won't matter anyway
@@ -191,104 +145,10 @@ else if (istype(JOB, /datum/job/security/security_officer))\
unassigned -= candidate
JOB.assigned++
- //we've filled out the high priority section of this job, drop it down to being a normal role for the rest
- if (JOB.assigned >= JOB.high_priority_limit && JOB.assigned < JOB.limit)
- high_priority_jobs -= JOB
- available_job_roles |= JOB
- shuffle_list(available_job_roles)
-
- else
- // if we are in sandbox mode just roll the hi-pri jobs back into the regular list so
- // people can still get them if they chose them
- available_job_roles = available_job_roles | high_priority_jobs
-
- // Next we go through each player and see if we can get them into their favorite jobs
- // If we don't do this loop then the main loop below might get to a job they have in their
- // medium or low priority lists first and give them that one rather than their favorite
- for (var/mob/new_player/player in unassigned)
- // If they don't have a favorite, skip em
- if (derelict_mode) // stop freaking out at the weird jobs
- continue
- if (global.totally_random_jobs) // we don't care about favorites
- continue
- if (!player?.client?.preferences || player?.client?.preferences.job_favorite == null)
- continue
- // Now get the in-system job via the string
- var/datum/job/JOB = find_job_in_controller_by_string(player.client.preferences.job_favorite)
- // Do a few checks to make sure they're allowed to have this job
- if (ticker?.mode && istype(ticker.mode, /datum/game_mode/revolution))
- if(player.mind?.is_antagonist() && (JOB.cant_spawn_as_rev || JOB.cant_spawn_as_con))
- // Fixed AI, security etc spawning as rev heads. The special job picker doesn't care about that var yet,
- // but I'm not gonna waste too much time tending to a basically abandoned game mode (Convair880).
- continue
- if (!JOB || jobban_isbanned(player,JOB.name))
- continue
- if (JOB.needs_college && !player.has_medal("Unlike the director, I went to college"))
- continue
- if (JOB.requires_whitelist && !NT.Find(ckey(player.mind.key)))
- continue
- if (!JOB.allow_traitors && player.mind.special_role || !JOB.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
- player.antag_fallthrough = TRUE
- continue
- if ((!JOB.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
- player.antag_fallthrough = TRUE
- continue
- // If there's an open job slot for it, give the player the job and remove them from
- // the list of unassigned players, hey presto everyone's happy (except clarks probly)
- if (JOB.limit < 0 || !(JOB.assigned >= JOB.limit))
- ASSIGN_STAFF_LISTS(JOB, player)
-
- logTheThing(LOG_DEBUG, null, "I Said No/Jobs: [player] took [JOB.name] from favorite selector")
- player.mind.assigned_role = JOB.name
- logTheThing(LOG_DEBUG, player, "assigned job: [player.mind.assigned_role]")
- unassigned -= player
- JOB.assigned++
-
- // Do this loop twice - once for med priority and once for low priority, because elsewise
- // it was causing weird shit to happen where having something in low priority would
- // sometimes cause you to get that instead of a higher prioritized job
- for(var/datum/job/JOB in available_job_roles)
- // If we've got everyone a job, then stop wasting cycles and get on with the show
- if (!length(unassigned)) break
- // If there's no more slots for this job available, move onto the next one
- if (JOB.limit > 0 && JOB.assigned >= JOB.limit) continue
- // First, rebuild the lists of who wants to be this job
- pick2 = FindOccupationCandidates(unassigned,JOB.name,2, TRUE)
- // Now loop through the candidates in order of priority, and elect them to the
- // job position if possible - if at any point the job is filled, break the loops
- for(var/mob/new_player/candidate in pick2)
- if (JOB.assigned >= JOB.limit || !length(unassigned))
- break
- ASSIGN_STAFF_LISTS(JOB, candidate)
-
- logTheThing(LOG_DEBUG, null, "I Said No/Jobs: [candidate] took [JOB.name] from Level 2 Job Picker")
- candidate.mind.assigned_role = JOB.name
- logTheThing(LOG_DEBUG, candidate, "assigned job: [candidate.mind.assigned_role]")
- unassigned -= candidate
- JOB.assigned++
-
- // And then again for low priority
- for(var/datum/job/JOB in available_job_roles)
- if (!length(unassigned))
- break
-
- if (JOB.limit == 0)
- continue
-
- if (JOB.limit > 0 && JOB.assigned >= JOB.limit)
- continue
-
- pick3 = FindOccupationCandidates(unassigned,JOB.name,3, TRUE)
- for(var/mob/new_player/candidate in pick3)
- if (JOB.assigned >= JOB.limit || !length(unassigned))
- break
- ASSIGN_STAFF_LISTS(JOB, candidate)
-
- logTheThing(LOG_DEBUG, null, "I Said No/Jobs: [candidate] took [JOB.name] from Level 3 Job Picker")
- candidate.mind.assigned_role = JOB.name
- logTheThing(LOG_DEBUG, candidate, "assigned job: [candidate.mind.assigned_role]")
- unassigned -= candidate
- JOB.assigned++
+ // allocate the remaining players to jobs by preference
+ for (var/mob/new_player/player as anything in unassigned)
+ var/datum/job/job = job_controls.allocate_player_to_job_by_preference(player)
+ ASSIGN_STAFF_LISTS(job, player)
/////////////////////////////////////////////////
///////////COMMAND PROMOTIONS////////////////////
@@ -296,39 +156,25 @@ else if (istype(JOB, /datum/job/security/security_officer))\
//Find the command jobs, if they are unfilled, pick a random person from within that department to be that command officer
//if they had the command job in their medium or low priority jobs
- for(var/datum/job/JOB in available_job_roles)
- //cheaper to discout this first than type check here *I think*
- if (istype(JOB, /datum/job/command) && JOB.limit > 0 && JOB.assigned < JOB.limit)
+ for(var/datum/job/command/command_job in job_controls.staple_jobs)
+ if ((command_job.limit > 0) && (command_job.assigned < command_job.limit))
var/list/picks
- if (istype(JOB, /datum/job/command/chief_engineer))
- picks = FindPromotionCandidates(engineering_staff, JOB)
- else if (istype(JOB, /datum/job/command/research_director))
- picks = FindPromotionCandidates(research_staff, JOB)
- else if (istype(JOB, /datum/job/command/medical_director))
- picks = FindPromotionCandidates(medical_staff, JOB)
- else if (istype(JOB, /datum/job/command/head_of_security))
- picks = FindPromotionCandidates(security_officers, JOB)
+ if (istype(command_job, /datum/job/command/chief_engineer))
+ picks = FindPromotionCandidates(engineering_staff, command_job)
+ else if (istype(command_job, /datum/job/command/research_director))
+ picks = FindPromotionCandidates(research_staff, command_job)
+ else if (istype(command_job, /datum/job/command/medical_director))
+ picks = FindPromotionCandidates(medical_staff, command_job)
+ else if (istype(command_job, /datum/job/command/head_of_security))
+ picks = FindPromotionCandidates(security_officers, command_job)
if (!length(picks))
continue
var/mob/new_player/candidate = pick(picks)
- logTheThing(LOG_DEBUG, null, "kyle: [candidate] took [JOB.name] from Job Promotion Picker")
- candidate.mind.assigned_role = JOB.name
+ logTheThing(LOG_DEBUG, null, "kyle: [candidate] took [command_job.name] from Job Promotion Picker")
+ candidate.mind.assigned_role = command_job.name
logTheThing(LOG_DEBUG, candidate, "reassigned job: [candidate.mind.assigned_role]")
- JOB.assigned++
-
-
- // If there's anyone left without a job after this, lump them with a randomly
- // picked low priority role and be done with it
- if (!length(low_priority_jobs))
- // we really need to fix this or it'll be some kinda weird inf loop shit
- low_priority_jobs += "Staff Assistant"
- for (var/mob/new_player/player in unassigned)
- if(!player?.mind) continue
- logTheThing(LOG_DEBUG, null, "I Said No/Jobs: [player] given a low priority role")
- player.mind.assigned_role = pick(low_priority_jobs)
- logTheThing(LOG_DEBUG, player, "assigned job: [player.mind.assigned_role]")
-
- return 1
+ command_job.assigned++
+ return TRUE
//Given a list of candidates returns candidates that are acceptable to be promoted based on their medium/low priorities
//ideally JOB should only be a command position. eg. CE, RD, MD
From 8861c33b2f7b8b27d47deb7e97d500408505416b Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Sun, 12 May 2024 21:20:17 -0400
Subject: [PATCH 02/10] fallback job fix
---
code/datums/controllers/job_controls.dm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 5b7e215eb35bd..2e30e365dbec6 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -193,7 +193,8 @@ var/datum/job_controller/job_controls
if(!fallback_job)
CRASH("Unable to locate the default fallback job in job controller. [player] has not been assigned a job!")
assign_job(player, fallback_job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (emergency fallback job)")
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fallback_job.name] (emergency fallback job)")
+ return fallback_job
proc/assign_job(mob/player, datum/job/job)
PRIVATE_PROC(TRUE)
From 4343107e0d255fb1072ed011a51b0b569f643450 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Sun, 12 May 2024 21:55:11 -0400
Subject: [PATCH 03/10] runtime on log fix
---
code/datums/controllers/job_controls.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 2e30e365dbec6..e5e08f753e7de 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -163,7 +163,7 @@ var/datum/job_controller/job_controls
continue
if (check_job_eligibility(player, job, STAPLE_JOBS))
assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (medium priority job)")
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (medium priority job)")
return job
// If no medium priority jobs are available or suitable, check low priority jobs
@@ -174,7 +174,7 @@ var/datum/job_controller/job_controls
continue
if (check_job_eligibility(player, job, STAPLE_JOBS))
assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (low priority job)")
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (low priority job)")
return job
// look, we tried ok? Just be happy you work here at all.
From 7f97c058bda7b7384c44e5c2603be6e2eba12936 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Sun, 12 May 2024 22:15:27 -0400
Subject: [PATCH 04/10] fix jobban check runtime
---
code/datums/controllers/job_controls.dm | 26 +++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index e5e08f753e7de..6ef3337a082c9 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -92,7 +92,7 @@ var/datum/job_controller/job_controls
return
else if ((istype(ticker?.mode, /datum/game_mode/conspiracy)) && job.cant_spawn_as_con)
return
- if (jobban_isbanned(player, job))
+ if (!job.no_jobban_from_this_job && jobban_isbanned(player, job.name))
logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], but is job banned.")
return
if (job.mentor_only && !(player.ckey in mentors))
@@ -143,17 +143,18 @@ var/datum/job_controller/job_controls
return random_job
// antag fall through flag set check
- var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
- if (fav_job)
- if (!fav_job.allow_traitors && player.mind.special_role || !fav_job.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
- player.antag_fallthrough = TRUE
- else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
- player.antag_fallthrough = TRUE
-
- if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
- assign_job(player, fav_job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
- return fav_job
+ if (player_preferences.job_favorite)
+ var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
+ if (fav_job)
+ if (!fav_job.allow_traitors && player.mind.special_role || !fav_job.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
+ player.antag_fallthrough = TRUE
+ else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
+ player.antag_fallthrough = TRUE
+
+ if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
+ assign_job(player, fav_job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
+ return fav_job
// If favorite job isn't available, check medium priority jobs
shuffle_list(player_preferences.jobs_med_priority)
@@ -1064,6 +1065,7 @@ var/datum/job_controller/job_controls
/proc/find_job_in_controller_by_string(var/string, var/staple_only = 0, var/soft = FALSE, var/case_sensitive = TRUE)
RETURN_TYPE(/datum/job)
if (!string || !istext(string))
+ stack_trace("Attempt to find job with bad string in controller detected")
logTheThing(LOG_DEBUG, null, "Job Controller: Attempt to find job with bad string in controller detected")
return null
var/list/excluded_strings = list("Special Respawn","Custom Names","Everything Except Assistant",
From b32051145ec32a292f8d8917fbba02ec5e980844 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Sun, 12 May 2024 22:19:43 -0400
Subject: [PATCH 05/10] fix potential bug, remove temp debug logging
---
code/datums/controllers/job_controls.dm | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 6ef3337a082c9..20fca08f08c19 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -142,19 +142,20 @@ var/datum/job_controller/job_controls
random_job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant) // very random
return random_job
- // antag fall through flag set check
if (player_preferences.job_favorite)
var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
if (fav_job)
+ // antag fall through flag set check
if (!fav_job.allow_traitors && player.mind.special_role || !fav_job.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
player.antag_fallthrough = TRUE
else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
player.antag_fallthrough = TRUE
- if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
- assign_job(player, fav_job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
- return fav_job
+ // try to assign fav job
+ if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
+ assign_job(player, fav_job)
+ logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
+ return fav_job
// If favorite job isn't available, check medium priority jobs
shuffle_list(player_preferences.jobs_med_priority)
@@ -1065,7 +1066,6 @@ var/datum/job_controller/job_controls
/proc/find_job_in_controller_by_string(var/string, var/staple_only = 0, var/soft = FALSE, var/case_sensitive = TRUE)
RETURN_TYPE(/datum/job)
if (!string || !istext(string))
- stack_trace("Attempt to find job with bad string in controller detected")
logTheThing(LOG_DEBUG, null, "Job Controller: Attempt to find job with bad string in controller detected")
return null
var/list/excluded_strings = list("Special Respawn","Custom Names","Everything Except Assistant",
From 38b3aa0e9d4882956f9b4206064d272ab14b25cb Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Mon, 13 May 2024 00:17:16 -0400
Subject: [PATCH 06/10] HoS agrees to retire from SPACE COPS gang leader, add
more code comments
---
code/datums/controllers/job_controls.dm | 25 +++++++++++++++++--------
code/mob/new_player.dm | 2 +-
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 20fca08f08c19..104b756cee7f5 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -74,6 +74,7 @@ var/datum/job_controller/job_controls
return
if ((job.limit >= 0) && (job.assigned >= job.limit))
return
+ // prevent someone from trying to sneak their way into a job they shouldn't be able to choose
var/list/valid_jobs = list()
if (HAS_FLAG(valid_categories, STAPLE_JOBS))
valid_jobs.Add(src.staple_jobs)
@@ -84,25 +85,31 @@ var/datum/job_controller/job_controls
if (!valid_jobs.Find(job))
logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], but it was not found in list of valid jobs! (Flag value: [valid_categories]).")
return
-
var/datum/preferences/P = player.client.preferences
+ // antag job exemptions
if(player.mind?.is_antagonist())
- if (istype(ticker?.mode, /datum/game_mode/revolution))
- if (job.cant_spawn_as_rev || ("loyalist" in P?.traitPreferences.traits_selected)) //Why would an NT Loyalist be a revolutionary?
- return
+ if ((!job.allow_traitors && player.mind.special_role))
+ return
+ else if (!job.allow_spy_theft && (player.mind.special_role == ROLE_SPY_THIEF))
+ return
+ else if (istype(ticker?.mode, /datum/game_mode/revolution) && (job.cant_spawn_as_rev || ("loyalist" in P?.traitPreferences.traits_selected)))
+ return
else if ((istype(ticker?.mode, /datum/game_mode/conspiracy)) && job.cant_spawn_as_con)
return
+ else if ((!job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
+ return
+ // job ban check
if (!job.no_jobban_from_this_job && jobban_isbanned(player, job.name))
logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], but is job banned.")
return
+ // mentor only job check
if (job.mentor_only && !(player.ckey in mentors))
logTheThing(LOG_DEBUG, null, "Jobs: check job eligibility error - [player.ckey] requested [job.name], a mentor only job.")
return
-
+ // meant to prevent you from setting sec as fav and captain (or similar) as your only medium to ensure only captain traitor rounds
if (!job.allow_antag_fallthrough && player.antag_fallthrough)
return
-
- // all of the 'serious' check have passed
+ // all of the 'serious' check have passed, ignore the rest of the requirements for random job rounds.
if (global.totally_random_jobs)
return TRUE
@@ -146,7 +153,9 @@ var/datum/job_controller/job_controls
var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
if (fav_job)
// antag fall through flag set check
- if (!fav_job.allow_traitors && player.mind.special_role || !fav_job.allow_spy_theft && player.mind.special_role == ROLE_SPY_THIEF)
+ if ((!fav_job.allow_traitors && player.mind.special_role))
+ player.antag_fallthrough = TRUE
+ else if (!fav_job.allow_spy_theft && (player.mind.special_role == ROLE_SPY_THIEF))
player.antag_fallthrough = TRUE
else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
player.antag_fallthrough = TRUE
diff --git a/code/mob/new_player.dm b/code/mob/new_player.dm
index 22ac0dd45edf9..60f5c76fef4aa 100644
--- a/code/mob/new_player.dm
+++ b/code/mob/new_player.dm
@@ -471,7 +471,7 @@ var/global/datum/mutex/limited/latespawning = new(5 SECONDS)
if (J.no_late_join)
return
var/limit = J.limit
- if (!job_controls.check_job_eligibility(src, J, STAPLE_JOBS|SPECIAL_JOBS))
+ if (!job_controls.check_job_eligibility(src, J, STAPLE_JOBS | SPECIAL_JOBS))
// Show unavailable jobs, but no joining them
limit = 0
From 4697601440dafa4aa9372c29f787325436e9e137 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Mon, 13 May 2024 01:45:22 -0400
Subject: [PATCH 07/10] Not wanting a job isnt the same as being ineligible to
do it now get to work
---
code/datums/controllers/job_controls.dm | 4 ----
1 file changed, 4 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 104b756cee7f5..3e06972da710e 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -123,10 +123,6 @@ var/datum/job_controller/job_controls
return
if (job.requires_supervisor_job && countJob(job.requires_supervisor_job) <= 0)
return
-
- if (P.jobs_unwanted.Find(job.name))
- return
-
return TRUE
/// Assigns a player a job based on their preferences and job availability
From 7480e035de9b841013fddfe9b8e5f5b0d6a623b4 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Mon, 13 May 2024 02:39:59 -0400
Subject: [PATCH 08/10] dedupe some code into try_assign_job_from_list
---
code/datums/controllers/job_controls.dm | 89 ++++++++++++++-----------
1 file changed, 49 insertions(+), 40 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 3e06972da710e..fe754998c476f 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -125,6 +125,23 @@ var/datum/job_controller/job_controls
return
return TRUE
+ /// attempts to assign a player to a job from a list of either job datums or job strings
+ proc/try_assign_job_from_list(mob/player, list/jobs)
+ PRIVATE_PROC(TRUE)
+ RETURN_TYPE(/datum/job)
+ shuffle_list(jobs)
+ for(var/job_entry in jobs)
+ var/datum/job/job
+ if (istext(job_entry))
+ job = find_job_in_controller_by_string(job_entry)
+ else
+ job = job_entry
+ if (job && check_job_eligibility(player, job, STAPLE_JOBS))
+ player.mind.assigned_role = job.name
+ job.assigned++
+ return job
+ return null
+
/// Assigns a player a job based on their preferences and job availability
proc/allocate_player_to_job_by_preference(mob/new_player/player)
RETURN_TYPE(/datum/job)
@@ -133,55 +150,46 @@ var/datum/job_controller/job_controls
var/datum/preferences/player_preferences = player.client.preferences
if (!player_preferences)
return
+
if (totally_random_jobs)
- var/datum/job/random_job
- shuffle_list(staple_jobs)
- for (var/datum/job/job as anything in src.staple_jobs)
- if (check_job_eligibility(player, job))
- random_job = job
- assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (random job)")
- if (!random_job) // what are you like, banned from everything...?
- random_job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant) // very random
- return random_job
+ var/datum/job/job = try_assign_job_from_list(player, staple_jobs)
+ if (!job) // what are you like, banned from everything...?
+ job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant) // very random
+ player.mind.assigned_role = job.name
+ job.assigned++
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [job.name] (random job)")
+ return job
if (player_preferences.job_favorite)
- var/datum/job/fav_job = find_job_in_controller_by_string(player_preferences.job_favorite)
- if (fav_job)
+ var/datum/job/job = find_job_in_controller_by_string(player_preferences.job_favorite)
+ if (job)
// antag fall through flag set check
- if ((!fav_job.allow_traitors && player.mind.special_role))
+ if ((!job.allow_traitors && player.mind.special_role))
player.antag_fallthrough = TRUE
- else if (!fav_job.allow_spy_theft && (player.mind.special_role == ROLE_SPY_THIEF))
+ else if (!job.allow_spy_theft && (player.mind.special_role == ROLE_SPY_THIEF))
player.antag_fallthrough = TRUE
- else if ((!fav_job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
+ else if ((!job.can_join_gangs) && (player.mind.special_role in list(ROLE_GANG_MEMBER,ROLE_GANG_LEADER)))
player.antag_fallthrough = TRUE
// try to assign fav job
- if (check_job_eligibility(player, fav_job, STAPLE_JOBS))
- assign_job(player, fav_job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fav_job.name] (favorite job)")
- return fav_job
+ if (check_job_eligibility(player, job, STAPLE_JOBS))
+ player.mind.assigned_role = job.name
+ job.assigned++
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [job.name] (favorite job)")
+ return job
// If favorite job isn't available, check medium priority jobs
- shuffle_list(player_preferences.jobs_med_priority)
- for(var/job_name in player_preferences.jobs_med_priority)
- var/datum/job/job = find_job_in_controller_by_string(job_name)
- if (!job)
- continue
- if (check_job_eligibility(player, job, STAPLE_JOBS))
- assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (medium priority job)")
+ if (length(player_preferences.jobs_med_priority))
+ var/datum/job/job = try_assign_job_from_list(player, player_preferences.jobs_med_priority)
+ if (job)
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [job.name] (medium priority job)")
return job
// If no medium priority jobs are available or suitable, check low priority jobs
- shuffle_list(player_preferences.jobs_low_priority)
- for(var/job_name in player_preferences.jobs_low_priority)
- var/datum/job/job = find_job_in_controller_by_string(job_name)
- if (!job)
- continue
- if (check_job_eligibility(player, job, STAPLE_JOBS))
- assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [job.name] (low priority job)")
+ if (length(player_preferences.jobs_low_priority))
+ var/datum/job/job = try_assign_job_from_list(player, player_preferences.jobs_low_priority)
+ if (job)
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [job.name] (low priority job)")
return job
// look, we tried ok? Just be happy you work here at all.
@@ -191,22 +199,23 @@ var/datum/job_controller/job_controls
low_priority_jobs += job
if (length(low_priority_jobs))
var/datum/job/job = pick(low_priority_jobs)
- assign_job(player, job)
- logTheThing(LOG_DEBUG, null, "Jobs: Unable to give [player] a preferred job. Assigned [job.name] from the low priority jobs.")
+ player.mind.assigned_role = job.name
+ job.assigned++
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [job.name] (fallback job).")
return job
// staffie fallback
var/datum/job/fallback_job = find_job_in_controller_by_path(/datum/job/civilian/staff_assistant)
if(!fallback_job)
CRASH("Unable to locate the default fallback job in job controller. [player] has not been assigned a job!")
- assign_job(player, fallback_job)
- logTheThing(LOG_DEBUG, null, "Jobs: Assigned [player] job [fallback_job.name] (emergency fallback job)")
+ player.mind.assigned_role = fallback_job.name
+ fallback_job.assigned++
+ logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [fallback_job.name] (emergency fallback job)")
return fallback_job
proc/assign_job(mob/player, datum/job/job)
PRIVATE_PROC(TRUE)
player.mind.assigned_role = job.name
- logTheThing(LOG_DEBUG, player, "assigned job: [player.mind.assigned_role]")
job.assigned++
proc/job_creator()
From 29eb9d60a27a4d0b89de4f5bf0101e1155e4d8a2 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Mon, 13 May 2024 02:41:13 -0400
Subject: [PATCH 09/10] remove unused proc
---
code/datums/controllers/job_controls.dm | 5 -----
1 file changed, 5 deletions(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index fe754998c476f..08c8dfe44b2be 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -213,11 +213,6 @@ var/datum/job_controller/job_controls
logTheThing(LOG_DEBUG, player, "Jobs: Assigned job: [fallback_job.name] (emergency fallback job)")
return fallback_job
- proc/assign_job(mob/player, datum/job/job)
- PRIVATE_PROC(TRUE)
- player.mind.assigned_role = job.name
- job.assigned++
-
proc/job_creator()
src.check_user_changed()
var/list/dat = list("Job Creation")
From 497cc141f8f674c65e9e2028f7f02b5983e44537 Mon Sep 17 00:00:00 2001
From: Sovexe <33204415+Sovexe@users.noreply.github.com>
Date: Mon, 13 May 2024 02:48:59 -0400
Subject: [PATCH 10/10] return null -> return
---
code/datums/controllers/job_controls.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/datums/controllers/job_controls.dm b/code/datums/controllers/job_controls.dm
index 08c8dfe44b2be..7795caf9b1fd1 100644
--- a/code/datums/controllers/job_controls.dm
+++ b/code/datums/controllers/job_controls.dm
@@ -140,7 +140,7 @@ var/datum/job_controller/job_controls
player.mind.assigned_role = job.name
job.assigned++
return job
- return null
+ return
/// Assigns a player a job based on their preferences and job availability
proc/allocate_player_to_job_by_preference(mob/new_player/player)
|