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("Job Creation") diff --git a/code/mob/new_player.dm b/code/mob/new_player.dm index 27913845b8349..22ac0dd45edf9 100644 --- a/code/mob/new_player.dm +++ b/code/mob/new_player.dm @@ -271,31 +271,6 @@ var/global/datum/mutex/limited/latespawning = new(5 SECONDS) else if(!href_list["late_join"]) new_player_panel() - proc/IsJobAvailable(var/datum/job/JOB) - if(!ticker || !ticker.mode) - return 0 - if (!JOB || !istype(JOB,/datum/job/) || JOB.limit == 0) - return 0 - if (!JOB.no_jobban_from_this_job && jobban_isbanned(src,JOB.name)) - return 0 - if (JOB.requires_supervisor_job && countJob(JOB.requires_supervisor_job) <= 0) - return 0 - if (JOB.requires_whitelist) - if (!(src.ckey in NT)) - return 0 - if (JOB.mentor_only) - if (!(src.ckey in mentors)) - return 0 - if (JOB.needs_college && !src.has_medal("Unlike the director, I went to college")) - return 0 - if (JOB.rounds_needed_to_play && (src.client && src.client.player)) - var/round_num = src.client.player.get_rounds_participated() - if (!isnull(round_num) && round_num < JOB.rounds_needed_to_play) //they havent played enough rounds! - return 0 - if (JOB.limit < 0 || JOB.assigned < JOB.limit) - return 1 - return 0 - proc/IsSiliconAvailableForLateJoin(var/mob/living/silicon/S) if (isdead(S)) return 0 @@ -321,7 +296,7 @@ var/global/datum/mutex/limited/latespawning = new(5 SECONDS) return global.latespawning.lock() - if (JOB && (force || IsJobAvailable(JOB))) + if (JOB && (force || job_controls.check_job_eligibility(src, JOB, STAPLE_JOBS | SPECIAL_JOBS))) var/mob/character = create_character(JOB, JOB.allow_traitors) if (isnull(character)) global.latespawning.unlock() @@ -496,7 +471,7 @@ var/global/datum/mutex/limited/latespawning = new(5 SECONDS) if (J.no_late_join) return var/limit = J.limit - if (!IsJobAvailable(J)) + if (!job_controls.check_job_eligibility(src, J, STAPLE_JOBS|SPECIAL_JOBS)) // Show unavailable jobs, but no joining them limit = 0 @@ -694,11 +669,11 @@ a.latejoin-card:hover { dat += {" Special Jobs"} for(var/datum/job/special/J in job_controls.special_jobs) - if (IsJobAvailable(J) && !J.no_late_join) + if (job_controls.check_job_eligibility(src, J, SPECIAL_JOBS) && !J.no_late_join) dat += LateJoinLink(J) for(var/datum/job/created/J in job_controls.special_jobs) - if (IsJobAvailable(J) && !J.no_late_join) + if (job_controls.check_job_eligibility(src, J, SPECIAL_JOBS) && !J.no_late_join) dat += LateJoinLink(J) dat += "" @@ -728,7 +703,7 @@ a.latejoin-card:hover { D.limit = -1 C.enabled_jobs += D for (var/datum/job/J in C.enabled_jobs) - if (IsJobAvailable(J) && !J.no_late_join) + if (job_controls.check_job_eligibility(src, J, STAPLE_JOBS|SPECIAL_JOBS) && !J.no_late_join) var/hover_text = J.short_description || "Join the round as [J.name]." dat += "" 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)