From 12c5adeeb39dd047e662ba44c4fe29880cb66eb3 Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Mon, 13 Apr 2026 09:06:54 +0300 Subject: [PATCH] removes the last of the old job controller (#19344) * removes the last of the old job controller * . * . * . * . * . * Update admin_verbs.dm * Update admin_verbs.dm --------- Co-authored-by: Cameron Lennox --- code/_helpers/global_lists.dm | 8 - code/controllers/admin.dm | 2 - code/controllers/master_controller.dm | 37 - code/controllers/subsystems/antag_job.dm | 5 +- code/controllers/subsystems/job.dm | 949 ++++++++++++++++- code/controllers/subsystems/persist_vr.dm | 4 +- code/controllers/subsystems/ticker.dm | 10 +- code/datums/mind.dm | 2 +- code/datums/outfits/jobs/job.dm | 2 +- code/game/jobs/access.dm | 2 +- code/game/jobs/job/job.dm | 6 +- code/game/jobs/job_controller.dm | 986 ------------------ code/game/jobs/whitelist.dm | 6 +- code/game/machinery/computer/security.dm | 2 +- code/game/machinery/computer/timeclock_vr.dm | 12 +- code/game/machinery/cryopod.dm | 2 +- code/game/machinery/protean_reconstitutor.dm | 2 +- .../machinery/virtual_reality/ar_console.dm | 2 +- .../machinery/virtual_reality/vr_console.dm | 2 +- .../machinery/virtual_reality/vr_procs.dm | 2 +- .../items/weapons/id cards/station_ids.dm | 2 +- code/game/objects/mail.dm | 2 +- .../objects/structures/ghost_pods/event_vr.dm | 2 +- .../ghost_pods/unified_ghost_hole.dm | 2 +- code/game/world.dm | 4 - code/modules/admin/admin_verbs.dm | 18 +- code/modules/admin/topic.dm | 44 +- code/modules/admin/verbs/mapping.dm | 4 +- code/modules/admin/verbs/randomverbs.dm | 10 +- code/modules/admin/verbs/tripAI.dm | 4 +- .../preference_setup/occupation/occupation.dm | 8 +- code/modules/mob/dead/observer/free_vr.dm | 2 +- code/modules/mob/living/silicon/silicon.dm | 2 +- code/modules/mob/mob.dm | 2 +- code/modules/mob/new_player/new_player.dm | 8 +- .../mob/new_player/preferences_setup.dm | 8 +- code/modules/resleeving/autoresleever.dm | 4 +- code/modules/tgs_commands/vorestation.dm | 4 +- code/modules/tgui/modules/late_choices.dm | 2 +- vorestation.dme | 2 - 40 files changed, 1029 insertions(+), 1148 deletions(-) delete mode 100644 code/controllers/master_controller.dm delete mode 100644 code/game/jobs/job_controller.dm diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 87b9070a57..baccc475e1 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -16,7 +16,6 @@ GLOBAL_LIST_EMPTY(cable_list) //Index for all cables, so that powernets don GLOBAL_LIST_EMPTY(landmarks_list) //list of all landmarks created GLOBAL_LIST_EMPTY(event_triggers) //Associative list of creator_ckey:list(landmark references) for event triggers GLOBAL_LIST_EMPTY(surgery_steps) //list of all surgery steps |BS12 -GLOBAL_LIST_EMPTY(joblist) //list of all jobstypes, minus borg and AI GLOBAL_LIST_EMPTY(mechas_list) //list of all mechs. Used by hostile mobs target tracking. GLOBAL_LIST_EMPTY_TYPED(PDAs, /obj/item/pda) @@ -173,13 +172,6 @@ GLOBAL_LIST_EMPTY(mannequins) GLOB.surgery_steps += S sort_surgeries() - //List of job. I can't believe this was calculated multiple times per tick! - paths = subtypesof(/datum/job) - paths -= GLOB.exclude_jobs - for(var/T in paths) - var/datum/job/J = new T - GLOB.joblist[J.title] = J - //Languages paths = subtypesof(/datum/language) for(var/T in paths) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 9e8b338fe3..043fd9eeef 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -77,8 +77,6 @@ ADMIN_VERB(debug_controller, R_DEBUG, "Debug Controller", "Debug the various per options[strtype] = S //Goon PS stuff, and other yet-to-be-subsystem things. - options["LEGACY: master_controller"] = GLOB.master_controller - options["LEGACY: job_master"] = GLOB.job_master options["LEGACY: cameranet"] = GLOB.cameranet var/pick = tgui_input_list(user, "Choose a controller to debug/view variables of.", "VV controller:", options) diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm deleted file mode 100644 index c0f9095ea9..0000000000 --- a/code/controllers/master_controller.dm +++ /dev/null @@ -1,37 +0,0 @@ -//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one. -//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs) -//WIP, needs lots of work still - -// -// TODO - This will be completely replaced by master.dm in time. -// -GLOBAL_DATUM(master_controller, /datum/controller/game_controller) //Set in world.New() - -/datum/controller/game_controller - var/list/shuttle_list // For debugging and VV - -/datum/controller/game_controller/New() - //There can be only one master_controller. Out with the old and in with the new. - if(GLOB.master_controller != src) - log_world("Rebuilding Master Controller") - if(istype(GLOB.master_controller)) - qdel(GLOB.master_controller) - GLOB.master_controller = src - - if(!GLOB.job_master) - GLOB.job_master = new /datum/controller/occupations() - GLOB.job_master.SetupOccupations() - GLOB.job_master.LoadJobs("config/jobs.txt") - admin_notice(span_danger("Job setup complete"), R_DEBUG) - -/datum/controller/game_controller/proc/setup() - // setupgenetics() Moved to SSatoms - // SetupXenoarch() - Moved to SSxenoarch - - admin_notice(span_danger("Initializations complete."), R_DEBUG) - -// #if UNIT_TESTS -// # define CHECK_SLEEP_MASTER // For unit tests we don't care about a smooth lobby screen experience. We care about speed. -// #else -// # define CHECK_SLEEP_MASTER if(++initialized_objects > 500) { initialized_objects=0;sleep(world.tick_lag); } -// #endif diff --git a/code/controllers/subsystems/antag_job.dm b/code/controllers/subsystems/antag_job.dm index d00038da1b..5d2d0b7c4b 100644 --- a/code/controllers/subsystems/antag_job.dm +++ b/code/controllers/subsystems/antag_job.dm @@ -2,6 +2,9 @@ SUBSYSTEM_DEF(antag_job) name = "Antag Job" flags = SS_NO_FIRE //List of all jobs + dependencies = list( + /datum/controller/subsystem/job + ) var/list/occupations = list() var/list/syndicate_code_phrase @@ -73,7 +76,7 @@ SUBSYSTEM_DEF(antag_job) code_phrase += " " code_phrase += pick(GLOB.last_names) if(2) - code_phrase += pick(GLOB.joblist)//Returns a job. + code_phrase += pick(SSjob.occupations_by_name)//Returns a job. safety -= 1 if(2) switch(rand(1,2))//Places or things. diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm index fce533fc80..55ff3e14a4 100644 --- a/code/controllers/subsystems/job.dm +++ b/code/controllers/subsystems/job.dm @@ -5,43 +5,50 @@ SUBSYSTEM_DEF(job) ) flags = SS_NO_FIRE - var/list/occupations = list() //List of all jobs - var/list/datum/job/name_occupations = list() //Dict of all jobs, keys are titles + //List of all jobs + var/list/datum/job/occupations = list() + //List of all jobs + var/list/datum/job/occupation_with_excludes = list() + //Players who need jobs + var/list/mob/new_player/unassigned = list() + var/list/datum/job/occupations_by_name = list() //Dict of all jobs, keys are titles var/list/type_occupations = list() //Dict of all jobs, keys are types var/list/department_datums = list() + var/list/job_icon_cache = list() var/debug_messages = FALSE +/datum/controller/subsystem/job/proc/get_all_job_icons() //For all existing HUD icons + return occupation_with_excludes + GLOB.alt_titles_with_icons + list("Prisoner") + /datum/controller/subsystem/job/Initialize() - if(!length(department_datums)) - setup_departments() - if(!length(occupations)) - setup_occupations() + setup_departments() + setup_occupations() return SS_INIT_SUCCESS /datum/controller/subsystem/job/proc/setup_occupations(faction = FACTION_STATION) - occupations = list() + occupations.Cut() var/list/all_jobs = subtypesof(/datum/job) if(!length(all_jobs)) to_chat(world, span_warning("Error setting up jobs, no job datums found")) return FALSE - for(var/J in all_jobs) - var/datum/job/job = new J() - if(!job) - continue + for(var/job_path in all_jobs) + var/datum/job/job = new job_path() if(job.faction != faction) continue occupations += job - name_occupations[job.title] = job - type_occupations[J] = job + if(!(is_type_in_list(job, GLOB.exclude_jobs))) + occupation_with_excludes += job + occupations_by_name[job.title] = job + type_occupations[job_path] = job if(LAZYLEN(job.departments)) add_to_departments(job) sortTim(occupations, GLOBAL_PROC_REF(cmp_job_datums)) - for(var/D in department_datums) - var/datum/department/dept = department_datums[D] + for(var/department, value in department_datums) + var/datum/department/dept = value sortTim(dept.jobs, GLOBAL_PROC_REF(cmp_job_datums), TRUE) sortTim(dept.primary_jobs, GLOBAL_PROC_REF(cmp_job_datums), TRUE) @@ -80,7 +87,12 @@ SUBSYSTEM_DEF(job) return dept_datums /datum/controller/subsystem/job/proc/get_job(rank) - return name_occupations[rank] + if(!rank) + return null + return occupations_by_name[rank] + +/datum/controller/subsystem/job/proc/get_player_alt_title(mob/new_player/player, rank) + return player.client.prefs.GetPlayerAltTitle(get_job(rank)) /datum/controller/subsystem/job/proc/get_job_type(jobtype) return type_occupations[jobtype] @@ -139,3 +151,908 @@ SUBSYSTEM_DEF(job) /datum/controller/subsystem/job/proc/job_debug_message(message) if(debug_messages) log_world("JOB DEBUG: [message]") + +/datum/controller/subsystem/job/proc/assign_role(mob/new_player/player, rank, latejoin = FALSE) + job_debug_message("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") + if(player && player.mind && rank) + var/datum/job/job = get_job(rank) + if(!job) + return FALSE + if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) + return FALSE + if(jobban_isbanned(player, rank)) + return FALSE + if(!job.player_old_enough(player.client)) + return FALSE + if(!job.player_has_enough_playtime(player.client)) + return FALSE + if(!is_job_whitelisted(player, rank)) + return FALSE + + var/position_limit = job.total_positions + if(!latejoin) + position_limit = job.spawn_positions + if((job.current_positions < position_limit) || position_limit == -1) + job_debug_message("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") + player.mind.assigned_role = rank + player.mind.role_alt_title = get_player_alt_title(player, rank) + unassigned -= player + job.current_positions++ + return TRUE + job_debug_message("AR has failed, Player: [player], Rank: [rank]") + return FALSE + +/datum/controller/subsystem/job/proc/free_role(rank) //making additional slot on the fly + var/datum/job/job = get_job(rank) + if(job && job.total_positions != -1) + job.total_positions++ + return TRUE + return FALSE + +/datum/controller/subsystem/job/proc/update_limit(rank, comperator) + var/datum/job/job = get_job(rank) + if(job && job.total_positions != -1) + job.update_limit(comperator) + return TRUE + return FALSE + +/datum/controller/subsystem/job/proc/find_occupation_candidate(datum/job/job, level, flag) + job_debug_message("Running FOC, Job: [job], Level: [level], Flag: [flag]") + var/list/candidates = list() + for(var/mob/new_player/player in unassigned) + if(jobban_isbanned(player, job.title)) + job_debug_message("FOC isbanned failed, Player: [player]") + continue + if(!job.player_old_enough(player.client)) + job_debug_message("FOC player not old enough, Player: [player]") + continue + if(job.minimum_character_age && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) + job_debug_message("FOC character not old enough, Player: [player]") + continue + //VOREStation Code Start + if(!job.player_has_enough_playtime(player.client)) + job_debug_message("FOC character not enough playtime, Player: [player]") + continue + if(!is_job_whitelisted(player, job.title)) + job_debug_message("FOC is_job_whitelisted failed, Player: [player]") + continue + //VOREStation Code End + if(flag && !(player.client.prefs.be_special & flag)) + job_debug_message("FOC flag failed, Player: [player], Flag: [flag], ") + continue + if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + job_debug_message("FOC pass, Player: [player], Level:[level]") + candidates += player + return candidates + +/datum/controller/subsystem/job/proc/give_random_job(mob/new_player/player) + job_debug_message("GRJ Giving random job, Player: [player]") + for(var/datum/job/job in shuffle(occupations)) + if(!job) + continue + + if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) + continue + + if(istype(job, get_job(JOB_ALT_VISITOR))) // We don't want to give him assistant, that's boring! //VOREStation Edit - Visitor not Assistant + continue + + if(SSjob.is_job_in_department(job.title, DEPARTMENT_COMMAND)) //If you want a command position, select it! + continue + + if(jobban_isbanned(player, job.title)) + job_debug_message("GRJ isbanned failed, Player: [player], Job: [job.title]") + continue + + if(!job.player_old_enough(player.client)) + job_debug_message("GRJ player not old enough, Player: [player]") + continue + + if(!job.player_has_enough_playtime(player.client)) + job_debug_message("GRJ player not enough playtime, Player: [player]") + continue + if(!is_job_whitelisted(player, job.title)) + job_debug_message("GRJ player not whitelisted for this job, Player: [player], Job: [job.title]") + continue + + if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) + job_debug_message("GRJ Random job given, Player: [player], Job: [job]") + assign_role(player, job.title) + unassigned -= player + break + +/datum/controller/subsystem/job/proc/reset_occupations() + for(var/mob/new_player/player in GLOB.player_list) + if((player) && (player.mind)) + player.mind.assigned_role = null + player.mind.special_role = null + setup_occupations() + unassigned = list() + return + +///This proc is called before the level loop of DivideOccupations() and will try to select a head, ignoring ALL non-head preferences for every level until it locates a head or runs out of levels to check +/datum/controller/subsystem/job/proc/fill_head_position() + for(var/level = 1 to 3) + for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) + var/datum/job/job = get_job(command_position) + if(!job) + continue + var/list/candidates = find_occupation_candidate(job, level) + if(!length(candidates)) + continue + + // Build a weighted list, weight by age. + var/list/weightedCandidates = list() + for(var/mob/mob_candidate in candidates) + // Log-out during round-start? What a bad boy, no head position for you! + if(!mob_candidate.client) + continue + var/age = mob_candidate.read_preference(/datum/preference/numeric/human/age) + + if(age < job.get_min_age(mob_candidate.client.prefs.read_preference(/datum/preference/choiced/species), mob_candidate.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN])) // Nope. + continue + + var/idealage = job.get_ideal_age(mob_candidate.client.prefs.read_preference(/datum/preference/choiced/species), mob_candidate.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]) + var/agediff = abs(idealage - age) // Compute the absolute difference in age from target + switch(agediff) /// If the math sucks, it's because I almost failed algebra in high school. + if(20 to INFINITY) + weightedCandidates[mob_candidate] = 3 // Too far off + if(10 to 20) + weightedCandidates[mob_candidate] = 6 // Nearer the mark, but not quite + if(0 to 10) + weightedCandidates[mob_candidate] = 10 // On the mark + else + // If there's ABSOLUTELY NOBODY ELSE + if(length(candidates) == 1) + weightedCandidates[mob_candidate] = 1 + + + var/mob/new_player/candidate = pickweight(weightedCandidates) + if(assign_role(candidate, command_position)) + return TRUE + return FALSE + +///This proc is called at the start of the level loop of DivideOccupations() and will cause head jobs to be checked before any other jobs of the same level +/datum/controller/subsystem/job/proc/check_head_position(level) + for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) + var/datum/job/job = get_job(command_position) + if(!job) + continue + var/list/candidates = find_occupation_candidate(job, level) + if(!length(candidates)) + continue + var/mob/new_player/candidate = pick(candidates) + assign_role(candidate, command_position) + +/** Proc DivideOccupations + * fills var "assigned_role" for all ready players. + * This proc must not have any side effect besides of modifying "assigned_role". + **/ +/datum/controller/subsystem/job/proc/divide_occupations() + //Setup new player list and get the jobs list + job_debug_message("Running DO") + setup_occupations() + + //Holder for Triumvirate is stored in the ticker, this just processes it + if(SSticker && GLOB.triai) + for(var/datum/job/A in occupations) + if(A.title == JOB_AI) + A.spawn_positions = 3 + break + + //Get the players who are ready + for(var/mob/new_player/player in GLOB.player_list) + if(player.ready && player.mind && !player.mind.assigned_role) + unassigned += player + + job_debug_message("DO, Len: [length(unassigned)]") + if(!length(unassigned)) + return FALSE + + //Shuffle players and jobs + unassigned = shuffle(unassigned) + + handle_feedback_gathering() + + //People who wants to be assistants, sure, go on. + job_debug_message("DO, Running Assistant Check 1") + var/datum/job/assist = new DEFAULT_JOB_TYPE () + var/list/assistant_candidates = find_occupation_candidate(assist, 3) + job_debug_message("AC1, Candidates: [length(assistant_candidates)]") + for(var/mob/new_player/player in assistant_candidates) + job_debug_message("AC1 pass, Player: [player]") + assign_role(player, JOB_ALT_VISITOR) //VOREStation Edit - Visitor not Assistant + assistant_candidates -= player + job_debug_message("DO, AC1 end") + + //Select one head + job_debug_message("DO, Running Head Check") + fill_head_position() + job_debug_message("DO, Head Check end") + + //Other jobs are now checked + job_debug_message("DO, Running Standard Check") + + + // New job giving system by Donkie + // This will cause lots of more loops, but since it's only done once it shouldn't really matter much at all. + // Hopefully this will add more randomness and fairness to job giving. + + // Loop through all levels from high to low + var/list/shuffledoccupations = shuffle(occupations) + // var/list/disabled_jobs = SSticker.mode.disabled_jobs // So we can use .Find down below without a colon. + for(var/level = 1 to 3) + //Check the head jobs first each level + check_head_position(level) + + // Loop through all unassigned players + for(var/mob/new_player/player in unassigned) + + // Loop through all jobs + for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY + if(!job || SSticker.mode.disabled_jobs.Find(job.title) ) + continue + + if(jobban_isbanned(player, job.title)) + job_debug_message("DO isbanned failed, Player: [player], Job:[job.title]") + continue + + if(!job.player_old_enough(player.client)) + job_debug_message("DO player not old enough, Player: [player], Job:[job.title]") + continue + + //VOREStation Add + if(!job.player_has_enough_playtime(player.client)) + job_debug_message("DO player not enough playtime, Player: [player]") + continue + //VOREStation Add End + + // If the player wants that job on this level, then try give it to him. + if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + + // If the job isn't filled + if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) + job_debug_message("DO pass, Player: [player], Level:[level], Job:[job.title]") + assign_role(player, job.title) + unassigned -= player + break + + // Hand out random jobs to the people who didn't get any in the last check + // Also makes sure that they got their preference correct + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == GET_RANDOM_JOB) + give_random_job(player) + + job_debug_message("DO, Standard Check end") + + job_debug_message("DO, Running AC2") + + // For those who wanted to be assistant if their preferences were filled, here you go. + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == BE_ASSISTANT) + job_debug_message("AC2 Assistant located, Player: [player]") + assign_role(player, JOB_ALT_VISITOR) //VOREStation Edit - Visitor not Assistant + + //For ones returning to lobby + for(var/mob/new_player/player in unassigned) + if(player.client.prefs.alternate_option == RETURN_TO_LOBBY) + player.ready = PLAYER_NOT_READY + unassigned -= player + return TRUE + +/datum/controller/subsystem/job/proc/equip_rank(mob/living/carbon/human/human_mob, rank, joined_late = 0, announce = TRUE) + if(!human_mob) + return null + + var/datum/job/job = get_job(rank) + var/list/spawn_in_storage = list() + + if(!joined_late) + var/obj/spawn_point = null + var/list/possible_spawns = list() + for(var/obj/effect/landmark/start/sloc in GLOB.landmarks_list) + if(sloc.name != rank) continue + if(locate(/mob/living) in sloc.loc) continue + possible_spawns.Add(sloc) + if(length(possible_spawns)) + spawn_point = pick(possible_spawns) + if(!spawn_point) + spawn_point = locate("start*[rank]") // use old stype + if(istype(spawn_point, /obj/effect/landmark/start) && istype(spawn_point.loc, /turf)) + human_mob.forceMove(spawn_point.loc) + else + var/list/spawn_props = late_spawn(human_mob.client, rank) + var/turf/spawn_turf = spawn_props["turf"] + if(!spawn_turf) + to_chat(human_mob, span_critical("You were unable to be spawned at your chosen late-join spawnpoint. Please verify your job/spawn point combination makes sense, and try another one.")) + return + else + human_mob.forceMove(spawn_turf) + + // Moving wheelchair if they have one + if(human_mob.buckled && istype(human_mob.buckled, /obj/structure/bed/chair/wheelchair)) + human_mob.buckled.forceMove(human_mob.loc) + human_mob.buckled.set_dir(human_mob.dir) + + if(job) + + //Equip custom gear loadout. + var/list/custom_equip_slots = list() + var/list/custom_equip_leftovers = list() + if(human_mob?.client?.prefs && !(job.mob_type & JOB_SILICON)) + var/list/active_gear_list = LAZYACCESS(human_mob.client.prefs.gear_list, "[human_mob.client.prefs.gear_slot]") + for(var/thing in active_gear_list) + var/datum/gear/gaar_thing = GLOB.gear_datums[thing] + if(!gaar_thing) //Not a real gear datum (maybe removed, as this is loaded from their savefile) + continue + + var/permitted + // Check if it is restricted to certain roles + if(gaar_thing.allowed_roles) + for(var/job_name in gaar_thing.allowed_roles) + if(job.title == job_name) + permitted = TRUE + else + permitted = TRUE + + // Check if they're whitelisted for this gear (in alien whitelist? seriously?) + if(gaar_thing.whitelisted && !is_alien_whitelisted(human_mob.client, GLOB.all_species[gaar_thing.whitelisted])) + permitted = FALSE + + // If they aren't, tell them + if(!permitted) + to_chat(human_mob, span_warning("Your current species, job or whitelist status does not permit you to spawn with [thing]!")) + continue + + // Implants get special treatment + if(gaar_thing.slot == "implant") + var/obj/item/implant/gear_implant = gaar_thing.spawn_item(human_mob, active_gear_list[gaar_thing.display_name]) + gear_implant.invisibility = INVISIBILITY_MAXIMUM + gear_implant.implant_loadout(human_mob) + continue + + // Try desperately (and sorta poorly) to equip the item. Now with increased desperation! + if(gaar_thing.slot && !(gaar_thing.slot in custom_equip_slots)) + var/metadata = active_gear_list[gaar_thing.display_name] + //if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head) + // custom_equip_leftovers += thing + //else + if(gaar_thing.slot == slot_wear_suit && human_mob.client?.prefs?.no_jacket) + continue + if(gaar_thing.slot == slot_shoes && human_mob.client?.prefs?.shoe_hater) //RS ADD + continue + if(human_mob.equip_to_slot_or_del(gaar_thing.spawn_item(human_mob, metadata), gaar_thing.slot)) + to_chat(human_mob, span_notice("Equipping you with \the [thing]!")) + if(gaar_thing.slot != slot_tie) + custom_equip_slots.Add(gaar_thing.slot) + else + custom_equip_leftovers.Add(thing) + else + spawn_in_storage += thing + + // Set up their account + job.setup_account(human_mob) + + // Equip job items. + job.equip(human_mob, human_mob.mind ? human_mob.mind.role_alt_title : "") + + // Stick their fingerprints on literally everything + job.apply_fingerprints(human_mob) + + // Only non-silicons get post-job-equip equipment and dormant diseases + if(!(job.mob_type & JOB_SILICON)) + human_mob.equip_post_job() + human_mob.give_random_dormant_disease(guaranteed_symptoms = job.symptoms) + + // If some custom items could not be equipped before, try again now. + for(var/thing in custom_equip_leftovers) + var/datum/gear/gear_thing = GLOB.gear_datums[thing] + if(gear_thing.slot == slot_wear_suit && human_mob.client?.prefs?.no_jacket) + continue + if(gear_thing.slot == slot_shoes && human_mob.client?.prefs?.shoe_hater) + continue + if(gear_thing.slot in custom_equip_slots) + spawn_in_storage += thing + else + var/list/active_gear_list = LAZYACCESS(human_mob.client.prefs.gear_list, "[human_mob.client.prefs.gear_slot]") + var/metadata = active_gear_list[gear_thing.display_name] + if(human_mob.equip_to_slot_or_del(gear_thing.spawn_item(human_mob, metadata), gear_thing.slot)) + to_chat(human_mob, span_notice("Equipping you with \the [thing]!")) + custom_equip_slots.Add(gear_thing.slot) + else + spawn_in_storage += thing + + //Give new players a welcome guide! + if(isnum(human_mob.client?.player_age) && human_mob.client.player_age < 10) + human_mob.equip_to_slot_or_del(new /obj/item/book/manual/virgo_pamphlet(human_mob), slot_r_hand) + else + to_chat(human_mob, span_filter_notice("Your job is [rank] and the game just can't handle it! Please report this bug to an administrator.")) + + human_mob.job = rank + log_game("JOINED [key_name(human_mob)] as \"[rank]\"") + log_game("SPECIES [key_name(human_mob)] is a: \"[human_mob.species.name]\"") //VOREStation Add + + // If they're head, give them the account info for their department + if(human_mob.mind && job.department_accounts) + var/remembered_info = "" + for(var/job_department in job.department_accounts) + var/datum/money_account/department_account = GLOB.department_accounts[job_department] + if(department_account) + remembered_info += span_bold("Department account number ([job_department]):") + " #[department_account.account_number]
" + remembered_info += span_bold("Department account pin ([job_department]):") + " [department_account.remote_access_pin]
" + remembered_info += span_bold("Department account funds ([job_department]):") + " $[department_account.money]
" + + human_mob.mind.store_memory(remembered_info) + + var/alt_title = null + if(human_mob.mind) + human_mob.mind.assigned_role = rank + alt_title = human_mob.mind.role_alt_title + + // If we're a silicon, we may be done at this point + if(job.mob_type & JOB_SILICON_ROBOT) + return human_mob.Robotize() + if(job.mob_type & JOB_SILICON_AI) + return human_mob + + // TWEET PEEP + if(rank == JOB_SITE_MANAGER && announce) + var/sound/announce_sound = (SSticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20) + GLOB.captain_announcement.Announce("All hands, [alt_title ? alt_title : JOB_SITE_MANAGER] [human_mob.real_name] on deck!", new_sound = announce_sound, zlevel = human_mob.z) + + //Deferred item spawning. + if(spawn_in_storage && length(spawn_in_storage)) + var/obj/item/storage/storage_bag + for(var/obj/item/storage/worn_bag in human_mob.contents) + storage_bag = worn_bag + break + + var/list/active_gear_list = LAZYACCESS(human_mob.client.prefs.gear_list, "[human_mob.client.prefs.gear_slot]") + if(!isnull(storage_bag)) + for(var/thing in spawn_in_storage) + to_chat(human_mob, span_notice("Placing \the [thing] in your [storage_bag.name]!")) + var/datum/gear/gear_thing = GLOB.gear_datums[thing] + var/metadata = active_gear_list[gear_thing.display_name] + gear_thing.spawn_item(storage_bag, metadata) + else + to_chat(human_mob, span_danger("Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.")) + + if(istype(human_mob)) //give humans wheelchairs, if they need them. + var/obj/item/organ/external/l_foot = human_mob.get_organ(BP_L_FOOT) + var/obj/item/organ/external/r_foot = human_mob.get_organ(BP_R_FOOT) + var/obj/item/storage/storage_bag = locate() in human_mob.contents + var/obj/item/wheelchair/used_wheelchair + if(storage_bag) + used_wheelchair = locate() in storage_bag.contents + if(!l_foot || !r_foot || used_wheelchair) + var/wheelchair_type = used_wheelchair?.unfolded_type || /obj/structure/bed/chair/wheelchair + var/obj/structure/bed/chair/wheelchair/active_wheelchair = new wheelchair_type(human_mob.loc) + active_wheelchair.buckle_mob(human_mob) + human_mob.update_canmove() + active_wheelchair.set_dir(human_mob.dir) + active_wheelchair.add_fingerprint(human_mob) + if(used_wheelchair) + active_wheelchair.color = used_wheelchair.color + qdel(used_wheelchair) + + to_chat(human_mob, span_filter_notice(span_bold("You are [job.total_positions == 1 ? "the" : "a"] [alt_title ? alt_title : rank]."))) + + if(job.supervisors) + to_chat(human_mob, span_filter_notice(span_bold("As the [alt_title ? alt_title : rank] you answer directly to [job.supervisors]. Special circumstances may change this."))) + if(job.has_headset) + human_mob.equip_to_slot_or_del(new /obj/item/radio/headset(human_mob), slot_l_ear) + to_chat(human_mob, span_filter_notice(span_bold("To speak on your department's radio channel use :h. For the use of other channels, examine your headset."))) + + if(job.req_admin_notify) + to_chat(human_mob, span_filter_notice(span_bold("You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp."))) + + // EMAIL GENERATION + // Email addresses will be created under this domain name. Mostly for the looks. + var/domain = "freemail.nt" + if(using_map && LAZYLEN(using_map.usable_email_tlds)) + domain = using_map.usable_email_tlds[1] + var/sanitized_name = sanitize(replacetext(replacetext(lowertext(human_mob.real_name), " ", "."), "'", "")) + var/complete_login = "[sanitized_name]@[domain]" + + // It is VERY unlikely that we'll have two players, in the same round, with the same name and branch, but still, this is here. + // If such conflict is encountered, a random number will be appended to the email address. If this fails too, no email account will be created. + if(GLOB.ntnet_global.does_email_exist(complete_login)) + complete_login = "[sanitized_name][random_id(/datum/computer_file/data/email_account/, 100, 999)]@[domain]" + + // If even fallback login generation failed, just don't give them an email. The chance of this happening is astronomically low. + if(GLOB.ntnet_global.does_email_exist(complete_login)) + to_chat(human_mob, span_filter_notice("You were not assigned an email address.")) + human_mob.mind.store_memory("You were not assigned an email address.") + else + var/datum/computer_file/data/email_account/user_mail_acc = new/datum/computer_file/data/email_account() + user_mail_acc.password = GenerateKey() + user_mail_acc.login = complete_login + to_chat(human_mob, span_filter_notice("Your email account address is " + span_bold("[user_mail_acc.login]") + " and the password is " + span_bold("[user_mail_acc.password]") + ". This information has also been placed into your notes.")) + human_mob.mind.store_memory("Your email account address is [user_mail_acc.login] and the password is [user_mail_acc.password].") + // END EMAIL GENERATION + + //Gives glasses to the vision impaired + if(human_mob.disabilities & NEARSIGHTED) + var/equipped = human_mob.equip_to_slot_or_del(new /obj/item/clothing/glasses/regular(human_mob), slot_glasses) + if(equipped != 1) + var/obj/item/clothing/glasses/worn_glasses = human_mob.glasses + worn_glasses.prescription = TRUE + + BITSET(human_mob.hud_updateflag, ID_HUD) + BITSET(human_mob.hud_updateflag, IMPLOYAL_HUD) + BITSET(human_mob.hud_updateflag, SPECIALROLE_HUD) + return human_mob + +/datum/controller/subsystem/job/proc/handle_feedback_gathering() + for(var/datum/job/job in occupations) + var/tmp_str = "|[job.title]|" + + var/level1 = 0 //high + var/level2 = 0 //medium + var/level3 = 0 //low + var/level4 = 0 //never + var/level5 = 0 //banned + var/level6 = 0 //account too young + for(var/mob/new_player/player in GLOB.player_list) + if(!(player.ready && player.mind && !player.mind.assigned_role)) + continue //This player is not ready + if(jobban_isbanned(player, job.title)) + level5++ + continue + if(!job.player_old_enough(player.client)) + level6++ + continue + if(!job.player_has_enough_playtime(player.client)) + level6++ + continue + if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) + level1++ + else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) + level2++ + else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag) + level3++ + else level4++ //not selected + + tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-" + feedback_add_details("job_preferences",tmp_str) + +/datum/controller/subsystem/job/proc/late_spawn(client/spawn_client, rank) + + var/datum/spawnpoint/spawnpos + var/fail_deadly = FALSE + var/obj/belly/vore_spawn_gut + var/absorb_choice = FALSE // Ability to start absorbed with vorespawn + var/mob/living/prey_to_nomph + var/obj/item/item_to_be // Item TF spawning + var/mob/living/item_carrier // Capture crystal spawning + var/vorgans = FALSE // capture crystal simplemob spawning + + // Remove fail_deadly addition on offmap_spawn + + //Spawn them at their preferred one + if(spawn_client?.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)) + if(spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Vorespawn - Prey") + var/list/preds = list() + var/list/pred_names = list() //This is cringe + for(var/client/current_client in GLOB.clients) + if(!isliving(current_client.mob)) + continue + var/mob/living/current_mob = current_client.mob + if(current_mob.stat == UNCONSCIOUS || current_mob.stat == DEAD || (current_mob.client.is_afk(10 MINUTES) && !current_mob.no_latejoin_vore_warning)) + continue + if(!current_mob.latejoin_vore) + continue + if(!(current_mob.z in using_map.vorespawn_levels)) + continue + preds += current_mob + pred_names += current_mob.real_name //very cringe + + if(length(preds)) + var/pred_name = tgui_input_list(spawn_client, "Choose a Predator.", "Pred Spawnpoint", pred_names) + if(!pred_name) + return + var/index = pred_names.Find(pred_name) + var/mob/living/pred = preds[index] + var/list/available_bellies = list() + for(var/obj/belly/current_belly in pred.vore_organs) + if(current_belly.vorespawn_blacklist) + continue + if(LAZYLEN(current_belly.vorespawn_whitelist) && !(spawn_client.ckey in current_belly.vorespawn_whitelist)) + continue + available_bellies += current_belly + var/backup = tgui_alert(spawn_client, "Do you want a mind backup?", "Confirm", list("Yes", "No")) + if(backup == "Yes") + backup = 1 + vore_spawn_gut = tgui_input_list(spawn_client, "Choose a Belly.", "Belly Spawnpoint", available_bellies) + if(!vore_spawn_gut) + return + if(vore_spawn_gut.vorespawn_absorbed & VS_FLAG_ABSORB_YES) + absorb_choice = TRUE + if(vore_spawn_gut.vorespawn_absorbed & VS_FLAG_ABSORB_PREY) + if(tgui_alert(spawn_client, "Do you want to start absorbed into [pred]'s [vore_spawn_gut]?", "Confirm", list("Yes", "No")) != "Yes") + absorb_choice = FALSE + else if(tgui_alert(spawn_client, "[pred]'s [vore_spawn_gut] will start with you absorbed. Continue?", "Confirm", list("Yes", "No")) != "Yes") + return + to_chat(spawn_client, span_boldwarning("[pred] has received your spawn request. Please wait.")) + log_admin("[key_name(spawn_client)] has requested to vore spawn into [key_name(pred)]") + message_admins("[key_name(spawn_client)] has requested to vore spawn into [key_name(pred)]") + + var/confirm + var/spawner_name = spawn_client.prefs.read_preference(/datum/preference/name/real_name) + if(pred.no_latejoin_vore_warning) + if(pred.no_latejoin_vore_warning_time > 0) + if(absorb_choice) + confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn absorbed as your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), pred.no_latejoin_vore_warning_time SECONDS) + else + confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn into your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), pred.no_latejoin_vore_warning_time SECONDS) + if(!confirm) + confirm = "Yes" + else + if(absorb_choice) + confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn absorbed as your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) + else + confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn into your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) + if(confirm != "Yes") + to_chat(spawn_client, span_warning("[pred] has declined your spawn request.")) + var/message = tgui_input_text(pred,"Do you want to leave them a message?", "Notify Prey", max_length = MAX_MESSAGE_LEN) + if(message) + to_chat(spawn_client, span_notice("[pred] message : [message]")) + return + if(!vore_spawn_gut || QDELETED(vore_spawn_gut)) + to_chat(spawn_client, span_warning("Somehow, the belly you were trying to enter no longer exists.")) + return + if(pred.stat == UNCONSCIOUS || pred.stat == DEAD) + to_chat(spawn_client, span_warning("[pred] is not conscious.")) + to_chat(pred, span_warning("You must be conscious to accept.")) + return + if(!(pred.z in using_map.vorespawn_levels)) + to_chat(spawn_client, span_warning("[pred] is no longer in station grounds.")) + to_chat(pred, span_warning("You must be within station grounds to accept.")) + return + if(backup) + addtimer(CALLBACK(src, PROC_REF(m_backup_client), spawn_client), 5 SECONDS) + log_admin("[key_name(spawn_client)] has vore spawned into [key_name(pred)]") + message_admins("[key_name(spawn_client)] has vore spawned into [key_name(pred)]") + to_chat(spawn_client, span_notice("You have been spawned via vore. You are free to roleplay how you got there as you please, such as teleportation or having had already been there.")) + if(vore_spawn_gut.entrance_logs) + to_chat(pred, span_notice("Your prey has spawned via vore. You are free to roleplay this how you please, such as teleportation or having had already been there.")) + else + to_chat(spawn_client, span_warning("No predators were available to accept you.")) + return + spawnpos = GLOB.spawntypes[spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)] + if(spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Vorespawn - Pred") //Same as above, but in reverse! + var/list/preys = list() + var/list/prey_names = list() //This is still cringe + for(var/client/current_client in GLOB.clients) + if(!isliving(current_client.mob)) + continue + var/mob/living/current_mob = current_client.mob + if(current_mob.stat == UNCONSCIOUS || current_mob.stat == DEAD || (current_mob.client.is_afk(10 MINUTES) && !current_mob.no_latejoin_prey_warning)) + continue + if(!current_mob.latejoin_prey) + continue + if(!(current_mob.z in using_map.vorespawn_levels)) + continue + preys += current_mob + prey_names += current_mob.real_name + if(length(preys)) + var/prey_name = tgui_input_list(spawn_client, "Choose a Prey to spawn nom.", "Prey Spawnpoint", prey_names) + if(!prey_name) + return + var/index = prey_names.Find(prey_name) + var/mob/living/prey = preys[index] + var/list/available_bellies = list() + + var/datum/vore_preferences/spawn_preferences = spawn_client.prefs_vr + for(var/preference in spawn_preferences.belly_prefs) + available_bellies += preference["name"] + vore_spawn_gut = tgui_input_list(spawn_client, "Choose your Belly.", "Belly Spawnpoint", available_bellies) + if(!vore_spawn_gut) + return + if(alert(spawn_client, "Do you want to instantly absorb them?", "Confirm", "Yes", "No") == "Yes") + absorb_choice = TRUE + to_chat(spawn_client, span_boldwarning("[prey] has received your spawn request. Please wait.")) + log_admin("[key_name(spawn_client)] has requested to pred spawn onto [key_name(prey)]") + message_admins("[key_name(spawn_client)] has requested to pred spawn onto [key_name(prey)]") + + var/confirm + var/spawner_name = spawn_client.prefs.read_preference(/datum/preference/name/real_name) + if(prey.no_latejoin_prey_warning) + if(prey.no_latejoin_prey_warning_time > 0) + if(absorb_choice) + confirm = tgui_alert(prey, "[spawner_name] is attempting to televore and instantly absorb you with their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), prey.no_latejoin_prey_warning_time SECONDS) + else + confirm = tgui_alert(prey, "[spawner_name] is attempting to televore you into their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), prey.no_latejoin_prey_warning_time SECONDS) + if(!confirm) + confirm = "Yes" + else + if(absorb_choice) + confirm = tgui_alert(prey, "[spawner_name] is attempting to televore and instantly absorb you with their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) + else + confirm = tgui_alert(prey, "[spawner_name] is attempting to televore you into their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) + if(confirm != "Yes") + to_chat(spawn_client, span_warning("[prey] has declined your spawn request.")) + var/message = tgui_input_text(prey,"Do you want to leave them a message?", "Notify Pred", max_length = MAX_MESSAGE_LEN) + if(message) + to_chat(spawn_client, span_notice("[prey] message : [message]")) + return + if(prey.stat == UNCONSCIOUS || prey.stat == DEAD) + to_chat(spawn_client, span_warning("[prey] is not conscious.")) + to_chat(prey, span_warning("You must be conscious to accept.")) + return + if(!(prey.z in using_map.vorespawn_levels)) + to_chat(spawn_client, span_warning("[prey] is no longer in station grounds.")) + to_chat(prey, span_warning("You must be within station grounds to accept.")) + return + log_admin("[key_name(spawn_client)] has pred spawned onto [key_name(prey)]") + message_admins("[key_name(spawn_client)] has pred spawned onto [key_name(prey)]") + prey_to_nomph = prey + else + to_chat(spawn_client, span_warning("No prey were available to accept you.")) + return + // Item TF spawnpoints! + else if(spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Item TF spawn") + var/list/items = list() + var/list/item_names = list() + var/list/carriers = list() + for(var/obj/item/item_spawnpoint in GLOB.item_tf_spawnpoints) + if(LAZYLEN(item_spawnpoint.ckeys_allowed_itemspawn)) + if(!(spawn_client.ckey in item_spawnpoint.ckeys_allowed_itemspawn)) + continue + var/atom/item_loc = item_spawnpoint.loc + var/mob/living/carrier + while(!isturf(item_loc)) + if(isliving(item_loc)) + carrier = item_loc + break + else + item_loc = item_loc.loc + if(istype(carrier)) + if(!(carrier.z in using_map.vorespawn_levels)) + continue + if(carrier.stat == UNCONSCIOUS || carrier.stat == DEAD || carrier.client.is_afk(10 MINUTES)) + continue + carriers += carrier + else + if(!(item_loc.z in using_map.vorespawn_levels)) + continue + carriers += null + + if(istype(item_spawnpoint, /obj/item/capture_crystal)) + if(carrier) + items += item_spawnpoint + var/obj/item/capture_crystal/cryst = item_spawnpoint + if(cryst.spawn_mob_type) + item_names += "\a [cryst.spawn_mob_name] inside of [carrier]'s [item_spawnpoint.name] ([item_spawnpoint.loc.name])" + else + item_names += "Inside of [carrier]'s [item_spawnpoint.name] ([item_spawnpoint.loc.name])" + else if(item_spawnpoint.name == initial(item_spawnpoint.name)) + items += item_spawnpoint + if(carrier) + item_names += "[carrier]'s [item_spawnpoint.name] ([item_spawnpoint.loc.name])" + else + item_names += "[item_spawnpoint.name] ([item_spawnpoint.loc.name])" + else + items += item_spawnpoint + if(carrier) + item_names += "[carrier]'s [item_spawnpoint.name] (\a [initial(item_spawnpoint.name)] at [item_spawnpoint.loc.name])" + else + item_names += "[item_spawnpoint.name] (\a [initial(item_spawnpoint.name)] at [item_spawnpoint.loc.name])" + if(LAZYLEN(items)) + var/backup = tgui_alert(spawn_client, "Do you want a mind backup?", "Confirm", list("Yes", "No")) + if(backup == "Yes") + backup = TRUE + var/item_name = tgui_input_list(spawn_client, "Choose an Item to spawn as.", "Item TF Spawnpoint", item_names) + if(!item_name) + return + var/index = item_names.Find(item_name) + var/obj/item/item = items[index] + + var/mob/living/carrier = carriers[index] + if(istype(carrier)) + to_chat(spawn_client, span_boldwarning("[carrier] has received your spawn request. Please wait.")) + log_and_message_admins("[key_name(spawn_client)] has requested to item spawn into [key_name(carrier)]'s possession") + + var/confirm = tgui_alert(carrier, "[spawn_client.prefs.read_preference(/datum/preference/name/real_name)] is attempting to join as the [item_name] in your possession.", "Confirm", list("No", "Yes")) + if(confirm != "Yes") + to_chat(spawn_client, span_warning("[carrier] has declined your spawn request.")) + var/message = tgui_input_text(carrier,"Do you want to leave them a message?", "Notify Spawner", max_length = MAX_MESSAGE_LEN) + if(message) + to_chat(spawn_client, span_notice("[carrier] message : [message]")) + return + if(carrier.stat == UNCONSCIOUS || carrier.stat == DEAD) + to_chat(spawn_client, span_warning("[carrier] is not conscious.")) + to_chat(carrier, span_warning("You must be conscious to accept.")) + return + if(!(carrier.z in using_map.vorespawn_levels)) + to_chat(spawn_client, span_warning("[carrier] is no longer in station grounds.")) + to_chat(carrier, span_warning("You must be within station grounds to accept.")) + return + log_and_message_admins("[key_name(spawn_client)] has item spawned onto [key_name(carrier)]") + item_to_be = item + item_carrier = carrier + if(backup) + addtimer(CALLBACK(src, PROC_REF(m_backup_client), spawn_client), 5 SECONDS) + else + var/confirm = tgui_alert(spawn_client, "\The [item.name] is currently not in any character's possession! Do you still want to spawn as it?", "Confirm", list("No", "Yes")) + if(confirm != "Yes") + return + log_and_message_admins("[key_name(spawn_client)] has item spawned into \a [item.name] that was not held by anyone") + item_to_be = item + if(backup) + addtimer(CALLBACK(src, PROC_REF(m_backup_client), spawn_client), 5 SECONDS) + if(istype(item, /obj/item/capture_crystal)) + var/obj/item/capture_crystal/cryst = item + if(cryst.spawn_mob_type) + var/confirm = tgui_alert(spawn_client, "Do you want to spawn with your slot's vore organs and prefs?", "Confirm", list("No", "Yes")) + if(confirm == "Yes") + vorgans = TRUE + else + to_chat(spawn_client, span_warning("No items were available to accept you.")) + return + else + if(!(spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) in using_map.allowed_spawns)) + if(fail_deadly) + to_chat(spawn_client, span_warning("Your chosen spawnpoint is unavailable for this map and your job requires a specific spawnpoint. Please correct your spawn point choice.")) + return + else + to_chat(spawn_client, span_warning("Your chosen spawnpoint ([spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead.")) + spawnpos = null + else + spawnpos = GLOB.spawntypes[spawn_client.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)] + + //We will return a list key'd by "turf" and "msg" + . = list("turf","msg", "voreny", "prey", "itemtf", "vorgans", "carrier") // Item TF spawnpoints, spawn as mob + if(vore_spawn_gut) + .["voreny"] = vore_spawn_gut + .["absorb"] = absorb_choice + if(prey_to_nomph) + .["prey"] = prey_to_nomph //We pass this on later to reverse the vorespawn in new_player.dm + // Item TF spawnpoints + if(item_to_be) + .["carrier"] = item_carrier + .["vorgans"] = vorgans + .["itemtf"] = item_to_be + if(spawnpos && istype(spawnpos) && length(spawnpos.turfs)) + if(spawnpos.check_job_spawning(rank)) + .["turf"] = spawnpos.get_spawn_position() + .["msg"] = spawnpos.msg + .["channel"] = spawnpos.announce_channel + else + var/datum/job/job_rank = SSjob.get_job(rank) + if(fail_deadly || job_rank?.offmap_spawn) + to_chat(spawn_client, span_warning("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Please correct your spawn point choice.")) + return + to_chat(spawn_client, span_filter_warning("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")) + var/spawning = pick(GLOB.latejoin) + .["turf"] = get_turf(spawning) + .["msg"] = "will arrive at the station shortly" + else if(!fail_deadly) + var/spawning = pick(GLOB.latejoin) + .["turf"] = get_turf(spawning) + .["msg"] = "has arrived on the station" + +/datum/controller/subsystem/job/proc/m_backup_client(client/target_client) //Same as m_backup, but takes a client entry. Used for vore late joining. + if(!ishuman(target_client.mob)) + return + var/mob/living/carbon/human/target_human = target_client.mob + SStranscore.m_backup(target_human.mind, target_human.nif, TRUE) + +/datum/controller/subsystem/job/proc/get_all_jobs() + var/list/all_jobs = list() + for(var/datum/job/current_job as anything in occupation_with_excludes) + all_jobs += current_job.title + return all_jobs + +/datum/controller/subsystem/job/proc/get_all_centcom_jobs() + return list("VIP Guest", + "Custodian", + "Thunderdome Overseer", + "Intel Officer", + "Medical Officer", + "Death Commando", + "Research Officer", + "BlackOps Commander", + "Supreme Commander", + "Emergency Response Team", + "Emergency Response Team Leader") diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm index 97e5f99311..e219fb20d9 100644 --- a/code/controllers/subsystems/persist_vr.dm +++ b/code/controllers/subsystems/persist_vr.dm @@ -108,10 +108,10 @@ SUBSYSTEM_DEF(persist) if(R) // We found someone with a record. var/recorded_rank = R.fields["real_rank"] if(recorded_rank) - . = GLOB.job_master.GetJob(recorded_rank) + . = SSjob.get_job(recorded_rank) if(.) return // They have a custom title, aren't crew, or someone deleted their record, so we need a fallback method. // Let's check the mind. if(M.mind && M.mind.assigned_role) - . = GLOB.job_master.GetJob(M.mind.assigned_role) + . = SSjob.get_job(M.mind.assigned_role) diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index ca072b059f..173ccda950 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -312,16 +312,16 @@ SUBSYSTEM_DEF(ticker) to_chat(world, span_boldannounce("Serious error in mode setup! Reverting to pregame lobby.")) //Uses setup instead of set up due to computational context. return 0 - GLOB.job_master.ResetOccupations() + SSjob.reset_occupations() src.mode.create_antagonists() src.mode.pre_setup() - GLOB.job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. + SSjob.divide_occupations() // Apparently important for new antagonist system to register specific job antags properly. if(!src.mode.can_start()) to_chat(world, span_filter_system(span_bold("Unable to start [mode.name].") + " Not enough players readied, [CONFIG_GET(keyed_list/player_requirements)[mode.config_tag]] players needed. Reverting to pregame lobby.")) mode.fail_setup() mode = null - GLOB.job_master.ResetOccupations() + SSjob.reset_occupations() return 0 if(hide_mode) @@ -367,7 +367,7 @@ SUBSYSTEM_DEF(ticker) // Ask their new_player mob to spawn them if(!player.spawn_checks_vr(player.mind.assigned_role)) - var/datum/job/job_datum = GLOB.job_master.GetJob(J.title) + var/datum/job/job_datum = SSjob.get_job(J.title) job_datum.current_positions-- player.mind.assigned_role = null continue //VOREStation Add @@ -404,7 +404,7 @@ SUBSYSTEM_DEF(ticker) if(player.mind.assigned_role == JOB_SITE_MANAGER) captainless=0 if(!SSantag_job.player_is_antag(player.mind, only_offstation_roles = 1)) - GLOB.job_master.EquipRank(player, player.mind.assigned_role, 0) + SSjob.equip_rank(player, player.mind.assigned_role, 0) UpdateFactionList(player) //equip_custom_items(player) //VOREStation Removal //player.apply_traits() //VOREStation Removal diff --git a/code/datums/mind.dm b/code/datums/mind.dm index e200e4efd2..f17d77a80f 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -194,7 +194,7 @@ if(antag) antag.place_mob(src.current) else if (href_list["role_edit"]) - var/new_role = tgui_input_list(usr, "Select new role", "Assigned role", assigned_role, GLOB.joblist) + var/new_role = tgui_input_list(usr, "Select new role", "Assigned role", assigned_role, SSjob.occupations_by_name) if (!new_role) return assigned_role = new_role diff --git a/code/datums/outfits/jobs/job.dm b/code/datums/outfits/jobs/job.dm index 571c2ec828..8cc486d513 100644 --- a/code/datums/outfits/jobs/job.dm +++ b/code/datums/outfits/jobs/job.dm @@ -20,7 +20,7 @@ var/obj/item/card/id/C = ..() if(!C) return - var/datum/job/J = GLOB.job_master.GetJob(rank) + var/datum/job/J = SSjob.get_job(rank) if(J) C.access = J.get_access() if(H.mind) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 158cdf50e5..b039896581 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -94,7 +94,7 @@ return C.registered_name /proc/get_all_job_icons() //For all existing HUD icons - return GLOB.joblist + GLOB.alt_titles_with_icons + list("Prisoner") + return SSjob.occupations_by_name + GLOB.alt_titles_with_icons + list("Prisoner") /obj/proc/GetJobName() //Used in secHUD icon generation var/obj/item/card/id/I = GetID() diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index aaabb2d45f..b4da026d6e 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -173,7 +173,7 @@ return message /datum/job/proc/get_job_icon() - if(!GLOB.job_master.job_icons[title]) + if(!SSjob.job_icon_cache[title]) var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin("#job_icon") dress_mannequin(mannequin) mannequin.dir = SOUTH @@ -181,9 +181,9 @@ var/icon/preview_icon = getFlatIcon(mannequin) preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. - GLOB.job_master.job_icons[title] = preview_icon + SSjob.job_icon_cache[title] = preview_icon - return GLOB.job_master.job_icons[title] + return SSjob.job_icon_cache[title] /datum/job/proc/dress_mannequin(var/mob/living/carbon/human/dummy/mannequin/mannequin) mannequin.delete_inventory(TRUE) diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm deleted file mode 100644 index e5baaf6913..0000000000 --- a/code/game/jobs/job_controller.dm +++ /dev/null @@ -1,986 +0,0 @@ -GLOBAL_DATUM(job_master, /datum/controller/occupations) - -/datum/controller/occupations - //List of all jobs - var/list/occupations = list() - //Players who need jobs - var/list/unassigned = list() - //Debug info - var/list/job_debug = list() - //Cache of icons for job info window - var/list/job_icons = list() - -/datum/controller/occupations/proc/SetupOccupations(var/faction = FACTION_STATION) - occupations = list() - //var/list/all_jobs = typesof(/datum/job) - var/list/all_jobs = list(/datum/job/assistant) | using_map.allowed_jobs - if(!all_jobs.len) - to_chat(world, span_boldannounce("Error setting up jobs, no job datums found!")) - return 0 - for(var/J in all_jobs) - var/datum/job/job = new J() - if(!job) continue - if(job.faction != faction) continue - occupations += job - sortTim(occupations, GLOBAL_PROC_REF(cmp_job_datums)) - - - return 1 - - -/datum/controller/occupations/proc/Debug(var/text) - if(!GLOB.Debug2) return 0 - job_debug.Add(text) - return 1 - - -/datum/controller/occupations/proc/GetJob(var/rank) - if(!rank) return null - for(var/datum/job/J in occupations) - if(!J) continue - if(J.title == rank) return J - return null - -/datum/controller/occupations/proc/GetPlayerAltTitle(mob/new_player/player, rank) - return player.client.prefs.GetPlayerAltTitle(GetJob(rank)) - -/datum/controller/occupations/proc/AssignRole(var/mob/new_player/player, var/rank, var/latejoin = 0) - Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") - if(player && player.mind && rank) - var/datum/job/job = GetJob(rank) - if(!job) - return 0 - if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) - return 0 - if(jobban_isbanned(player, rank)) - return 0 - if(!job.player_old_enough(player.client)) - return 0 - //VOREStation Add - if(!job.player_has_enough_playtime(player.client)) - return 0 - if(!is_job_whitelisted(player, rank)) - return 0 - //VOREStation Add End - - var/position_limit = job.total_positions - if(!latejoin) - position_limit = job.spawn_positions - if((job.current_positions < position_limit) || position_limit == -1) - Debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") - player.mind.assigned_role = rank - player.mind.role_alt_title = GetPlayerAltTitle(player, rank) - unassigned -= player - job.current_positions++ - return 1 - Debug("AR has failed, Player: [player], Rank: [rank]") - return 0 - -/datum/controller/occupations/proc/FreeRole(var/rank) //making additional slot on the fly - var/datum/job/job = GetJob(rank) - if(job && job.total_positions != -1) - job.total_positions++ - return 1 - return 0 - -/datum/controller/occupations/proc/update_limit(var/rank, var/comperator) - var/datum/job/job = GetJob(rank) - if(job && job.total_positions != -1) - job.update_limit(comperator) - return 1 - return 0 - -/datum/controller/occupations/proc/FindOccupationCandidates(datum/job/job, level, flag) - Debug("Running FOC, Job: [job], Level: [level], Flag: [flag]") - var/list/candidates = list() - for(var/mob/new_player/player in unassigned) - if(jobban_isbanned(player, job.title)) - Debug("FOC isbanned failed, Player: [player]") - continue - if(!job.player_old_enough(player.client)) - Debug("FOC player not old enough, Player: [player]") - continue - if(job.minimum_character_age && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) - Debug("FOC character not old enough, Player: [player]") - continue - //VOREStation Code Start - if(!job.player_has_enough_playtime(player.client)) - Debug("FOC character not enough playtime, Player: [player]") - continue - if(!is_job_whitelisted(player, job.title)) - Debug("FOC is_job_whitelisted failed, Player: [player]") - continue - //VOREStation Code End - if(flag && !(player.client.prefs.be_special & flag)) - Debug("FOC flag failed, Player: [player], Flag: [flag], ") - continue - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) - Debug("FOC pass, Player: [player], Level:[level]") - candidates += player - return candidates - -/datum/controller/occupations/proc/GiveRandomJob(var/mob/new_player/player) - Debug("GRJ Giving random job, Player: [player]") - for(var/datum/job/job in shuffle(occupations)) - if(!job) - continue - - if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) - continue - - if(istype(job, GetJob(JOB_ALT_VISITOR))) // We don't want to give him assistant, that's boring! //VOREStation Edit - Visitor not Assistant - continue - - if(SSjob.is_job_in_department(job.title, DEPARTMENT_COMMAND)) //If you want a command position, select it! - continue - - if(jobban_isbanned(player, job.title)) - Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") - continue - - if(!job.player_old_enough(player.client)) - Debug("GRJ player not old enough, Player: [player]") - continue - - //VOREStation Code Start - if(!job.player_has_enough_playtime(player.client)) - Debug("GRJ player not enough playtime, Player: [player]") - continue - if(!is_job_whitelisted(player, job.title)) - Debug("GRJ player not whitelisted for this job, Player: [player], Job: [job.title]") - continue - //VOREStation Code End - - if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) - Debug("GRJ Random job given, Player: [player], Job: [job]") - AssignRole(player, job.title) - unassigned -= player - break - -/datum/controller/occupations/proc/ResetOccupations() - for(var/mob/new_player/player in GLOB.player_list) - if((player) && (player.mind)) - player.mind.assigned_role = null - player.mind.special_role = null - SetupOccupations() - unassigned = list() - return - - -///This proc is called before the level loop of DivideOccupations() and will try to select a head, ignoring ALL non-head preferences for every level until it locates a head or runs out of levels to check -/datum/controller/occupations/proc/FillHeadPosition() - for(var/level = 1 to 3) - for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) - var/datum/job/job = GetJob(command_position) - if(!job) continue - var/list/candidates = FindOccupationCandidates(job, level) - if(!candidates.len) continue - - // Build a weighted list, weight by age. - var/list/weightedCandidates = list() - for(var/mob/V in candidates) - // Log-out during round-start? What a bad boy, no head position for you! - if(!V.client) continue - var/age = V.read_preference(/datum/preference/numeric/human/age) - - if(age < job.get_min_age(V.client.prefs.read_preference(/datum/preference/choiced/species), V.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN])) // Nope. - continue - - var/idealage = job.get_ideal_age(V.client.prefs.read_preference(/datum/preference/choiced/species), V.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]) - var/agediff = abs(idealage - age) // Compute the absolute difference in age from target - switch(agediff) /// If the math sucks, it's because I almost failed algebra in high school. - if(20 to INFINITY) - weightedCandidates[V] = 3 // Too far off - if(10 to 20) - weightedCandidates[V] = 6 // Nearer the mark, but not quite - if(0 to 10) - weightedCandidates[V] = 10 // On the mark - else - // If there's ABSOLUTELY NOBODY ELSE - if(candidates.len == 1) weightedCandidates[V] = 1 - - - var/mob/new_player/candidate = pickweight(weightedCandidates) - if(AssignRole(candidate, command_position)) - return 1 - return 0 - - -///This proc is called at the start of the level loop of DivideOccupations() and will cause head jobs to be checked before any other jobs of the same level -/datum/controller/occupations/proc/CheckHeadPositions(var/level) - for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) - var/datum/job/job = GetJob(command_position) - if(!job) continue - var/list/candidates = FindOccupationCandidates(job, level) - if(!candidates.len) continue - var/mob/new_player/candidate = pick(candidates) - AssignRole(candidate, command_position) - return - - -/** Proc DivideOccupations - * fills var "assigned_role" for all ready players. - * This proc must not have any side effect besides of modifying "assigned_role". - **/ -/datum/controller/occupations/proc/DivideOccupations() - //Setup new player list and get the jobs list - Debug("Running DO") - SetupOccupations() - - //Holder for Triumvirate is stored in the ticker, this just processes it - if(SSticker && GLOB.triai) - for(var/datum/job/A in occupations) - if(A.title == JOB_AI) - A.spawn_positions = 3 - break - - //Get the players who are ready - for(var/mob/new_player/player in GLOB.player_list) - if(player.ready && player.mind && !player.mind.assigned_role) - unassigned += player - - Debug("DO, Len: [unassigned.len]") - if(unassigned.len == 0) return 0 - - //Shuffle players and jobs - unassigned = shuffle(unassigned) - - HandleFeedbackGathering() - - //People who wants to be assistants, sure, go on. - Debug("DO, Running Assistant Check 1") - var/datum/job/assist = new DEFAULT_JOB_TYPE () - var/list/assistant_candidates = FindOccupationCandidates(assist, 3) - Debug("AC1, Candidates: [assistant_candidates.len]") - for(var/mob/new_player/player in assistant_candidates) - Debug("AC1 pass, Player: [player]") - AssignRole(player, JOB_ALT_VISITOR) //VOREStation Edit - Visitor not Assistant - assistant_candidates -= player - Debug("DO, AC1 end") - - //Select one head - Debug("DO, Running Head Check") - FillHeadPosition() - Debug("DO, Head Check end") - - //Other jobs are now checked - Debug("DO, Running Standard Check") - - - // New job giving system by Donkie - // This will cause lots of more loops, but since it's only done once it shouldn't really matter much at all. - // Hopefully this will add more randomness and fairness to job giving. - - // Loop through all levels from high to low - var/list/shuffledoccupations = shuffle(occupations) - // var/list/disabled_jobs = SSticker.mode.disabled_jobs // So we can use .Find down below without a colon. - for(var/level = 1 to 3) - //Check the head jobs first each level - CheckHeadPositions(level) - - // Loop through all unassigned players - for(var/mob/new_player/player in unassigned) - - // Loop through all jobs - for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY - if(!job || SSticker.mode.disabled_jobs.Find(job.title) ) - continue - - if(jobban_isbanned(player, job.title)) - Debug("DO isbanned failed, Player: [player], Job:[job.title]") - continue - - if(!job.player_old_enough(player.client)) - Debug("DO player not old enough, Player: [player], Job:[job.title]") - continue - - //VOREStation Add - if(!job.player_has_enough_playtime(player.client)) - Debug("DO player not enough playtime, Player: [player]") - continue - //VOREStation Add End - - // If the player wants that job on this level, then try give it to him. - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) - - // If the job isn't filled - if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) - Debug("DO pass, Player: [player], Level:[level], Job:[job.title]") - AssignRole(player, job.title) - unassigned -= player - break - - // Hand out random jobs to the people who didn't get any in the last check - // Also makes sure that they got their preference correct - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == GET_RANDOM_JOB) - GiveRandomJob(player) - /* - Old job system - for(var/level = 1 to 3) - for(var/datum/job/job in occupations) - Debug("Checking job: [job]") - if(!job) - continue - if(!unassigned.len) - break - if((job.current_positions >= job.spawn_positions) && job.spawn_positions != -1) - continue - var/list/candidates = FindOccupationCandidates(job, level) - while(candidates.len && ((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)) - var/mob/new_player/candidate = pick(candidates) - Debug("Selcted: [candidate], for: [job.title]") - AssignRole(candidate, job.title) - candidates -= candidate*/ - - Debug("DO, Standard Check end") - - Debug("DO, Running AC2") - - // For those who wanted to be assistant if their preferences were filled, here you go. - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == BE_ASSISTANT) - Debug("AC2 Assistant located, Player: [player]") - AssignRole(player, JOB_ALT_VISITOR) //VOREStation Edit - Visitor not Assistant - - //For ones returning to lobby - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == RETURN_TO_LOBBY) - player.ready = PLAYER_NOT_READY - unassigned -= player - return 1 - - -/datum/controller/occupations/proc/EquipRank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0, var/announce = TRUE) - if(!H) return null - - var/datum/job/job = GetJob(rank) - var/list/spawn_in_storage = list() - - if(!joined_late) - var/obj/S = null - var/list/possible_spawns = list() - for(var/obj/effect/landmark/start/sloc in GLOB.landmarks_list) - if(sloc.name != rank) continue - if(locate(/mob/living) in sloc.loc) continue - possible_spawns.Add(sloc) - if(possible_spawns.len) - S = pick(possible_spawns) - if(!S) - S = locate("start*[rank]") // use old stype - if(istype(S, /obj/effect/landmark/start) && istype(S.loc, /turf)) - H.forceMove(S.loc) - else - var/list/spawn_props = LateSpawn(H.client, rank) - var/turf/T = spawn_props["turf"] - if(!T) - to_chat(H, span_critical("You were unable to be spawned at your chosen late-join spawnpoint. Please verify your job/spawn point combination makes sense, and try another one.")) - return - else - H.forceMove(T) - - // Moving wheelchair if they have one - if(H.buckled && istype(H.buckled, /obj/structure/bed/chair/wheelchair)) - H.buckled.forceMove(H.loc) - H.buckled.set_dir(H.dir) - - if(job) - - //Equip custom gear loadout. - var/list/custom_equip_slots = list() - var/list/custom_equip_leftovers = list() - if(H?.client?.prefs && !(job.mob_type & JOB_SILICON)) - var/list/active_gear_list = LAZYACCESS(H.client.prefs.gear_list, "[H.client.prefs.gear_slot]") - for(var/thing in active_gear_list) - var/datum/gear/G = GLOB.gear_datums[thing] - if(!G) //Not a real gear datum (maybe removed, as this is loaded from their savefile) - continue - - var/permitted - // Check if it is restricted to certain roles - if(G.allowed_roles) - for(var/job_name in G.allowed_roles) - if(job.title == job_name) - permitted = 1 - else - permitted = 1 - - // Check if they're whitelisted for this gear (in alien whitelist? seriously?) - if(G.whitelisted && !is_alien_whitelisted(H.client, GLOB.all_species[G.whitelisted])) - permitted = 0 - - // If they aren't, tell them - if(!permitted) - to_chat(H, span_warning("Your current species, job or whitelist status does not permit you to spawn with [thing]!")) - continue - - // Implants get special treatment - if(G.slot == "implant") - var/obj/item/implant/I = G.spawn_item(H, active_gear_list[G.display_name]) - I.invisibility = INVISIBILITY_MAXIMUM - I.implant_loadout(H) - continue - - // Try desperately (and sorta poorly) to equip the item. Now with increased desperation! - if(G.slot && !(G.slot in custom_equip_slots)) - var/metadata = active_gear_list[G.display_name] - //if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head) - // custom_equip_leftovers += thing - //else - if(G.slot == slot_wear_suit && H.client?.prefs?.no_jacket) - continue - if(G.slot == slot_shoes && H.client?.prefs?.shoe_hater) //RS ADD - continue - if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) - to_chat(H, span_notice("Equipping you with \the [thing]!")) - if(G.slot != slot_tie) - custom_equip_slots.Add(G.slot) - else - custom_equip_leftovers.Add(thing) - else - spawn_in_storage += thing - - // Set up their account - job.setup_account(H) - - // Equip job items. - job.equip(H, H.mind ? H.mind.role_alt_title : "") - - // Stick their fingerprints on literally everything - job.apply_fingerprints(H) - - // Only non-silicons get post-job-equip equipment and dormant diseases - if(!(job.mob_type & JOB_SILICON)) - H.equip_post_job() - H.give_random_dormant_disease(guaranteed_symptoms = job.symptoms) - - // If some custom items could not be equipped before, try again now. - for(var/thing in custom_equip_leftovers) - var/datum/gear/G = GLOB.gear_datums[thing] - if(G.slot == slot_wear_suit && H.client?.prefs?.no_jacket) - continue - if(G.slot == slot_shoes && H.client?.prefs?.shoe_hater) //RS ADD - continue - if(G.slot in custom_equip_slots) - spawn_in_storage += thing - else - var/list/active_gear_list = LAZYACCESS(H.client.prefs.gear_list, "[H.client.prefs.gear_slot]") - var/metadata = active_gear_list[G.display_name] - if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) - to_chat(H, span_notice("Equipping you with \the [thing]!")) - custom_equip_slots.Add(G.slot) - else - spawn_in_storage += thing - - //Give new players a welcome guide! - if(isnum(H.client?.player_age) && H.client.player_age < 10) - H.equip_to_slot_or_del(new /obj/item/book/manual/virgo_pamphlet(H), slot_r_hand) - else - to_chat(H, span_filter_notice("Your job is [rank] and the game just can't handle it! Please report this bug to an administrator.")) - - H.job = rank - log_game("JOINED [key_name(H)] as \"[rank]\"") - log_game("SPECIES [key_name(H)] is a: \"[H.species.name]\"") //VOREStation Add - - // If they're head, give them the account info for their department - if(H.mind && job.department_accounts) - var/remembered_info = "" - for(var/D in job.department_accounts) - var/datum/money_account/department_account = GLOB.department_accounts[D] - if(department_account) - remembered_info += span_bold("Department account number ([D]):") + " #[department_account.account_number]
" - remembered_info += span_bold("Department account pin ([D]):") + " [department_account.remote_access_pin]
" - remembered_info += span_bold("Department account funds ([D]):") + " $[department_account.money]
" - - H.mind.store_memory(remembered_info) - - var/alt_title = null - if(H.mind) - H.mind.assigned_role = rank - alt_title = H.mind.role_alt_title - - // If we're a silicon, we may be done at this point - if(job.mob_type & JOB_SILICON_ROBOT) - return H.Robotize() - if(job.mob_type & JOB_SILICON_AI) - return H - - // TWEET PEEP - if(rank == JOB_SITE_MANAGER && announce) - var/sound/announce_sound = (SSticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20) - GLOB.captain_announcement.Announce("All hands, [alt_title ? alt_title : JOB_SITE_MANAGER] [H.real_name] on deck!", new_sound = announce_sound, zlevel = H.z) - - //Deferred item spawning. - if(spawn_in_storage && spawn_in_storage.len) - var/obj/item/storage/B - for(var/obj/item/storage/S in H.contents) - B = S - break - - var/list/active_gear_list = LAZYACCESS(H.client.prefs.gear_list, "[H.client.prefs.gear_slot]") - if(!isnull(B)) - for(var/thing in spawn_in_storage) - to_chat(H, span_notice("Placing \the [thing] in your [B.name]!")) - var/datum/gear/G = GLOB.gear_datums[thing] - var/metadata = active_gear_list[G.display_name] - G.spawn_item(B, metadata) - else - to_chat(H, span_danger("Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.")) - - if(istype(H)) //give humans wheelchairs, if they need them. - var/obj/item/organ/external/l_foot = H.get_organ(BP_L_FOOT) - var/obj/item/organ/external/r_foot = H.get_organ(BP_R_FOOT) - var/obj/item/storage/S = locate() in H.contents - var/obj/item/wheelchair/R - if(S) - R = locate() in S.contents - if(!l_foot || !r_foot || R) - var/wheelchair_type = R?.unfolded_type || /obj/structure/bed/chair/wheelchair - var/obj/structure/bed/chair/wheelchair/W = new wheelchair_type(H.loc) - W.buckle_mob(H) - H.update_canmove() - W.set_dir(H.dir) - W.add_fingerprint(H) - if(R) - W.color = R.color - qdel(R) - - to_chat(H, span_filter_notice(span_bold("You are [job.total_positions == 1 ? "the" : "a"] [alt_title ? alt_title : rank]."))) - - if(job.supervisors) - to_chat(H, span_filter_notice(span_bold("As the [alt_title ? alt_title : rank] you answer directly to [job.supervisors]. Special circumstances may change this."))) - if(job.has_headset) - H.equip_to_slot_or_del(new /obj/item/radio/headset(H), slot_l_ear) - to_chat(H, span_filter_notice(span_bold("To speak on your department's radio channel use :h. For the use of other channels, examine your headset."))) - - if(job.req_admin_notify) - to_chat(H, span_filter_notice(span_bold("You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp."))) - - // EMAIL GENERATION - // Email addresses will be created under this domain name. Mostly for the looks. - var/domain = "freemail.nt" - if(using_map && LAZYLEN(using_map.usable_email_tlds)) - domain = using_map.usable_email_tlds[1] - var/sanitized_name = sanitize(replacetext(replacetext(lowertext(H.real_name), " ", "."), "'", "")) - var/complete_login = "[sanitized_name]@[domain]" - - // It is VERY unlikely that we'll have two players, in the same round, with the same name and branch, but still, this is here. - // If such conflict is encountered, a random number will be appended to the email address. If this fails too, no email account will be created. - if(GLOB.ntnet_global.does_email_exist(complete_login)) - complete_login = "[sanitized_name][random_id(/datum/computer_file/data/email_account/, 100, 999)]@[domain]" - - // If even fallback login generation failed, just don't give them an email. The chance of this happening is astronomically low. - if(GLOB.ntnet_global.does_email_exist(complete_login)) - to_chat(H, span_filter_notice("You were not assigned an email address.")) - H.mind.store_memory("You were not assigned an email address.") - else - var/datum/computer_file/data/email_account/EA = new/datum/computer_file/data/email_account() - EA.password = GenerateKey() - EA.login = complete_login - to_chat(H, span_filter_notice("Your email account address is [EA.login] and the password is [EA.password]. This information has also been placed into your notes.")) - H.mind.store_memory("Your email account address is [EA.login] and the password is [EA.password].") - // END EMAIL GENERATION - - //Gives glasses to the vision impaired - if(H.disabilities & NEARSIGHTED) - var/equipped = H.equip_to_slot_or_del(new /obj/item/clothing/glasses/regular(H), slot_glasses) - if(equipped != 1) - var/obj/item/clothing/glasses/G = H.glasses - G.prescription = TRUE - - BITSET(H.hud_updateflag, ID_HUD) - BITSET(H.hud_updateflag, IMPLOYAL_HUD) - BITSET(H.hud_updateflag, SPECIALROLE_HUD) - return H - -/datum/controller/occupations/proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist - if(!CONFIG_GET(flag/load_jobs_from_txt)) - return 0 - - var/list/jobEntries = world.file2list(jobsfile) - - for(var/job in jobEntries) - if(!job) - continue - - job = trim(job) - if (!length(job)) - continue - - var/pos = findtext(job, "=") - var/name = null - var/value = null - - if(pos) - name = copytext(job, 1, pos) - value = copytext(job, pos + 1) - else - continue - - if(name && value) - var/datum/job/J = GetJob(name) - if(!J) continue - J.total_positions = text2num(value) - J.spawn_positions = text2num(value) - if(J.mob_type & JOB_SILICON) - J.total_positions = 0 - - return 1 - - -/datum/controller/occupations/proc/HandleFeedbackGathering() - for(var/datum/job/job in occupations) - var/tmp_str = "|[job.title]|" - - var/level1 = 0 //high - var/level2 = 0 //medium - var/level3 = 0 //low - var/level4 = 0 //never - var/level5 = 0 //banned - var/level6 = 0 //account too young - for(var/mob/new_player/player in GLOB.player_list) - if(!(player.ready && player.mind && !player.mind.assigned_role)) - continue //This player is not ready - if(jobban_isbanned(player, job.title)) - level5++ - continue - if(!job.player_old_enough(player.client)) - level6++ - continue - //VOREStation Add - if(!job.player_has_enough_playtime(player.client)) - level6++ - continue - //VOREStation Add End - if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) - level1++ - else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) - level2++ - else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag) - level3++ - else level4++ //not selected - - tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-" - feedback_add_details("job_preferences",tmp_str) - -/datum/controller/occupations/proc/LateSpawn(var/client/C, var/rank) - - var/datum/spawnpoint/spawnpos - var/fail_deadly = FALSE - var/obj/belly/vore_spawn_gut - var/absorb_choice = FALSE // Ability to start absorbed with vorespawn - var/mob/living/prey_to_nomph - var/obj/item/item_to_be // Item TF spawning - var/mob/living/item_carrier // Capture crystal spawning - var/vorgans = FALSE // capture crystal simplemob spawning - - // Remove fail_deadly addition on offmap_spawn - - //Spawn them at their preferred one - if(C && C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)) - if(C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Vorespawn - Prey") - var/list/preds = list() - var/list/pred_names = list() //This is cringe - for(var/client/V in GLOB.clients) - if(!isliving(V.mob)) - continue - var/mob/living/M = V.mob - if(M.stat == UNCONSCIOUS || M.stat == DEAD || (M.client.is_afk(10 MINUTES) && !M.no_latejoin_vore_warning)) - continue - if(!M.latejoin_vore) - continue - if(!(M.z in using_map.vorespawn_levels)) - continue - preds += M - pred_names += M.real_name //very cringe - - if(preds.len) - var/pred_name = tgui_input_list(C, "Choose a Predator.", "Pred Spawnpoint", pred_names) - if(!pred_name) - return - var/index = pred_names.Find(pred_name) - var/mob/living/pred = preds[index] - var/list/available_bellies = list() - for(var/obj/belly/Y in pred.vore_organs) - if(Y.vorespawn_blacklist) - continue - if(LAZYLEN(Y.vorespawn_whitelist) && !(C.ckey in Y.vorespawn_whitelist)) - continue - available_bellies += Y - var/backup = tgui_alert(C, "Do you want a mind backup?", "Confirm", list("Yes", "No")) - if(backup == "Yes") - backup = 1 - vore_spawn_gut = tgui_input_list(C, "Choose a Belly.", "Belly Spawnpoint", available_bellies) - if(!vore_spawn_gut) - return - if(vore_spawn_gut.vorespawn_absorbed & VS_FLAG_ABSORB_YES) - absorb_choice = TRUE - if(vore_spawn_gut.vorespawn_absorbed & VS_FLAG_ABSORB_PREY) - if(tgui_alert(C, "Do you want to start absorbed into [pred]'s [vore_spawn_gut]?", "Confirm", list("Yes", "No")) != "Yes") - absorb_choice = FALSE - else if(tgui_alert(C, "[pred]'s [vore_spawn_gut] will start with you absorbed. Continue?", "Confirm", list("Yes", "No")) != "Yes") - return - to_chat(C, span_boldwarning("[pred] has received your spawn request. Please wait.")) - log_admin("[key_name(C)] has requested to vore spawn into [key_name(pred)]") - message_admins("[key_name(C)] has requested to vore spawn into [key_name(pred)]") - - var/confirm - var/spawner_name = C.prefs.read_preference(/datum/preference/name/real_name) - if(pred.no_latejoin_vore_warning) - if(pred.no_latejoin_vore_warning_time > 0) - if(absorb_choice) - confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn absorbed as your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), pred.no_latejoin_vore_warning_time SECONDS) - else - confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn into your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), pred.no_latejoin_vore_warning_time SECONDS) - if(!confirm) - confirm = "Yes" - else - if(absorb_choice) - confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn absorbed as your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) - else - confirm = tgui_alert(pred, "[spawner_name] is attempting to spawn into your [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) - if(confirm != "Yes") - to_chat(C, span_warning("[pred] has declined your spawn request.")) - var/message = tgui_input_text(pred,"Do you want to leave them a message?", "Notify Prey", max_length = MAX_MESSAGE_LEN) - if(message) - to_chat(C, span_notice("[pred] message : [message]")) - return - if(!vore_spawn_gut || QDELETED(vore_spawn_gut)) - to_chat(C, span_warning("Somehow, the belly you were trying to enter no longer exists.")) - return - if(pred.stat == UNCONSCIOUS || pred.stat == DEAD) - to_chat(C, span_warning("[pred] is not conscious.")) - to_chat(pred, span_warning("You must be conscious to accept.")) - return - if(!(pred.z in using_map.vorespawn_levels)) - to_chat(C, span_warning("[pred] is no longer in station grounds.")) - to_chat(pred, span_warning("You must be within station grounds to accept.")) - return - if(backup) - addtimer(CALLBACK(src, PROC_REF(m_backup_client), C), 5 SECONDS) - log_admin("[key_name(C)] has vore spawned into [key_name(pred)]") - message_admins("[key_name(C)] has vore spawned into [key_name(pred)]") - to_chat(C, span_notice("You have been spawned via vore. You are free to roleplay how you got there as you please, such as teleportation or having had already been there.")) - if(vore_spawn_gut.entrance_logs) - to_chat(pred, span_notice("Your prey has spawned via vore. You are free to roleplay this how you please, such as teleportation or having had already been there.")) - else - to_chat(C, span_warning("No predators were available to accept you.")) - return - spawnpos = GLOB.spawntypes[C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)] - if(C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Vorespawn - Pred") //Same as above, but in reverse! - var/list/preys = list() - var/list/prey_names = list() //This is still cringe - for(var/client/V in GLOB.clients) - if(!isliving(V.mob)) - continue - var/mob/living/M = V.mob - if(M.stat == UNCONSCIOUS || M.stat == DEAD || (M.client.is_afk(10 MINUTES) && !M.no_latejoin_prey_warning)) - continue - if(!M.latejoin_prey) - continue - if(!(M.z in using_map.vorespawn_levels)) - continue - preys += M - prey_names += M.real_name - if(preys.len) - var/prey_name = tgui_input_list(C, "Choose a Prey to spawn nom.", "Prey Spawnpoint", prey_names) - if(!prey_name) - return - var/index = prey_names.Find(prey_name) - var/mob/living/prey = preys[index] - var/list/available_bellies = list() - - var/datum/vore_preferences/P = C.prefs_vr - for(var/Y in P.belly_prefs) - available_bellies += Y["name"] - vore_spawn_gut = tgui_input_list(C, "Choose your Belly.", "Belly Spawnpoint", available_bellies) - if(!vore_spawn_gut) - return - if(alert(C, "Do you want to instantly absorb them?", "Confirm", "Yes", "No") == "Yes") - absorb_choice = TRUE - to_chat(C, span_boldwarning("[prey] has received your spawn request. Please wait.")) - log_admin("[key_name(C)] has requested to pred spawn onto [key_name(prey)]") - message_admins("[key_name(C)] has requested to pred spawn onto [key_name(prey)]") - - var/confirm - var/spawner_name = C.prefs.read_preference(/datum/preference/name/real_name) - if(prey.no_latejoin_prey_warning) - if(prey.no_latejoin_prey_warning_time > 0) - if(absorb_choice) - confirm = tgui_alert(prey, "[spawner_name] is attempting to televore and instantly absorb you with their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), prey.no_latejoin_prey_warning_time SECONDS) - else - confirm = tgui_alert(prey, "[spawner_name] is attempting to televore you into their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes"), prey.no_latejoin_prey_warning_time SECONDS) - if(!confirm) - confirm = "Yes" - else - if(absorb_choice) - confirm = tgui_alert(prey, "[spawner_name] is attempting to televore and instantly absorb you with their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) - else - confirm = tgui_alert(prey, "[spawner_name] is attempting to televore you into their [vore_spawn_gut]. Let them?", "Confirm", list("No", "Yes")) - if(confirm != "Yes") - to_chat(C, span_warning("[prey] has declined your spawn request.")) - var/message = tgui_input_text(prey,"Do you want to leave them a message?", "Notify Pred", max_length = MAX_MESSAGE_LEN) - if(message) - to_chat(C, span_notice("[prey] message : [message]")) - return - if(prey.stat == UNCONSCIOUS || prey.stat == DEAD) - to_chat(C, span_warning("[prey] is not conscious.")) - to_chat(prey, span_warning("You must be conscious to accept.")) - return - if(!(prey.z in using_map.vorespawn_levels)) - to_chat(C, span_warning("[prey] is no longer in station grounds.")) - to_chat(prey, span_warning("You must be within station grounds to accept.")) - return - log_admin("[key_name(C)] has pred spawned onto [key_name(prey)]") - message_admins("[key_name(C)] has pred spawned onto [key_name(prey)]") - prey_to_nomph = prey - else - to_chat(C, span_warning("No prey were available to accept you.")) - return - // Item TF spawnpoints! - else if(C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) == "Item TF spawn") - var/list/items = list() - var/list/item_names = list() - var/list/carriers = list() - for(var/obj/item/I in GLOB.item_tf_spawnpoints) - if(LAZYLEN(I.ckeys_allowed_itemspawn)) - if(!(C.ckey in I.ckeys_allowed_itemspawn)) - continue - var/atom/item_loc = I.loc - var/mob/living/carrier - while(!isturf(item_loc)) - if(isliving(item_loc)) - carrier = item_loc - break - else - item_loc = item_loc.loc - if(istype(carrier)) - if(!(carrier.z in using_map.vorespawn_levels)) - continue - if(carrier.stat == UNCONSCIOUS || carrier.stat == DEAD || carrier.client.is_afk(10 MINUTES)) - continue - carriers += carrier - else - if(!(item_loc.z in using_map.vorespawn_levels)) - continue - carriers += null - - if(istype(I, /obj/item/capture_crystal)) - if(carrier) - items += I - var/obj/item/capture_crystal/cryst = I - if(cryst.spawn_mob_type) - item_names += "\a [cryst.spawn_mob_name] inside of [carrier]'s [I.name] ([I.loc.name])" - else - item_names += "Inside of [carrier]'s [I.name] ([I.loc.name])" - else if(I.name == initial(I.name)) - items += I - if(carrier) - item_names += "[carrier]'s [I.name] ([I.loc.name])" - else - item_names += "[I.name] ([I.loc.name])" - else - items += I - if(carrier) - item_names += "[carrier]'s [I.name] (\a [initial(I.name)] at [I.loc.name])" - else - item_names += "[I.name] (\a [initial(I.name)] at [I.loc.name])" - if(LAZYLEN(items)) - var/backup = tgui_alert(C, "Do you want a mind backup?", "Confirm", list("Yes", "No")) - if(backup == "Yes") - backup = 1 - var/item_name = tgui_input_list(C, "Choose an Item to spawn as.", "Item TF Spawnpoint", item_names) - if(!item_name) - return - var/index = item_names.Find(item_name) - var/obj/item/item = items[index] - - var/mob/living/carrier = carriers[index] - if(istype(carrier)) - to_chat(C, span_boldwarning("[carrier] has received your spawn request. Please wait.")) - log_and_message_admins("[key_name(C)] has requested to item spawn into [key_name(carrier)]'s possession") - - var/confirm = tgui_alert(carrier, "[C.prefs.read_preference(/datum/preference/name/real_name)] is attempting to join as the [item_name] in your possession.", "Confirm", list("No", "Yes")) - if(confirm != "Yes") - to_chat(C, span_warning("[carrier] has declined your spawn request.")) - var/message = tgui_input_text(carrier,"Do you want to leave them a message?", "Notify Spawner", max_length = MAX_MESSAGE_LEN) - if(message) - to_chat(C, span_notice("[carrier] message : [message]")) - return - if(carrier.stat == UNCONSCIOUS || carrier.stat == DEAD) - to_chat(C, span_warning("[carrier] is not conscious.")) - to_chat(carrier, span_warning("You must be conscious to accept.")) - return - if(!(carrier.z in using_map.vorespawn_levels)) - to_chat(C, span_warning("[carrier] is no longer in station grounds.")) - to_chat(carrier, span_warning("You must be within station grounds to accept.")) - return - log_and_message_admins("[key_name(C)] has item spawned onto [key_name(carrier)]") - item_to_be = item - item_carrier = carrier - if(backup) - addtimer(CALLBACK(src, PROC_REF(m_backup_client), C), 5 SECONDS) - else - var/confirm = tgui_alert(C, "\The [item.name] is currently not in any character's possession! Do you still want to spawn as it?", "Confirm", list("No", "Yes")) - if(confirm != "Yes") - return - log_and_message_admins("[key_name(C)] has item spawned into \a [item.name] that was not held by anyone") - item_to_be = item - if(backup) - addtimer(CALLBACK(src, PROC_REF(m_backup_client), C), 5 SECONDS) - if(istype(item, /obj/item/capture_crystal)) - var/obj/item/capture_crystal/cryst = item - if(cryst.spawn_mob_type) - var/confirm = tgui_alert(C, "Do you want to spawn with your slot's vore organs and prefs?", "Confirm", list("No", "Yes")) - if(confirm == "Yes") - vorgans = TRUE - else - to_chat(C, span_warning("No items were available to accept you.")) - return - else - if(!(C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint) in using_map.allowed_spawns)) - if(fail_deadly) - to_chat(C, span_warning("Your chosen spawnpoint is unavailable for this map and your job requires a specific spawnpoint. Please correct your spawn point choice.")) - return - else - to_chat(C, span_warning("Your chosen spawnpoint ([C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead.")) - spawnpos = null - else - spawnpos = GLOB.spawntypes[C.prefs.read_preference(/datum/preference/choiced/living/spawnpoint)] - - //We will return a list key'd by "turf" and "msg" - . = list("turf","msg", "voreny", "prey", "itemtf", "vorgans", "carrier") // Item TF spawnpoints, spawn as mob - if(vore_spawn_gut) - .["voreny"] = vore_spawn_gut - .["absorb"] = absorb_choice - if(prey_to_nomph) - .["prey"] = prey_to_nomph //We pass this on later to reverse the vorespawn in new_player.dm - // Item TF spawnpoints - if(item_to_be) - .["carrier"] = item_carrier - .["vorgans"] = vorgans - .["itemtf"] = item_to_be - if(spawnpos && istype(spawnpos) && length(spawnpos.turfs)) - if(spawnpos.check_job_spawning(rank)) - .["turf"] = spawnpos.get_spawn_position() - .["msg"] = spawnpos.msg - .["channel"] = spawnpos.announce_channel - else - var/datum/job/J = SSjob.get_job(rank) - if(fail_deadly || J?.offmap_spawn) - to_chat(C, span_warning("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Please correct your spawn point choice.")) - return - to_chat(C, span_filter_warning("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")) - var/spawning = pick(GLOB.latejoin) - .["turf"] = get_turf(spawning) - .["msg"] = "will arrive at the station shortly" - else if(!fail_deadly) - var/spawning = pick(GLOB.latejoin) - .["turf"] = get_turf(spawning) - .["msg"] = "has arrived on the station" - -/datum/controller/occupations/proc/m_backup_client(var/client/C) //Same as m_backup, but takes a client entry. Used for vore late joining. - if(!ishuman(C.mob)) - return - var/mob/living/carbon/human/CM = C.mob - SStranscore.m_backup(CM.mind, CM.nif, TRUE) diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index 3fdcf0a625..305c5d1e64 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -35,7 +35,7 @@ ADMIN_VERB(open_whitelist_editor, R_ADMIN|R_SERVER, "Open Whitelist Editor", "Op /datum/whitelist_editor/tgui_static_data(mob/user) var/list/whitelist_jobs = list() - for(var/datum/job/our_job in GLOB.job_master.occupations) + for(var/datum/job/our_job in SSjob.occupations) if(our_job.whitelist_only) whitelist_jobs += our_job.title @@ -75,7 +75,7 @@ ADMIN_VERB(open_whitelist_editor, R_ADMIN|R_SERVER, "Open Whitelist Editor", "Op var/role = params["role"] switch(kind) if("job") - var/datum/job/job = GLOB.job_master.GetJob(role) + var/datum/job/job = SSjob.get_job(role) if(!job) to_chat(ui.user, span_warning("Error, invalid job entered. Check spelling and capitalization.")) return FALSE @@ -292,7 +292,7 @@ ADMIN_VERB(open_whitelist_editor, R_ADMIN|R_SERVER, "Open Whitelist Editor", "Op /proc/is_job_whitelisted(mob/M, var/rank) // Check if the job actually requires a whitelist - var/datum/job/job = GLOB.job_master.GetJob(rank) + var/datum/job/job = SSjob.get_job(rank) if(!job.whitelist_only) return TRUE diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 7e2e195a2d..cecb7aea32 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -403,7 +403,7 @@ answer = text2num(answer) if(field == "rank") - if(answer in GLOB.joblist) + if(answer in SSjob.occupations_by_name) active1.fields["real_rank"] = answer if(field == "criminal") diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm index c554582ee7..67e35e5934 100644 --- a/code/game/machinery/computer/timeclock_vr.dm +++ b/code/game/machinery/computer/timeclock_vr.dm @@ -92,7 +92,7 @@ data["card"] = "[card]" data["assignment"] = card.assignment data["card_cooldown"] = getCooldown() - var/datum/job/job = GLOB.job_master.GetJob(card.rank) + var/datum/job/job = SSjob.get_job(card.rank) if(job) data["job_datum"] = list( "title" = job.title, @@ -146,7 +146,7 @@ /obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department) var/list/available_jobs = list() - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) if(isOpenOnDutyJob(user, department, job)) available_jobs[job.title] = list(job.title) if(job.alt_titles) @@ -167,8 +167,8 @@ && job.timeoff_factor > 0 /obj/machinery/computer/timeclock/proc/makeOnDuty(var/newrank, var/newassignment, var/mob/user) - var/datum/job/oldjob = GLOB.job_master.GetJob(card.rank) - var/datum/job/newjob = GLOB.job_master.GetJob(newrank) + var/datum/job/oldjob = SSjob.get_job(card.rank) + var/datum/job/newjob = SSjob.get_job(newrank) if(!oldjob || !isOpenOnDutyJob(user, oldjob.pto_type, newjob)) return if(newassignment != newjob.title && !(newassignment in newjob.alt_titles)) @@ -189,12 +189,12 @@ return /obj/machinery/computer/timeclock/proc/makeOffDuty(var/mob/user) - var/datum/job/foundjob = GLOB.job_master.GetJob(card.rank) + var/datum/job/foundjob = SSjob.get_job(card.rank) if(!foundjob) return var/new_dept = foundjob.pto_type || PTO_CIVILIAN var/datum/job/ptojob = null - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) if(job.pto_type == new_dept && job.timeoff_factor < 0) ptojob = job break diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 09ee9217ba..1c8acb531f 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -487,7 +487,7 @@ //Handle job slot/tater cleanup. var/job = to_despawn.mind.assigned_role - GLOB.job_master.FreeRole(job) + SSjob.free_role(job) to_despawn.mind.assigned_role = null if(to_despawn.mind.objectives.len) diff --git a/code/game/machinery/protean_reconstitutor.dm b/code/game/machinery/protean_reconstitutor.dm index d1a6828c4f..28b335b5bd 100644 --- a/code/game/machinery/protean_reconstitutor.dm +++ b/code/game/machinery/protean_reconstitutor.dm @@ -254,7 +254,7 @@ antag_data.add_antagonist(P.mind) antag_data.place_mob(P) P.mind.assigned_role = charjob - P.mind.role_alt_title = GLOB.job_master.GetPlayerAltTitle(P, charjob) + P.mind.role_alt_title = SSjob.get_player_alt_title(P, charjob) //no need to be particularly thorough about language handover, we can safely assume that they were allowed to have it if they had it to begin with P.languages.Cut() diff --git a/code/game/machinery/virtual_reality/ar_console.dm b/code/game/machinery/virtual_reality/ar_console.dm index f39c66e15b..300655f20c 100644 --- a/code/game/machinery/virtual_reality/ar_console.dm +++ b/code/game/machinery/virtual_reality/ar_console.dm @@ -117,7 +117,7 @@ occupant.enter_vr(avatar) if(spawn_with_clothing) - GLOB.job_master.EquipRank(avatar,"Visitor", 1, FALSE) + SSjob.equip_rank(avatar,"Visitor", 1, FALSE) add_verb(avatar,/mob/living/carbon/human/proc/perform_exit_vr) avatar.virtual_reality_mob = FALSE //THIS IS THE BIG DIFFERENCE WITH ALIEN VR PODS. THEY ARE NOT VR, THEY ARE REAL. diff --git a/code/game/machinery/virtual_reality/vr_console.dm b/code/game/machinery/virtual_reality/vr_console.dm index c2818e0b9b..9bd95ed932 100644 --- a/code/game/machinery/virtual_reality/vr_console.dm +++ b/code/game/machinery/virtual_reality/vr_console.dm @@ -291,7 +291,7 @@ occupant.enter_vr(avatar) if(spawn_with_clothing) - GLOB.job_master.EquipRank(avatar,"Visitor", 1, FALSE) + SSjob.equip_rank(avatar,"Visitor", 1, FALSE) add_verb(avatar,/mob/living/carbon/human/proc/perform_exit_vr) add_verb(avatar,/mob/living/carbon/human/proc/vr_transform_into_mob) add_verb(avatar,/mob/living/proc/set_size) diff --git a/code/game/machinery/virtual_reality/vr_procs.dm b/code/game/machinery/virtual_reality/vr_procs.dm index 501aa5cfcd..5f787c7041 100644 --- a/code/game/machinery/virtual_reality/vr_procs.dm +++ b/code/game/machinery/virtual_reality/vr_procs.dm @@ -81,7 +81,7 @@ avatar.regenerate_icons() avatar.update_transform() - GLOB.job_master.EquipRank(avatar,JOB_VR, 1, FALSE) + SSjob.equip_rank(avatar,JOB_VR, 1, FALSE) add_verb(avatar,/mob/living/carbon/human/proc/fake_exit_vr) add_verb(avatar,/mob/living/carbon/human/proc/vr_transform_into_mob) add_verb(avatar,/mob/living/proc/set_size) diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm index d0a64e89e4..8723df681b 100644 --- a/code/game/objects/items/weapons/id cards/station_ids.dm +++ b/code/game/objects/items/weapons/id cards/station_ids.dm @@ -142,7 +142,7 @@ /obj/item/card/id/Initialize(mapload) . = ..() - var/datum/job/J = GLOB.job_master.GetJob(rank) + var/datum/job/J = SSjob.get_job(rank) if(J) access = J.get_access() diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index 2b8312e183..1a9b83ab3e 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -253,7 +253,7 @@ name = "[initial(name)] for [recipient.name] ([current_title])" recipient_ref = WEAKREF(recipient) - var/datum/job/this_job = SSjob.name_occupations[recipient.assigned_role] + var/datum/job/this_job = SSjob.occupations_by_name[recipient.assigned_role] var/list/goodies = generic_goodies if(this_job) diff --git a/code/game/objects/structures/ghost_pods/event_vr.dm b/code/game/objects/structures/ghost_pods/event_vr.dm index 637afa1892..e261df2a30 100644 --- a/code/game/objects/structures/ghost_pods/event_vr.dm +++ b/code/game/objects/structures/ghost_pods/event_vr.dm @@ -170,7 +170,7 @@ new_character.mind.loaded_from_ckey = picked_ckey new_character.mind.loaded_from_slot = picked_slot - GLOB.job_master.EquipRank(new_character, JOB_MAINT_LURKER, 1) + SSjob.equip_rank(new_character, JOB_MAINT_LURKER, 1) for(var/lang in new_character.client.prefs.alternate_languages) var/datum/language/chosen_language = GLOB.all_languages[lang] diff --git a/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm b/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm index 17024555cd..c44cc0ea16 100644 --- a/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm +++ b/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm @@ -132,7 +132,7 @@ new_character.mind.loaded_from_ckey = picked_ckey new_character.mind.loaded_from_slot = picked_slot - GLOB.job_master.EquipRank(new_character, JOB_MAINT_LURKER, 1) + SSjob.equip_rank(new_character, JOB_MAINT_LURKER, 1) for(var/lang in new_character.client.prefs.alternate_languages) var/datum/language/chosen_language = GLOB.all_languages[lang] diff --git a/code/game/world.dm b/code/game/world.dm index b813452887..cc12aae2d4 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -172,12 +172,8 @@ GLOBAL_VAR(restart_counter) log_test("If you did not intend to enable this please check code/__defines/unit_testing.dm") #endif - GLOB.master_controller = new /datum/controller/game_controller() Master.Initialize(10, FALSE, TRUE) // VOREStation Edit - spawn(1) - GLOB.master_controller.setup() - RunUnattendedFunctions() spawn(3000) //so we aren't adding to the round-start lag diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 28cc364aaf..6f2c523536 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -357,17 +357,17 @@ ADMIN_VERB(shuttle_panel, R_ADMIN|R_EVENT, "Shuttle Control Panel", "Access the ADMIN_VERB(free_slot, R_ADMIN|R_FUN|R_EVENT, "Free Job Slot", "Frees another job slot.", ADMIN_CATEGORY_EVENTS) var/list/jobs = list() - for (var/datum/job/current_job in GLOB.job_master.occupations) - if (current_job.current_positions >= current_job.total_positions && current_job.total_positions != -1) - jobs += current_job.title - if (!length(jobs)) - to_chat(user, "There are no fully staffed jobs.") + for(var/datum/job/J in SSjob.occupations) + if (J.current_positions >= J.total_positions && J.total_positions != -1) + jobs += J.title + if(!jobs.len) + to_chat(usr, "There are no fully staffed jobs.") return - var/job = tgui_input_list(user, "Please select job slot to free", "Free job slot", jobs) - if (!job) + var/job = tgui_input_list(usr, "Please select job slot to free", "Free job slot", jobs) + if(job) + SSjob.free_role(job) + message_admins("A job slot for [job] has been opened by [key_name_admin(usr)]") return - GLOB.job_master.FreeRole(job) - message_admins("A job slot for [job] has been opened by [key_name_admin(user)]") ADMIN_VERB(toggleghostwriters, R_ADMIN|R_FUN|R_EVENT, "Toggle ghost writers", "Toggles ghost writing.", ADMIN_CATEGORY_SERVER_GAME) if(!config) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 08da154eec..0cc06674d4 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -257,7 +257,7 @@ if(!M.ckey) //sanity to_chat(usr, span_filter_adminlog("This mob has no ckey")) return - if(!GLOB.job_master) + if(!SSjob) to_chat(usr, span_filter_adminlog("Job Master has not been setup!")) return @@ -278,7 +278,7 @@ jobs += "Command Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -298,7 +298,7 @@ jobs += "Security Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -318,7 +318,7 @@ jobs += "Engineering Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -338,7 +338,7 @@ jobs += "Cargo Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CARGO)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -358,7 +358,7 @@ jobs += "Medical Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_MEDICAL)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -378,7 +378,7 @@ jobs += "Science Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_RESEARCH)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -398,7 +398,7 @@ jobs += "Exploration Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_PLANET)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -422,7 +422,7 @@ jobs += "Offmap Positions" for(var/jobPos in offmap_jobs) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -442,7 +442,7 @@ jobs += "Civilian Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CIVILIAN)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -467,7 +467,7 @@ jobs += "Synthetic Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC)) if(!jobPos) continue - var/datum/job/job = GLOB.job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -547,7 +547,7 @@ tgui_alert_async(usr, "You cannot perform this action. You must be of a higher administrative rank!") return - if(!GLOB.job_master) + if(!SSjob) to_chat(usr, span_filter_adminlog("Job Master has not been setup!")) return @@ -557,63 +557,63 @@ if("commanddept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("securitydept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("engineeringdept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("cargodept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CARGO)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("medicaldept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_MEDICAL)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("sciencedept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_RESEARCH)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("explorationdept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_PLANET)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("offmapdept") for(var/dept in GLOB.offmap_departments) for(var/jobPos in SSjob.get_job_titles_in_department(dept)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("civiliandept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CIVILIAN)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("nonhumandept") joblist += "pAI" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC)) if(!jobPos) continue - var/datum/job/temp = GLOB.job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title else diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 72fbb6fcab..90b5196527 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -57,8 +57,8 @@ ADMIN_VERB(camera_view, R_DEBUG, "Camera Range Display", "Globally changes the c ADMIN_VERB_VISIBILITY(sec_camera_report, ADMIN_VERB_VISIBLITY_FLAG_LOCALHOST) ADMIN_VERB(sec_camera_report, R_DEBUG, "Camera Report", "Gives a report of the camera state (Only use on a test server).", ADMIN_CATEGORY_MAPPING_TESTS) - if(!GLOB.master_controller) - tgui_alert_async(user,"Master_controller not found.","Sec Camera Report") + if(!SSticker.HasRoundStarted()) + tgui_alert_async(user,"Game init not ready.","Sec Camera Report") return 0 var/list/obj/machinery/camera/CL = list() diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index f606359ddb..0a7c205cb0 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -390,7 +390,7 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp //Well you're not reloading their job or they never had one. if(!charjob) - var/pickjob = tgui_input_list(src, "Pick a job to assign them (or none).","Job Select", GLOB.joblist.Copy() + "-No Job-", "-No Job-") + var/pickjob = tgui_input_list(src, "Pick a job to assign them (or none).","Job Select", SSjob.occupations_by_name.Copy() + "-No Job-", "-No Job-") if(!pickjob) return if(pickjob != "-No Job-") @@ -521,10 +521,10 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp //If desired, apply equipment. if(equipment) if(charjob) - GLOB.job_master.EquipRank(new_character, charjob, 1) + SSjob.equip_rank(new_character, charjob, 1) if(new_character.mind) new_character.mind.assigned_role = charjob - new_character.mind.role_alt_title = GLOB.job_master.GetPlayerAltTitle(new_character, charjob) + new_character.mind.role_alt_title = SSjob.get_player_alt_title(new_character, charjob) //If customised job title, modify here. if(custom_job && custom_job_title) @@ -652,8 +652,8 @@ ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_delete, R_FUN|R_ADMIN, "Delete", "Delete t user.admin_delete(atom_target) ADMIN_VERB(cmd_admin_list_open_jobs, R_HOLDER, "List free slots", "Show available job slots.", ADMIN_CATEGORY_INVESTIGATE) - if(GLOB.job_master) - for(var/datum/job/job in GLOB.job_master.occupations) + if(SSjob) + for(var/datum/job/job in SSjob.occupations) to_chat(user, "[job.title]: [job.total_positions]") feedback_add_details("admin_verb","LFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/tripAI.dm b/code/modules/admin/verbs/tripAI.dm index a19ba79a12..ac006f0847 100644 --- a/code/modules/admin/verbs/tripAI.dm +++ b/code/modules/admin/verbs/tripAI.dm @@ -6,8 +6,8 @@ to_chat(usr, "This option is currently only usable during pregame. This may change at a later date.") return - if(GLOB.job_master && SSticker) - var/datum/job/job = GLOB.job_master.GetJob(JOB_AI) + if(SSjob && SSticker) + var/datum/job/job = SSjob.get_job(JOB_AI) if(!job) to_chat(usr, "Unable to locate the AI job") return diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index aa3013dcb2..4ed98a745b 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -56,10 +56,10 @@ //VOREStation Add End if(!(pref.player_alt_titles)) pref.player_alt_titles = new() - if(!GLOB.job_master) + if(!SSjob) return - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) var/alt_title = pref.player_alt_titles[job.title] if(alt_title && !(alt_title in job.alt_titles)) pref.player_alt_titles -= job.title @@ -173,7 +173,7 @@ if("job_info") var/rank = params["rank"] - var/datum/job/job = GLOB.job_master.GetJob(rank) + var/datum/job/job = SSjob.get_job(rank) if(!istype(job)) return TOPIC_NOACTION @@ -225,7 +225,7 @@ pref.player_alt_titles[job.title] = new_title /datum/category_item/player_setup_item/occupation/proc/SetJob(mob/user, role, level) - var/datum/job/job = GLOB.job_master.GetJob(role) + var/datum/job/job = SSjob.get_job(role) if(!job) return 0 diff --git a/code/modules/mob/dead/observer/free_vr.dm b/code/modules/mob/dead/observer/free_vr.dm index 0a445dd36e..0b17f86ea4 100644 --- a/code/modules/mob/dead/observer/free_vr.dm +++ b/code/modules/mob/dead/observer/free_vr.dm @@ -31,7 +31,7 @@ GLOBAL_LIST_EMPTY(prevent_respawns) //Job slot cleanup var/job = src.mind.assigned_role - GLOB.job_master.FreeRole(job) + SSjob.free_role(job) //Their objectives cleanup if(src.mind.objectives.len) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index f1625a8151..e57afd3c3b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -409,7 +409,7 @@ //Handle job slot/tater cleanup. var/job = mind.assigned_role - GLOB.job_master.FreeRole(job) + SSjob.free_role(job) if(mind.objectives.len) qdel(mind.objectives) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index eb470b63ab..0ef3f6c80c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -471,7 +471,7 @@ //Job slot cleanup var/job = mind.assigned_role - GLOB.job_master.FreeRole(job) + SSjob.free_role(job) //Their objectives cleanup if(mind.objectives.len) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 45539f4a9e..b5e6eada06 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -197,7 +197,7 @@ return timer - world.time /mob/new_player/proc/IsJobAvailable(rank) - var/datum/job/job = GLOB.job_master.GetJob(rank) + var/datum/job/job = SSjob.get_job(rank) if(!job) return 0 if(!job.is_position_available()) @@ -232,7 +232,7 @@ return 0 //Find our spawning point. - var/list/join_props = GLOB.job_master.LateSpawn(client, rank) + var/list/join_props = SSjob.late_spawn(client, rank) if(!join_props) return @@ -271,10 +271,10 @@ qdel(src) return - GLOB.job_master.AssignRole(src, rank, 1) + SSjob.assign_role(src, rank, 1) var/mob/living/character = create_character(T) //creates the human and transfers vars and mind - character = GLOB.job_master.EquipRank(character, rank, 1) //equips the human + character = SSjob.equip_rank(character, rank, 1) //equips the human UpdateFactionList(character) var/datum/job/J = SSjob.get_job(rank) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index a7888bb798..618a9ef971 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -192,11 +192,11 @@ var/datum/job/previewJob // Determine what job is marked as 'High' priority, and dress them up as such. if(job_civilian_low & ASSISTANT) - previewJob = GLOB.job_master.GetJob(JOB_ALT_VISITOR) + previewJob = SSjob.get_job(JOB_ALT_VISITOR) else if(client && ispAI(client.mob)) pass() //Don't do anything! else - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) var/job_flag switch(job.department_flag) if(CIVILIAN) @@ -257,9 +257,9 @@ var/datum/job/highJob // Determine what job is marked as 'High' priority, and dress them up as such. if(job_civilian_low & ASSISTANT) - highJob = GLOB.job_master.GetJob(JOB_ALT_ASSISTANT) + highJob = SSjob.get_job(JOB_ALT_ASSISTANT) else - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) var/job_flag switch(job.department_flag) if(CIVILIAN) diff --git a/code/modules/resleeving/autoresleever.dm b/code/modules/resleeving/autoresleever.dm index f23dba56f2..2e57112363 100644 --- a/code/modules/resleeving/autoresleever.dm +++ b/code/modules/resleeving/autoresleever.dm @@ -209,9 +209,9 @@ GLOBAL_LIST_EMPTY(active_autoresleevers) //If desired, apply equipment. if(equip_body) if(charjob) - GLOB.job_master.EquipRank(new_character, charjob, 1) + SSjob.equip_rank(new_character, charjob, 1) new_character.mind.assigned_role = charjob - new_character.mind.role_alt_title = GLOB.job_master.GetPlayerAltTitle(new_character, charjob) + new_character.mind.role_alt_title = SSjob.get_player_alt_title(new_character, charjob) //A redraw for good measure new_character.regenerate_icons() diff --git a/code/modules/tgs_commands/vorestation.dm b/code/modules/tgs_commands/vorestation.dm index f4563fbd5e..b0f2808f7b 100644 --- a/code/modules/tgs_commands/vorestation.dm +++ b/code/modules/tgs_commands/vorestation.dm @@ -408,7 +408,7 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) if(action == "help") var/list/whitelist_jobs = list() - for(var/datum/job/our_job in GLOB.job_master.occupations) + for(var/datum/job/our_job in SSjob.occupations) if(our_job.whitelist_only) whitelist_jobs += our_job.title var/list/whitelisted_language = list() @@ -456,7 +456,7 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) if("add") switch(kind) if("job") - var/datum/job/job = GLOB.job_master.GetJob(role) + var/datum/job/job = SSjob.get_job(role) if(!job) message.text = "Error, invalid job entered. Check spelling and capitalization." return message diff --git a/code/modules/tgui/modules/late_choices.dm b/code/modules/tgui/modules/late_choices.dm index 130cf1b968..cf9bcaa8e0 100644 --- a/code/modules/tgui/modules/late_choices.dm +++ b/code/modules/tgui/modules/late_choices.dm @@ -74,7 +74,7 @@ var/list/jobs = list() - for(var/datum/job/job in GLOB.job_master.occupations) + for(var/datum/job/job in SSjob.occupations) if(job && user.IsJobAvailable(job.title)) // Check for jobs with minimum age requirements if(!character_old_enough_for_job(user.client.prefs, job)) diff --git a/vorestation.dme b/vorestation.dme index 48f5bc9dee..af12792580 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -545,7 +545,6 @@ #include "code\controllers\hooks-defs.dm" #include "code\controllers\hooks.dm" #include "code\controllers\master.dm" -#include "code\controllers\master_controller.dm" #include "code\controllers\subsystem.dm" #include "code\controllers\configuration\config_entry.dm" #include "code\controllers\configuration\configuration.dm" @@ -1239,7 +1238,6 @@ #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\access_datum.dm" -#include "code\game\jobs\job_controller.dm" #include "code\game\jobs\jobs.dm" #include "code\game\jobs\whitelist.dm" #include "code\game\jobs\job\_alt_title.dm"