diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm index 9371c5207a4..9e2fd7bef46 100644 --- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm @@ -997,7 +997,6 @@ /area/ruin/space/has_grav/listeningstation) "bx" = ( /obj/effect/mob_spawn/human/lavaland_syndicate/comms/space{ - assignedrole = "Space Syndicate"; dir = 8 }, /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 33ed59e50d2..2b26a3224ee 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -25,6 +25,8 @@ #define COMSIG_GLOB_BUTTON_PRESSED "!button_pressed" /// job subsystem has spawned and equipped a new mob #define COMSIG_GLOB_JOB_AFTER_SPAWN "!job_after_spawn" +/// job datum has been called to deal with the aftermath of a latejoin spawn +#define COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN "!job_after_latejoin_spawn" /// crewmember joined the game (mob/living, rank) #define COMSIG_GLOB_CREWMEMBER_JOINED "!crewmember_joined" /// Random event is trying to roll. (/datum/round_event_control/random_event) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index d284cedc30c..1d133b1af99 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -236,3 +236,16 @@ GLOBAL_LIST_INIT(book_types, typecacheof(list( /obj/item/book, /obj/item/spellbook, /obj/item/storage/book))) + + +// Jobs +#define is_assistant_job(job_type) (istype(job_type, /datum/job/assistant)) +#define is_bartender_job(job_type) (istype(job_type, /datum/job/bartender)) +#define is_captain_job(job_type) (istype(job_type, /datum/job/captain)) +#define is_chaplain_job(job_type) (istype(job_type, /datum/job/chaplain)) +#define is_clown_job(job_type) (istype(job_type, /datum/job/clown)) +#define is_detective_job(job_type) (istype(job_type, /datum/job/detective)) +#define is_scientist_job(job_type) (istype(job_type, /datum/job/scientist)) +#define is_security_officer_job(job_type) (istype(job_type, /datum/job/security_officer)) +#define is_research_director_job(job_type) (istype(job_type, /datum/job/research_director)) +#define is_unassigned_job(job_type) (istype(job_type, /datum/job/unassigned)) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 52dd1877de1..21349fa19c6 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -56,3 +56,18 @@ #define DEPARTMENT_SCIENCE (1<<5) #define DEPARTMENT_MEDICAL (1<<6) #define DEPARTMENT_SILICON (1<<7) + +/* Job datum job_flags */ +/// Whether the mob is announced on arrival. +#define JOB_ANNOUNCE_ARRIVAL (1<<0) +/// Whether the mob is added to the crew manifest. +#define JOB_CREW_MANIFEST (1<<1) +/// Whether the mob is equipped through SSjob.EquipRank() on spawn. +#define JOB_EQUIP_RANK (1<<2) +/// Whether the job is considered a regular crew member of the station. Equipment such as AI and cyborgs not included. +#define JOB_CREW_MEMBER (1<<3) +/// Whether this job can be joined through the new_player menu. +#define JOB_NEW_PLAYER_JOINABLE (1<<4) + +#define FACTION_NONE "None" +#define FACTION_STATION "Station" diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index c8014079047..d72ac49f49b 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -129,3 +129,22 @@ //recommened client FPS #define RECOMMENDED_FPS 40 + +// randomise_appearance_prefs() and randomize_human_appearance() proc flags +#define RANDOMIZE_GENDER (1<<0) +#define RANDOMIZE_SPECIES (1<<1) +#define RANDOMIZE_NAME (1<<2) +#define RANDOMIZE_AGE (1<<3) +#define RANDOMIZE_UNDERWEAR (1<<4) +#define RANDOMIZE_UNDERWEAR_COLOR (1<<5) +#define RANDOMIZE_UNDERSHIRT (1<<6) +#define RANDOMIZE_SOCKS (1<<7) +#define RANDOMIZE_BACKPACK (1<<8) +#define RANDOMIZE_JUMPSUIT_STYLE (1<<9) +#define RANDOMIZE_HAIRSTYLE (1<<10) +#define RANDOMIZE_FACIAL_HAIRSTYLE (1<<11) +#define RANDOMIZE_HAIR_COLOR (1<<12) +#define RANDOMIZE_FACIAL_HAIR_COLOR (1<<13) +#define RANDOMIZE_SKIN_TONE (1<<14) +#define RANDOMIZE_EYE_COLOR (1<<15) +#define RANDOMIZE_FEATURES (1<<16) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 7525a1adcbd..e1344c904cb 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -40,10 +40,46 @@ #define ROLE_LAVALAND "Lavaland" #define ROLE_INTERNAL_AFFAIRS "Internal Affairs Agent" #define ROLE_FAMILIES "Familes Antagonists" + +#define ROLE_POSITRONIC_BRAIN "Positronic Brain" +#define ROLE_FREE_GOLEM "Free Golem" +#define ROLE_SERVANT_GOLEM "Servant Golem" +#define ROLE_NUCLEAR_OPERATIVE "Nuclear Operative" +#define ROLE_CLOWN_OPERATIVE "Clown Operative" +#define ROLE_LONE_OPERATIVE "Lone Operative" +#define ROLE_NIGHTMARE "Nightmare" +#define ROLE_WIZARD_APPRENTICE "apprentice" +#define ROLE_SLAUGHTER_DEMON "Slaughter Demon" +#define ROLE_SENTIENT_DISEASE "Sentient Disease" +#define ROLE_MORPH "Morph" +#define ROLE_SANTA "Santa" +#define ROLE_FUGITIVE "Fugitive" + +//Spawner roles +#define ROLE_GHOST_ROLE "Ghost Role" +#define ROLE_SPIDER "Spider" +#define ROLE_EXILE "Exile" +#define ROLE_FUGITIVE_HUNTER "Fugitive Hunter" +#define ROLE_ESCAPED_PRISONER "Escaped Prisoner" +#define ROLE_LIFEBRINGER "Lifebringer" +#define ROLE_ASHWALKER "Ash Walker" +#define ROLE_LAVALAND_SYNDICATE "Lavaland Syndicate" +#define ROLE_HERMIT "Hermit" +#define ROLE_BEACH_BUM "Beach Bum" +#define ROLE_HOTEL_STAFF "Hotel Staff" +#define ROLE_SPACE_SYNDICATE "Space Syndicate" #define ROLE_SYNDICATE_CYBERSUN "Cybersun Space Syndicate" //Ghost role syndi from Forgottenship ruin #define ROLE_SYNDICATE_CYBERSUN_CAPTAIN "Cybersun Space Syndicate Captain" //Forgottenship captain syndie -#define ROLE_FREE_GOLEM "Free Golem" #define ROLE_HEADSLUG_CHANGELING "Headslug Changeling" +#define ROLE_SPACE_PIRATE "Space Pirate" +#define ROLE_ANCIENT_CREW "Ancient Crew" +#define ROLE_SPACE_DOCTOR "Space Doctor" +#define ROLE_SPACE_BARTENDER "Space Bartender" +#define ROLE_SPACE_BAR_PATRON "Space Bar Patron" +#define ROLE_SKELETON "Skeleton" +#define ROLE_ZOMBIE "Zombie" +#define ROLE_MAINTENANCE_DRONE "Maintenance Drone" + /// This defines the antagonists you can operate with in the settings. /// Keys are the antagonist, values are the number of days since the player's diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 7e119b0dc0c..a6e93db70fc 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -123,9 +123,9 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) if (CONFIG_GET(flag/log_econ)) WRITE_LOG(GLOB.world_econ_log, "MONEY: [text]") -/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE) +/proc/log_manifest(ckey, datum/mind/mind, mob/body, latejoin = FALSE) if (CONFIG_GET(flag/log_manifest)) - WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]") + WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role.title] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]") /proc/log_bomber(atom/user, details, atom/bomb, additional_details, message_admins = TRUE) var/bomb_message = "[details][bomb ? " [bomb.name] at [AREACOORD(bomb)]": ""][additional_details ? " [additional_details]" : ""]." diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 22787ea5136..7d1cd02fc42 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -8,6 +8,9 @@ #define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL)) #define CULT_POLL_WAIT 2400 +/// Returns either the error landmark or the location of the room. Needless to say, if this is used, it means things have gone awry. +#define GET_ERROR_ROOM ((locate(/obj/effect/landmark/error) in GLOB.landmarks_list) || locate(4,4,1)) + /proc/get_area_name(atom/X, format_text = FALSE) var/area/A = isarea(X) ? X : get_area(X) if(!A) @@ -455,7 +458,7 @@ var/mob/living/carbon/human/new_character = new//The mob being spawned. SSjob.SendToLateJoin(new_character) - G_found.client.prefs.copy_to(new_character) + G_found.client.prefs.safe_transfer_prefs_to(new_character) new_character.dna.update_dna_identity() new_character.key = G_found.key @@ -497,7 +500,7 @@ return if(!GLOB.announcement_systems.len) return - if((character.mind.assigned_role == "Cyborg") || (character.mind.assigned_role == character.mind.special_role)) + if(!(character.mind.assigned_role.job_flags & JOB_ANNOUNCE_ARRIVAL)) return var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 5d7f87ade1a..9c31637e0e2 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1047,31 +1047,33 @@ GLOBAL_LIST_EMPTY(friendly_animal_types) return 0 //For creating consistent icons for human looking simple animals -/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null) +/proc/get_flat_human_icon(icon_id, datum/job/job, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null) var/static/list/humanoid_icon_cache = list() - if(!icon_id || !humanoid_icon_cache[icon_id]) - var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key) - - if(prefs) - prefs.copy_to(body,TRUE,FALSE) - if(J) - J.equip(body, TRUE, FALSE, outfit_override = outfit_override) - else if (outfit_override) - body.equipOutfit(outfit_override,visualsOnly = TRUE) - - - var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing") - COMPILE_OVERLAYS(body) - for(var/D in showDirs) - var/icon/partial = getFlatIcon(body, defdir=D) - out_icon.Insert(partial,dir=D) - - humanoid_icon_cache[icon_id] = out_icon - dummy_key? unset_busy_human_dummy(dummy_key) : qdel(body) - return out_icon - else + if(icon_id && humanoid_icon_cache[icon_id]) return humanoid_icon_cache[icon_id] + var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key) + + if(prefs) + prefs.apply_prefs_to(body, TRUE) + + var/datum/outfit/outfit = outfit_override || job?.outfit + if(job) + body.dna.species.pre_equip_species_outfit(job, body, TRUE) + if(outfit) + body.equipOutfit(outfit, TRUE) + + var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing") + COMPILE_OVERLAYS(body) + for(var/D in showDirs) + var/icon/partial = getFlatIcon(body, defdir=D) + out_icon.Insert(partial,dir=D) + + humanoid_icon_cache[icon_id] = out_icon + dummy_key? unset_busy_human_dummy(dummy_key) : qdel(body) + return out_icon + + //Hook, override to run code on- wait this is images //Images have dir without being an atom, so they get their own definition. //Lame. diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index df8fdf83fde..979af067e06 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -45,7 +45,7 @@ var/mob/living/carbon/human/H = L category = "humans" if(H.mind) - mob_data["job"] = H.mind.assigned_role + mob_data["job"] = H.mind.assigned_role.title else mob_data["job"] = "Unknown" mob_data["species"] = H.dna.species.name @@ -183,7 +183,7 @@ /datum/controller/subsystem/ticker/proc/HandleRandomHardcoreScore(client/player_client) if(!ishuman(player_client?.mob)) return FALSE - var/mob/living/carbon/human/human_mob = player_client?.mob + var/mob/living/carbon/human/human_mob = player_client.mob if(!human_mob.hardcore_survival_score) ///no score no glory return FALSE @@ -197,9 +197,9 @@ didthegamerwin = FALSE if(!didthegamerwin) return FALSE - player_client?.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score * 2)) + player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score * 2)) else if(human_mob.onCentCom()) - player_client?.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score)) + player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score)) /datum/controller/subsystem/ticker/proc/declare_completion() @@ -542,31 +542,14 @@ * * award: Achievement to give service department */ /datum/controller/subsystem/ticker/proc/award_service(award) - for(var/mob/living/carbon/human/service_member as anything in GLOB.human_list) - if(!service_member.mind) + for(var/mob/living/carbon/human/human as anything in GLOB.human_list) + if(!human.client || !human.mind) continue - var/datum/mind/service_mind = service_member.mind - if(!service_mind.assigned_role) + var/datum/job/human_job = human.mind.assigned_role + if(!(human_job.departments & DEPARTMENT_SERVICE)) continue - for(var/job in GLOB.service_food_positions) - if(service_mind.assigned_role != job) - continue - //general awards - service_member.client?.give_award(award, service_member) - if(service_mind.assigned_role == "Cook") - var/datum/venue/restaurant = SSrestaurant.all_venues[/datum/venue/restaurant] - var/award_score = restaurant.total_income - var/award_status = service_member.client.get_award_status(/datum/award/score/chef_tourist_score) - if(award_score > award_status) - award_score -= award_status - service_member.client?.give_award(/datum/award/score/chef_tourist_score, service_member, award_score) - if(service_mind.assigned_role == "Bartender") - var/datum/venue/bar = SSrestaurant.all_venues[/datum/venue/bar] - var/award_score = bar.total_income - var/award_status = service_member.client.get_award_status(/datum/award/score/bartender_tourist_score) - if(award_score - award_status > 0) - award_score -= award_status - service_member.client?.give_award(/datum/award/score/bartender_tourist_score, service_member, award_score) + human_job.award_service(human.client, award) + /datum/controller/subsystem/ticker/proc/medal_report() if(GLOB.commendations.len) @@ -677,8 +660,8 @@ /proc/printplayer(datum/mind/ply, fleecheck) var/jobtext = "" - if(ply.assigned_role) - jobtext = " the [ply.assigned_role]" + if(!is_unassigned_job(ply.assigned_role)) + jobtext = " the [ply.assigned_role.title]" var/text = "[ply.key] was [ply.name][jobtext] and" if(ply.current) if(ply.current.stat == DEAD) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 812820287f0..2cdf763d8d1 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -199,10 +199,10 @@ Turf and target are separate in case you want to teleport some distance from a t var/loop = 1 var/safety = 0 - var/banned = C ? is_banned_from(C.ckey, "Appearance") : null + var/random = CONFIG_GET(flag/force_random_names) || (C ? is_banned_from(C.ckey, "Appearance") : FALSE) while(loop && safety < 5) - if(C?.prefs.custom_names[role] && !safety && !banned) + if(!safety && !random && C?.prefs.custom_names[role]) newname = C.prefs.custom_names[role] else switch(role) diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 0080e1499d7..3e7fc9574e0 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -309,8 +309,7 @@ Versioning if(!L.suiciding && !first_death.len) first_death["name"] = "[(L.real_name == L.name) ? L.real_name : "[L.real_name] as [L.name]"]" first_death["role"] = null - if(L.mind.assigned_role) - first_death["role"] = L.mind.assigned_role + first_death["role"] = L.mind.assigned_role.title first_death["area"] = "[AREACOORD(L)]" first_death["damage"] = "[L.getBruteLoss()]/[L.getFireLoss()]/[L.getToxLoss()]/[L.getOxyLoss()]/[L.getCloneLoss()]" first_death["last_words"] = L.last_words @@ -324,7 +323,7 @@ Versioning "}, list( "name" = L.real_name, "key" = L.ckey, - "job" = L.mind.assigned_role, + "job" = L.mind.assigned_role.title, "special" = L.mind.special_role, "pod" = get_area_name(L, TRUE), "laname" = L.lastattacker, diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index d6ee85f6f8d..691adf7be17 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -3,16 +3,19 @@ SUBSYSTEM_DEF(job) init_order = INIT_ORDER_JOBS flags = SS_NO_FIRE - var/list/occupations = list() //List of all jobs + /// List of all jobs. + var/list/all_occupations = list() + /// List of jobs that can be joined through the starting menu. + var/list/joinable_occupations = list() var/list/datum/job/name_occupations = list() //Dict of all jobs, keys are titles var/list/type_occupations = list() //Dict of all jobs, keys are types var/list/unassigned = list() //Players who need jobs var/initial_players_to_assign = 0 //used for checking against population caps var/list/prioritized_jobs = list() - var/list/latejoin_trackers = list() //Don't read this list, use GetLateJoinTurfs() instead + var/list/latejoin_trackers = list() - var/overflow_role = "Assistant" + var/overflow_role = /datum/job/assistant var/list/level_order = list(JP_HIGH,JP_MEDIUM,JP_LOW) @@ -52,12 +55,11 @@ SUBSYSTEM_DEF(job) var/safe_code_timer_id /// The loc to which the emergency safe code has been requested for delivery. var/turf/safe_code_request_loc - /// If TRUE, the "Captain" job will always be given the code to the spare ID safe and always have a "Captain on deck!" announcement. - var/always_promote_captain_job = TRUE + /datum/controller/subsystem/job/Initialize(timeofday) setup_job_lists() - if(!occupations.len) + if(!length(all_occupations)) SetupOccupations() if(CONFIG_GET(flag/load_jobs_from_txt)) LoadJobs() @@ -65,79 +67,83 @@ SUBSYSTEM_DEF(job) set_overflow_role(CONFIG_GET(string/overflow_job)) return ..() + /datum/controller/subsystem/job/proc/set_overflow_role(new_overflow_role) - var/datum/job/new_overflow = GetJob(new_overflow_role) + var/datum/job/new_overflow = ispath(new_overflow_role) ? GetJobType(new_overflow_role) : GetJob(new_overflow_role) + if(!new_overflow) + JobDebug("Failed to set new overflow role: [new_overflow_role]") + CRASH("set_overflow_role failed | new_overflow_role: [isnull(new_overflow_role) ? "null" : new_overflow_role]") var/cap = CONFIG_GET(number/overflow_cap) new_overflow.allow_bureaucratic_error = FALSE new_overflow.spawn_positions = cap new_overflow.total_positions = cap - if(new_overflow_role != overflow_role) - var/datum/job/old_overflow = GetJob(overflow_role) - old_overflow.allow_bureaucratic_error = initial(old_overflow.allow_bureaucratic_error) - old_overflow.spawn_positions = initial(old_overflow.spawn_positions) - old_overflow.total_positions = initial(old_overflow.total_positions) - overflow_role = new_overflow_role - JobDebug("Overflow role set to : [new_overflow_role]") + if(new_overflow.type == overflow_role) + return + var/datum/job/old_overflow = GetJobType(overflow_role) + old_overflow.allow_bureaucratic_error = initial(old_overflow.allow_bureaucratic_error) + old_overflow.spawn_positions = initial(old_overflow.spawn_positions) + old_overflow.total_positions = initial(old_overflow.total_positions) + overflow_role = new_overflow.type + JobDebug("Overflow role set to : [new_overflow.type]") -/datum/controller/subsystem/job/proc/SetupOccupations(faction = "Station") - occupations = list() + +/datum/controller/subsystem/job/proc/SetupOccupations() + all_occupations = list() + joinable_occupations = list() var/list/all_jobs = subtypesof(/datum/job) - if(!all_jobs.len) + if(!length(all_jobs)) to_chat(world, span_boldannounce("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 - if(job.faction != faction) - continue + for(var/job_type in all_jobs) + var/datum/job/job = new job_type() if(!job.config_check()) continue if(!job.map_check()) //Even though we initialize before mapping, this is fine because the config is loaded at new testing("Removed [job.type] due to map config") continue - occupations += job + all_occupations += job name_occupations[job.title] = job - type_occupations[J] = job + type_occupations[job_type] = job + if(job.job_flags & JOB_NEW_PLAYER_JOINABLE) + joinable_occupations += job return TRUE /datum/controller/subsystem/job/proc/GetJob(rank) - if(!occupations.len) + if(!length(all_occupations)) SetupOccupations() return name_occupations[rank] /datum/controller/subsystem/job/proc/GetJobType(jobtype) - if(!occupations.len) + if(!length(all_occupations)) SetupOccupations() return type_occupations[jobtype] -/datum/controller/subsystem/job/proc/AssignRole(mob/dead/new_player/player, rank, latejoin = FALSE) - JobDebug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") - if(player?.mind && rank) - var/datum/job/job = GetJob(rank) - if(!job) - return FALSE - if(is_banned_from(player.ckey, rank) || QDELETED(player)) - return FALSE - if(!job.player_old_enough(player.client)) - return FALSE - if(job.required_playtime_remaining(player.client)) - return FALSE - var/position_limit = job.total_positions - if(!latejoin) - position_limit = job.spawn_positions - JobDebug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") - player.mind.assigned_role = rank - unassigned -= player - job.current_positions++ - return TRUE - JobDebug("AR has failed, Player: [player], Rank: [rank]") - return FALSE + +/datum/controller/subsystem/job/proc/AssignRole(mob/dead/new_player/player, datum/job/job, latejoin = FALSE) + JobDebug("Running AR, Player: [player], Rank: [isnull(job) ? "null" : job.type], LJ: [latejoin]") + if(!player?.mind || !job) + JobDebug("AR has failed, Player: [player], Rank: [isnull(job) ? "null" : job.type]") + return FALSE + if(is_banned_from(player.ckey, job.title) || QDELETED(player)) + return FALSE + if(!job.player_old_enough(player.client)) + return FALSE + if(job.required_playtime_remaining(player.client)) + return FALSE + var/position_limit = job.total_positions + if(!latejoin) + position_limit = job.spawn_positions + JobDebug("Player: [player] is now Rank: [job.title], JCP:[job.current_positions], JPL:[position_limit]") + player.mind.set_assigned_role(job) + unassigned -= player + job.current_positions++ + return TRUE + /datum/controller/subsystem/job/proc/FreeRole(rank) if(!rank) @@ -173,14 +179,13 @@ SUBSYSTEM_DEF(job) candidates += player return candidates + /datum/controller/subsystem/job/proc/GiveRandomJob(mob/dead/new_player/player) JobDebug("GRJ Giving random job, Player: [player]") . = FALSE - for(var/datum/job/job in shuffle(occupations)) - if(!job) - continue + for(var/datum/job/job as anything in shuffle(joinable_occupations)) - if(istype(job, GetJob(SSjob.overflow_role))) // We don't want to give him assistant, that's boring! + if(istype(job, GetJobType(overflow_role))) // We don't want to give him assistant, that's boring! continue if(job.title in GLOB.command_positions) //If you want a command position, select it! @@ -207,16 +212,17 @@ SUBSYSTEM_DEF(job) if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) JobDebug("GRJ Random job given, Player: [player], Job: [job]") - if(AssignRole(player, job.title)) + if(AssignRole(player, job)) return TRUE + /datum/controller/subsystem/job/proc/ResetOccupations() JobDebug("Occupations reset.") - for(var/i in GLOB.new_player_list) - var/mob/dead/new_player/player = i - if((player) && (player.mind)) - player.mind.assigned_role = null - player.mind.special_role = null + for(var/mob/dead/new_player/player as anything in GLOB.new_player_list) + if(!player?.mind) + continue + player.mind.set_assigned_role(GetJobType(/datum/job/unassigned)) + player.mind.special_role = null SetupOccupations() unassigned = list() return @@ -237,7 +243,7 @@ SUBSYSTEM_DEF(job) if(!candidates.len) continue var/mob/dead/new_player/candidate = pick(candidates) - if(AssignRole(candidate, command_position)) + if(AssignRole(candidate, job)) return TRUE return FALSE @@ -255,7 +261,7 @@ SUBSYSTEM_DEF(job) if(!candidates.len) continue var/mob/dead/new_player/candidate = pick(candidates) - AssignRole(candidate, command_position) + AssignRole(candidate, job) /// Attempts to fill out all available AI positions. /datum/controller/subsystem/job/proc/fill_ai_positions() @@ -269,7 +275,7 @@ SUBSYSTEM_DEF(job) candidates = FindOccupationCandidates(ai_job, level) if(candidates.len) var/mob/dead/new_player/candidate = pick(candidates) - if(AssignRole(candidate, "AI")) + if(AssignRole(candidate, GetJobType(/datum/job/ai))) break @@ -286,7 +292,7 @@ SUBSYSTEM_DEF(job) //Get the players who are ready for(var/i in GLOB.new_player_list) var/mob/dead/new_player/player = i - if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role) + if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && is_unassigned_job(player.mind.assigned_role)) unassigned += player initial_players_to_assign = unassigned.len @@ -315,12 +321,12 @@ SUBSYSTEM_DEF(job) //People who wants to be the overflow role, sure, go on. JobDebug("DO, Running Overflow Check 1") - var/datum/job/overflow = GetJob(SSjob.overflow_role) - var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW) + var/datum/job/overflow_datum = GetJobType(overflow_role) + var/list/overflow_candidates = FindOccupationCandidates(overflow_datum, JP_LOW) JobDebug("AC1, Candidates: [overflow_candidates.len]") for(var/mob/dead/new_player/player in overflow_candidates) JobDebug("AC1 pass, Player: [player]") - AssignRole(player, SSjob.overflow_role) + AssignRole(player, GetJobType(overflow_role)) overflow_candidates -= player JobDebug("DO, AC1 end") @@ -343,7 +349,7 @@ SUBSYSTEM_DEF(job) // 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/shuffledoccupations = shuffle(joinable_occupations) for(var/level in level_order) //Check the head jobs first each level CheckHeadPositions(level) @@ -383,7 +389,7 @@ SUBSYSTEM_DEF(job) // If the job isn't filled if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]") - AssignRole(player, job.title) + AssignRole(player, job) unassigned -= player break @@ -398,7 +404,7 @@ SUBSYSTEM_DEF(job) //Mop up people who can't leave. for(var/mob/dead/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?) if(!GiveRandomJob(player)) - if(!AssignRole(player, SSjob.overflow_role)) //If everything is already filled, make them an assistant + if(!AssignRole(player, GetJobType(overflow_role))) //If everything is already filled, make them an assistant return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll return TRUE @@ -408,11 +414,12 @@ SUBSYSTEM_DEF(job) if(PopcapReached()) RejectPlayer(player) else if(player.client.prefs.joblessrole == BEOVERFLOW) - var/allowed_to_be_a_loser = !is_banned_from(player.ckey, SSjob.overflow_role) + var/datum/job/overflow_role_datum = GetJobType(overflow_role) + var/allowed_to_be_a_loser = !is_banned_from(player.ckey, overflow_role_datum.title) if(QDELETED(player) || !allowed_to_be_a_loser) RejectPlayer(player) else - if(!AssignRole(player, SSjob.overflow_role)) + if(!AssignRole(player, overflow_role_datum)) RejectPlayer(player) else if(player.client.prefs.joblessrole == BERANDOMJOB) if(!GiveRandomJob(player)) @@ -426,95 +433,49 @@ SUBSYSTEM_DEF(job) message_admins(message) RejectPlayer(player) + //Gives the player the stuff he should have with his rank -/datum/controller/subsystem/job/proc/EquipRank(mob/M, rank, joined_late = FALSE, is_captain = FALSE) - var/mob/dead/new_player/newplayer - var/mob/living/living_mob - if(!joined_late) - newplayer = M - living_mob = newplayer.new_character - else - living_mob = M +/datum/controller/subsystem/job/proc/EquipRank(mob/living/equipping, datum/job/job, client/player_client) + equipping.job = job.title - var/datum/job/job = GetJob(rank) + SEND_SIGNAL(equipping, COMSIG_JOB_RECEIVED, job) - living_mob.job = rank + equipping.mind?.set_assigned_role(job) - SEND_SIGNAL(living_mob, COMSIG_JOB_RECEIVED, living_mob.job) + if(player_client) + to_chat(player_client, "You are the [job.title].") - //If we joined at roundstart we should be positioned at our workstation - if(!joined_late) - var/spawning_handled = FALSE - var/obj/S = null - if(HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS) && job.random_spawns_possible) - SendToLateJoin(living_mob, buckle = TRUE, search_empty_chair = FALSE) - spawning_handled = TRUE - else if(HAS_TRAIT(SSstation, STATION_TRAIT_RANDOM_ARRIVALS) && job.random_spawns_possible) - DropLandAtRandomHallwayPoint(living_mob) - spawning_handled = TRUE - else if(HAS_TRAIT(SSstation, STATION_TRAIT_HANGOVER) && job.random_spawns_possible) - for(var/obj/effect/landmark/start/hangover/hangover_spawn in GLOB.start_landmarks_list) - S = hangover_spawn - if(locate(/mob/living) in hangover_spawn.loc) //so we can revert to spawning them on top of eachother if something goes wrong - continue - hangover_spawn.used = TRUE - break - else if(length(GLOB.jobspawn_overrides[rank])) - S = pick(GLOB.jobspawn_overrides[rank]) + equipping.on_job_equipping(job) + + job.announce_job(equipping) + + if(player_client?.holder) + if(CONFIG_GET(flag/auto_deadmin_players) || (player_client.prefs?.toggles & DEADMIN_ALWAYS)) + player_client.holder.auto_deadmin() else - for(var/_sloc in GLOB.start_landmarks_list) - var/obj/effect/landmark/start/sloc = _sloc - if(sloc.name != rank) - continue - S = sloc - if(locate(/mob/living) in sloc.loc) //so we can revert to spawning them on top of eachother if something goes wrong - continue - sloc.used = TRUE - break - if(S) - S.JoinPlayerHere(living_mob, FALSE) - if(!S && !spawning_handled) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper - log_world("Couldn't find a round start spawn point for [rank]") - if(!SendToLateJoin(living_mob)) - living_mob.move_to_error_room() + handle_auto_deadmin_roles(player_client, job.title) + if(player_client) + to_chat(player_client, "As the [job.title] you answer directly to [job.supervisors]. Special circumstances may change this.") - if(living_mob.mind) - living_mob.mind.assigned_role = rank + job.radio_help_message(equipping) - to_chat(M, "You are the [rank].") - if(job) - var/new_mob = job.equip(living_mob, null, null, joined_late, null, M.client, is_captain)//silicons override this proc to return a mob - if(ismob(new_mob)) - living_mob = new_mob - if(!joined_late) - newplayer.new_character = living_mob - else - M = living_mob - - if(M.client.holder) - if(CONFIG_GET(flag/auto_deadmin_players) || (M.client.prefs?.toggles & DEADMIN_ALWAYS)) - M.client.holder.auto_deadmin() - else - handle_auto_deadmin_roles(M.client, rank) - - to_chat(M, "As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.") - job.radio_help_message(M) + if(player_client) if(job.req_admin_notify) - to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") + to_chat(player_client, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") if(CONFIG_GET(number/minimal_access_threshold)) - to_chat(M, span_notice("As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.")) + to_chat(player_client, span_notice("As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.")) - var/related_policy = get_policy(rank) - if(related_policy) - to_chat(M,related_policy) - if(ishuman(living_mob)) - var/mob/living/carbon/human/wageslave = living_mob - living_mob.add_memory("Your account ID is [wageslave.account_id].") - if(job && living_mob) - job.after_spawn(living_mob, M, joined_late) // note: this happens before the mob has a key! M will always have a client, living_mob might not. + var/related_policy = get_policy(job.title) + if(related_policy) + to_chat(player_client, related_policy) + + if(ishuman(equipping)) + var/mob/living/carbon/human/wageslave = equipping + wageslave.add_memory("Your account ID is [wageslave.account_id].") + + job.after_spawn(equipping, player_client) - return living_mob /datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) if(!C?.holder) @@ -564,14 +525,14 @@ SUBSYSTEM_DEF(job) /datum/controller/subsystem/job/proc/LoadJobs() var/jobstext = file2text("[global.config.directory]/jobs.txt") - for(var/datum/job/J in occupations) - var/regex/jobs = new("[J.title]=(-1|\\d+),(-1|\\d+)") + for(var/datum/job/job as anything in joinable_occupations) + var/regex/jobs = new("[job.title]=(-1|\\d+),(-1|\\d+)") jobs.Find(jobstext) - J.total_positions = text2num(jobs.group[1]) - J.spawn_positions = text2num(jobs.group[2]) + job.total_positions = text2num(jobs.group[1]) + job.spawn_positions = text2num(jobs.group[2]) /datum/controller/subsystem/job/proc/HandleFeedbackGathering() - for(var/datum/job/job in occupations) + for(var/datum/job/job as anything in joinable_occupations) var/high = 0 //high var/medium = 0 //medium var/low = 0 //low @@ -580,7 +541,7 @@ SUBSYSTEM_DEF(job) var/young = 0 //account too young for(var/i in GLOB.new_player_list) var/mob/dead/new_player/player = i - if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)) + if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && is_unassigned_job(player.mind.assigned_role))) continue //This player is not ready if(is_banned_from(player.ckey, job.title) || QDELETED(player)) banned++ @@ -629,10 +590,10 @@ SUBSYSTEM_DEF(job) /datum/controller/subsystem/job/Recover() set waitfor = FALSE - var/oldjobs = SSjob.occupations + var/oldjobs = SSjob.all_occupations sleep(20) - for (var/datum/job/J in oldjobs) - INVOKE_ASYNC(src, .proc/RecoverJob, J) + for (var/datum/job/job as anything in oldjobs) + INVOKE_ASYNC(src, .proc/RecoverJob, job) /datum/controller/subsystem/job/proc/RecoverJob(datum/job/J) var/datum/job/newjob = GetJob(J.title) @@ -652,10 +613,10 @@ SUBSYSTEM_DEF(job) return ..() -/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE, search_empty_chair = TRUE) +/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE) var/atom/destination - if(M.mind && M.mind.assigned_role && length(GLOB.jobspawn_overrides[M.mind.assigned_role])) //We're doing something special today. - destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role]) + if(M.mind && !is_unassigned_job(M.mind.assigned_role) && length(GLOB.jobspawn_overrides[M.mind.assigned_role.title])) //We're doing something special today. + destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role.title]) destination.JoinPlayerHere(M, FALSE) return TRUE @@ -664,49 +625,39 @@ SUBSYSTEM_DEF(job) destination.JoinPlayerHere(M, buckle) return TRUE + destination = get_last_resort_spawn_points() + destination.JoinPlayerHere(M, buckle) + + +/datum/controller/subsystem/job/proc/get_last_resort_spawn_points() //bad mojo - var/area/shuttle/arrival/spawnarea = GLOB.areas_by_type[/area/shuttle/arrival] - if(spawnarea) - if(search_empty_chair) // search carefully for an unoccupied chair for the character can buckle to. - var/list/chairs = list() - for(var/obj/structure/chair/chair in spawnarea) - chairs += chair - while(chairs.len) - var/obj/structure/chair/chosen_chair = pick_n_take(chairs) - if(!chosen_chair.has_buckled_mobs()) - chosen_chair.JoinPlayerHere(M, buckle) - return TRUE - //we either couldn't find a free chair or couldn't be bothered to. - var/obj/structure/chair/chair = locate() in spawnarea - if(chair) - chair.JoinPlayerHere(M, buckle) - return TRUE + var/area/shuttle/arrival/arrivals_area = GLOB.areas_by_type[/area/shuttle/arrival] + if(arrivals_area) + //first check if we can find a chair + var/obj/structure/chair/shuttle_chair = locate() in arrivals_area + if(shuttle_chair) + return shuttle_chair //last hurrah - var/list/avail = list() - for(var/turf/T in spawnarea) - if(!T.is_blocked_turf(TRUE)) - avail += T - if(avail.len) - destination = pick(avail) - destination.JoinPlayerHere(M, FALSE) - return TRUE + var/list/turf/available_turfs = list() + for(var/turf/arrivals_turf in arrivals_area) + if(!arrivals_turf.is_blocked_turf(TRUE)) + available_turfs += arrivals_turf + if(length(available_turfs)) + return pick(available_turfs) //pick an open spot on arrivals and dump em var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival)) - if(arrivals_turfs.len) - for(var/turf/T in arrivals_turfs) - if(!T.is_blocked_turf(TRUE)) - T.JoinPlayerHere(M, FALSE) - return TRUE + if(length(arrivals_turfs)) + for(var/turf/arrivals_turf in arrivals_turfs) + if(!arrivals_turf.is_blocked_turf(TRUE)) + return arrivals_turf //last chance, pick ANY spot on arrivals and dump em - destination = arrivals_turfs[1] - destination.JoinPlayerHere(M, FALSE) - return TRUE - else - var/msg = "Unable to send mob [M] to late join!" - message_admins(msg) - CRASH(msg) + return pick(arrivals_turfs) + + stack_trace("Unable to find last resort spawn point.") + return GET_ERROR_ROOM + ///Lands specified mob at a random spot in the hallways /datum/controller/subsystem/job/proc/DropLandAtRandomHallwayPoint(mob/living/living_mob) @@ -724,10 +675,9 @@ SUBSYSTEM_DEF(job) /////////////////////////////////// /datum/controller/subsystem/job/proc/get_living_heads() . = list() - for(var/i in GLOB.human_list) - var/mob/living/carbon/human/player = i - if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.command_positions)) - . |= player.mind + for(var/mob/living/carbon/human/player as anything in GLOB.human_list) + if(player.stat != DEAD && (player.mind?.assigned_role.departments & DEPARTMENT_COMMAND)) + . += player.mind //////////////////////////// @@ -735,30 +685,27 @@ SUBSYSTEM_DEF(job) //////////////////////////// /datum/controller/subsystem/job/proc/get_all_heads() . = list() - for(var/i in GLOB.mob_list) - var/mob/player = i - if(player.mind && (player.mind.assigned_role in GLOB.command_positions)) - . |= player.mind + for(var/mob/living/carbon/human/player as anything in GLOB.human_list) + if(player.mind?.assigned_role.departments & DEPARTMENT_COMMAND) + . += player.mind ////////////////////////////////////////////// //Keeps track of all living security members// ////////////////////////////////////////////// /datum/controller/subsystem/job/proc/get_living_sec() . = list() - for(var/i in GLOB.human_list) - var/mob/living/carbon/human/player = i - if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.security_positions)) - . |= player.mind + for(var/mob/living/carbon/human/player as anything in GLOB.human_list) + if(player.stat != DEAD && (player.mind?.assigned_role.departments & DEPARTMENT_SECURITY)) + . += player.mind //////////////////////////////////////// //Keeps track of all security members// //////////////////////////////////////// /datum/controller/subsystem/job/proc/get_all_sec() . = list() - for(var/i in GLOB.human_list) - var/mob/living/carbon/human/player = i - if(player.mind && (player.mind.assigned_role in GLOB.security_positions)) - . |= player.mind + for(var/mob/living/carbon/human/player as anything in GLOB.human_list) + if(player.mind?.assigned_role.departments & DEPARTMENT_SECURITY) + . += player.mind /datum/controller/subsystem/job/proc/JobDebug(message) log_job_debug(message) @@ -839,4 +786,4 @@ SUBSYSTEM_DEF(job) /// Blindly assigns the required roles to every player in the dynamic_forced_occupations list. /datum/controller/subsystem/job/proc/assign_priority_positions() for(var/mob/new_player in dynamic_forced_occupations) - AssignRole(new_player, dynamic_forced_occupations[new_player]) + AssignRole(new_player, GetJob(dynamic_forced_occupations[new_player])) diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index dbd7b7e1834..c4f00ac7215 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -63,10 +63,6 @@ PROCESSING_SUBSYSTEM_DEF(quirks) if(badquirk) cli.prefs.save_character() - if(ishuman(user)) - var/mob/living/carbon/human/human = user - human.hardcore_survival_score = cli.prefs.hardcore_survival_score //Only do this if we actually asign quirks, to prevent sillicons etc from getting the points. - // Assign wayfinding pinpointer granting quirk if they're new if(cli.get_exp_living(TRUE) < EXP_ASSIGN_WAYFINDER && !user.has_quirk(/datum/quirk/item_quirk/needswayfinder)) user.add_quirk(/datum/quirk/item_quirk/needswayfinder) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 308de11d31a..2e85c319a0c 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -329,7 +329,11 @@ SUBSYSTEM_DEF(ticker) var/mob/dead/new_player/player = i if(player.ready == PLAYER_READY_TO_PLAY && player.mind) GLOB.joined_player_list += player.ckey - player.create_character(FALSE) + var/atom/destination = player.mind.assigned_role.get_roundstart_spawn_point() + if(!destination) // Failed to fetch a proper roundstart location, won't be going anywhere. + player.new_player_panel() + continue + player.create_character(destination) else player.new_player_panel() CHECK_TICK @@ -359,35 +363,47 @@ SUBSYSTEM_DEF(ticker) if(is_banned_from(new_player_mob.ckey, list("Captain"))) CHECK_TICK continue + if(!ishuman(new_player_mob.new_character)) + continue var/mob/living/carbon/human/new_player_human = new_player_mob.new_character - if(istype(new_player_human) && new_player_human.mind?.assigned_role) - // Keep a rolling tally of who'll get the cap's spare ID vault code. - // Check assigned_role's priority and curate the candidate list appropriately. - var/player_assigned_role = new_player_human.mind.assigned_role - var/spare_id_priority = SSjob.chain_of_command[player_assigned_role] - if(spare_id_priority) - if(spare_id_priority < highest_rank) - spare_id_candidates.Cut() - spare_id_candidates += new_player_mob - highest_rank = spare_id_priority - else if(spare_id_priority == highest_rank) - spare_id_candidates += new_player_mob - CHECK_TICK + if(!new_player_human.mind || is_unassigned_job(new_player_human.mind.assigned_role)) + continue + // Keep a rolling tally of who'll get the cap's spare ID vault code. + // Check assigned_role's priority and curate the candidate list appropriately. + var/player_assigned_role = new_player_human.mind.assigned_role.title + var/spare_id_priority = SSjob.chain_of_command[player_assigned_role] + if(spare_id_priority) + if(spare_id_priority < highest_rank) + spare_id_candidates.Cut() + spare_id_candidates += new_player_mob + highest_rank = spare_id_priority + else if(spare_id_priority == highest_rank) + spare_id_candidates += new_player_mob + CHECK_TICK if(length(spare_id_candidates)) picked_spare_id_candidate = pick(spare_id_candidates) for(var/mob/dead/new_player/new_player_mob as anything in GLOB.new_player_list) + if(!isliving(new_player_mob.new_character)) + CHECK_TICK + continue var/mob/living/new_player_living = new_player_mob.new_character - if(istype(new_player_living) && new_player_living.mind?.assigned_role) - var/player_assigned_role = new_player_living.mind.assigned_role - var/player_is_captain = (picked_spare_id_candidate == new_player_mob) || (SSjob.always_promote_captain_job && (player_assigned_role == "Captain")) - if(player_is_captain) - captainless = FALSE - if(player_assigned_role != new_player_living.mind.special_role) - new_player_living = SSjob.EquipRank(new_player_mob, player_assigned_role, FALSE, player_is_captain) - if(CONFIG_GET(flag/roundstart_traits) && ishuman(new_player_living)) - SSquirks.AssignQuirks(new_player_living, new_player_mob.client) + if(!new_player_living.mind || is_unassigned_job(new_player_living.mind.assigned_role)) + CHECK_TICK + continue + var/datum/job/player_assigned_role = new_player_living.mind.assigned_role + if(ishuman(new_player_living) && CONFIG_GET(flag/roundstart_traits)) + if(new_player_mob.client.prefs.should_be_random_hardcore(player_assigned_role, new_player_living.mind)) + new_player_mob.client.prefs.hardcore_random_setup(new_player_living) + SSquirks.AssignQuirks(new_player_living, new_player_mob.client) + if(player_assigned_role.job_flags & JOB_EQUIP_RANK) + SSjob.EquipRank(new_player_living, player_assigned_role, new_player_mob.client) + if(picked_spare_id_candidate == new_player_mob) + captainless = FALSE + var/acting_captain = !is_captain_job(player_assigned_role) + SSjob.promote_to_captain(new_player_living, acting_captain) + OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, player_assigned_role.get_captaincy_announcement(new_player_living))) CHECK_TICK if(captainless) @@ -397,6 +413,7 @@ SUBSYSTEM_DEF(ticker) to_chat(new_player_mob, span_notice("Captainship not forced on anyone.")) CHECK_TICK + /datum/controller/subsystem/ticker/proc/decide_security_officer_departments( list/new_players, list/departments, @@ -406,7 +423,7 @@ SUBSYSTEM_DEF(ticker) for (var/mob/dead/new_player/new_player_mob as anything in new_players) var/mob/living/carbon/human/character = new_player_mob.new_character - if (istype(character) && character.mind?.assigned_role == "Security Officer") + if (istype(character) && is_security_officer_job(character.mind?.assigned_role)) officer_mobs += character var/datum/client_interface/client = GET_CLIENT(new_player_mob) diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 9d5dfbabb8d..9d13af33caf 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -122,12 +122,15 @@ var/list/special_pool = list() //The special list, for quirk-based var/chosen_victim //The obsession target - for(var/mob/Player in GLOB.player_list)//prevents crewmembers falling in love with nuke ops they never met, and other annoying hijinks - if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client && Player != owner && SSjob.GetJob(Player.mind.assigned_role)) - viable_minds += Player.mind - for(var/datum/mind/possible_target in viable_minds) + for(var/mob/player as anything in GLOB.player_list)//prevents crewmembers falling in love with nuke ops they never met, and other annoying hijinks + if(!player.client || !player.mind || isnewplayer(player) || player.stat == DEAD || isbrain(player) || player == owner) + continue + if(!(player.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) + continue + viable_minds += player.mind + for(var/datum/mind/possible_target as anything in viable_minds) if(possible_target != owner && ishuman(possible_target.current)) - var/job = possible_target.assigned_role + var/job = possible_target.assigned_role.title if (trait_obsessions[job] != null && HAS_TRAIT(owner, trait_obsessions[job])) special_pool += possible_target.current possible_targets += possible_target.current diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 50b877ae45c..ae61315098e 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -105,7 +105,7 @@ var/gender = pick(MALE, FEMALE) real_name = random_unique_name(gender) name = real_name - human_image = get_flat_human_icon(null, pick(SSjob.occupations)) + human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations)) /mob/camera/imaginary_friend/proc/Show() if(!client) //nobody home diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index aceceac67f8..cfc7504885f 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -167,12 +167,8 @@ var/datum/uplink_item/I = uplink_items[category][item] if(I.limited_stock == 0) continue - if(I.restricted_roles.len) - var/is_inaccessible = TRUE - for(var/R in I.restricted_roles) - if(R == user.mind.assigned_role || debug) - is_inaccessible = FALSE - if(is_inaccessible) + if(length(I.restricted_roles)) + if(!debug && !(user.mind.assigned_role.title in I.restricted_roles)) continue if(I.restricted_species) if(ishuman(user)) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index f0f26775af4..95990b75159 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -227,14 +227,8 @@ /datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C) set waitfor = FALSE var/static/list/show_directions = list(SOUTH, WEST) - if(H.mind && (H.mind.assigned_role != H.mind.special_role)) - var/assignment - if(H.mind.assigned_role) - assignment = H.mind.assigned_role - else if(H.job) - assignment = H.job - else - assignment = "Unassigned" + if(H.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST) + var/assignment = H.mind.assigned_role.title var/static/record_id_num = 1001 var/id = num2hex(record_id_num++,6) @@ -302,9 +296,9 @@ //Locked Record var/datum/data/record/L = new() - L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]") //surely this should just be id, like the others? + L.fields["id"] = md5("[H.real_name][assignment]") //surely this should just be id, like the others? L.fields["name"] = H.real_name - L.fields["rank"] = H.mind.assigned_role + L.fields["rank"] = assignment L.fields["age"] = H.age L.fields["gender"] = H.gender if(H.gender == "male") @@ -324,7 +318,7 @@ return /datum/datacore/proc/get_id_photo(mob/living/carbon/human/H, client/C, show_directions = list(SOUTH)) - var/datum/job/J = SSjob.GetJob(H.mind.assigned_role) + var/datum/job/J = H.mind.assigned_role var/datum/preferences/P if(!C) C = H.client diff --git a/code/datums/dna.dm b/code/datums/dna.dm index cc5ccb49936..f5ad9f5c547 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -471,7 +471,7 @@ /mob/living/carbon/proc/create_dna() dna = new /datum/dna(src) if(!dna.species) - var/rando_race = pick(GLOB.roundstart_races) + var/rando_race = GLOB.species_list[pick(GLOB.roundstart_races)] dna.species = new rando_race() //proc used to update the mob's appearance after its dna UI has been changed diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index f4e5847cfc8..5eae09c57a4 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -227,10 +227,6 @@ /// Refreshes the valid areas from the cook job singleton, otherwise uses the default kitchen area as a fallback option. See also [/datum/job/cook/New]. /datum/martial_art/cqc/under_siege/proc/refresh_valid_areas() var/datum/job/cook/cook_job = SSjob.GetJobType(/datum/job/cook) - if(!istype(cook_job)) - kitchen_areas = list(/area/service/kitchen) - return - kitchen_areas = cook_job.kitchen_areas.Copy() /// Limits where the chef's CQC can be used to only whitelisted areas. diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0db7909c5bd..36a6d8b5984 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -38,7 +38,8 @@ var/memory - var/assigned_role + /// Job datum indicating the mind's role. This should always exist after initialization, as a reference to a singleton. + var/datum/job/assigned_role var/special_role var/list/restricted_roles = list() var/list/datum/objective/objectives = list() @@ -92,6 +93,7 @@ key = _key martial_art = default_martial_art init_known_skills() + set_assigned_role(SSjob.GetJobType(/datum/job/unassigned)) // Unassigned by default. /datum/mind/Destroy() SSticker.minds -= src @@ -495,10 +497,14 @@ A.admin_remove(usr) if (href_list["role_edit"]) - var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in sortList(SSjob.station_jobs) - if (!new_role) + var/new_role = input("Select new role", "Assigned role", assigned_role.title) as null|anything in sortList(SSjob.station_jobs) + if(isnull(new_role)) return - assigned_role = new_role + var/datum/job/new_job = SSjob.GetJob(new_role) + if (!new_job) + to_chat(usr, span_warning("Job not found.")) + return + set_assigned_role(new_role) else if (href_list["memory_edit"]) var/new_memo = stripped_multiline_input(usr, "Write new memory", "Memory", memory, MAX_MESSAGE_LEN) @@ -695,11 +701,14 @@ special_role = ROLE_CHANGELING return C + /datum/mind/proc/make_wizard() - if(!has_antag_datum(/datum/antagonist/wizard)) - special_role = ROLE_WIZARD - assigned_role = ROLE_WIZARD - add_antag_datum(/datum/antagonist/wizard) + if(has_antag_datum(/datum/antagonist/wizard)) + return + set_assigned_role(SSjob.GetJobType(/datum/job/space_wizard)) + special_role = ROLE_WIZARD + add_antag_datum(/datum/antagonist/wizard) + /datum/mind/proc/make_rev() var/datum/antagonist/rev/head/head = new() @@ -803,12 +812,22 @@ var/datum/addiction/affected_addiction = SSaddiction.all_addictions[type] return affected_addiction.on_lose_addiction_points(src) + +/// Setter for the assigned_role job datum. +/datum/mind/proc/set_assigned_role(datum/job/new_role) + if(assigned_role == new_role) + return + . = assigned_role + assigned_role = new_role + + /mob/dead/new_player/sync_mind() return /mob/dead/observer/sync_mind() return + //Initialisation procs /mob/proc/mind_initialize() if(mind) @@ -821,28 +840,26 @@ mind.name = real_name mind.set_current(src) + /mob/living/carbon/mind_initialize() ..() last_mind = mind -//HUMAN -/mob/living/carbon/human/mind_initialize() - ..() - if(!mind.assigned_role) - mind.assigned_role = "Unassigned" //default //AI /mob/living/silicon/ai/mind_initialize() - ..() - mind.assigned_role = "AI" + . = ..() + mind.set_assigned_role(SSjob.GetJobType(/datum/job/ai)) + //BORG /mob/living/silicon/robot/mind_initialize() - ..() - mind.assigned_role = "Cyborg" + . = ..() + mind.set_assigned_role(SSjob.GetJobType(/datum/job/cyborg)) + //PAI /mob/living/silicon/pai/mind_initialize() - ..() - mind.assigned_role = ROLE_PAI + . = ..() + mind.set_assigned_role(SSjob.GetJobType(/datum/job/personal_ai)) mind.special_role = "" diff --git a/code/datums/mutations/holy_mutation/honorbound.dm b/code/datums/mutations/holy_mutation/honorbound.dm index fc72db7748c..0426710fd67 100644 --- a/code/datums/mutations/holy_mutation/honorbound.dm +++ b/code/datums/mutations/holy_mutation/honorbound.dm @@ -79,8 +79,8 @@ return var/datum/mind/guilty_conscience = user.mind if(guilty_conscience) //sec and medical are immune to becoming guilty through attack (we don't check holy because holy shouldn't be able to attack eachother anyways) - var/job = guilty_conscience.assigned_role - if(job in (GLOB.security_positions + GLOB.medical_positions)) + var/datum/job/job = guilty_conscience.assigned_role + if(job.departments & (DEPARTMENT_MEDICAL | DEPARTMENT_SECURITY)) return if(declaration) to_chat(owner, span_notice("[user] is now considered guilty by [GLOB.deity] from your declaration.")) @@ -107,12 +107,12 @@ //THE JUST (Applies over guilt except for med, so you best be careful!) if(ishuman(target_creature)) var/mob/living/carbon/human/target_human = target_creature - var/job = target_human.mind?.assigned_role + var/datum/job/job = target_human.mind?.assigned_role var/is_holy = target_human.mind?.holy_role - if(job in GLOB.security_positions || is_holy) + if(is_holy || (job?.departments & DEPARTMENT_SECURITY)) to_chat(honorbound_human, span_warning("There is nothing righteous in attacking the just.")) return FALSE - if(job in GLOB.medical_positions) + if(job?.departments & DEPARTMENT_MEDICAL) to_chat(honorbound_human, span_warning("If you truly think this healer is not innocent, declare them guilty.")) return FALSE //THE INNOCENT @@ -272,7 +272,7 @@ if(!silent) to_chat(user, span_warning("Followers of [GLOB.deity] cannot be evil!")) return FALSE - if(guilty_conscience.assigned_role in GLOB.security_positions) + if(guilty_conscience.assigned_role.departments & DEPARTMENT_SECURITY) if(!silent) to_chat(user, span_warning("Members of security are uncorruptable! You cannot declare one evil!")) return FALSE diff --git a/code/datums/quirks/negative.dm b/code/datums/quirks/negative.dm index 3510c39ec41..335901bd364 100644 --- a/code/datums/quirks/negative.dm +++ b/code/datums/quirks/negative.dm @@ -166,7 +166,7 @@ heirloom_type = pick(holder_species.family_heirlooms) else // Our quirk holder's job - var/datum/job/holder_job = SSjob.GetJob(human_holder.mind?.assigned_role) + var/datum/job/holder_job = human_holder.mind?.assigned_role if(holder_job && LAZYLEN(holder_job.family_heirlooms)) heirloom_type = pick(holder_job.family_heirlooms) diff --git a/code/datums/quirks/neutral.dm b/code/datums/quirks/neutral.dm index 8db41b269ec..4510717dc56 100644 --- a/code/datums/quirks/neutral.dm +++ b/code/datums/quirks/neutral.dm @@ -147,7 +147,7 @@ quirk_holder.add_client_colour(/datum/client_colour/monochrome) /datum/quirk/monochromatic/post_add() - if(quirk_holder.mind.assigned_role == "Detective") + if(is_detective_job(quirk_holder.mind.assigned_role)) to_chat(quirk_holder, span_boldannounce("Mmm. Nothing's ever clear on this station. It's all shades of gray...")) quirk_holder.playsound_local(quirk_holder, 'sound/ambience/ambidet1.ogg', 50, FALSE) diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index 04004e8c4a9..ab1796e35ee 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -46,17 +46,26 @@ /datum/station_trait/hangover/New() . = ..() - RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn) + RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN, .proc/on_job_after_spawn) -/datum/station_trait/hangover/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/spawned_mob, joined_late) + +/datum/station_trait/hangover/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned_mob) SIGNAL_HANDLER - if(joined_late) + if(!prob(35)) return - if(prob(35)) - var/obj/item/hat = pick(list(/obj/item/clothing/head/sombrero, /obj/item/clothing/head/fedora, /obj/item/clothing/mask/balaclava, /obj/item/clothing/head/ushanka, /obj/item/clothing/head/cardborg, /obj/item/clothing/head/pirate, /obj/item/clothing/head/cone)) - hat = new hat(spawned_mob) - spawned_mob.equip_to_slot(hat, ITEM_SLOT_HEAD) + var/obj/item/hat = pick( + /obj/item/clothing/head/sombrero, + /obj/item/clothing/head/fedora, + /obj/item/clothing/mask/balaclava, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/cardborg, + /obj/item/clothing/head/pirate, + /obj/item/clothing/head/cone, + ) + hat = new hat(spawned_mob) + spawned_mob.equip_to_slot_or_del(hat, ITEM_SLOT_HEAD) + /datum/station_trait/blackout name = "Blackout" @@ -86,11 +95,20 @@ trait_type = STATION_TRAIT_NEGATIVE weight = 5 show_in_report = TRUE - var/list/jobs_to_use = list("Clown", "Bartender", "Cook", "Botanist", "Cargo Technician", "Mime", "Janitor", "Prisoner") var/chosen_job /datum/station_trait/overflow_job_bureaucracy/New() . = ..() + var/list/jobs_to_use = list( + /datum/job/clown, + /datum/job/bartender, + /datum/job/cook, + /datum/job/botanist, + /datum/job/cargo_technician, + /datum/job/mime, + /datum/job/janitor, + /datum/job/prisoner, + ) chosen_job = pick(jobs_to_use) RegisterSignal(SSjob, COMSIG_SUBSYSTEM_POST_INITIALIZE, .proc/set_overflow_job_override) diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index 585588e97b7..e26c3d5232f 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -97,11 +97,13 @@ RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn) -/datum/station_trait/scarves/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/M, joined_late) + +/datum/station_trait/scarves/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) SIGNAL_HANDLER var/scarf_type = pick(scarves) - living_mob.equip_to_slot_or_del(new scarf_type(living_mob), ITEM_SLOT_NECK, initial = FALSE) + spawned.equip_to_slot_or_del(new scarf_type(spawned), ITEM_SLOT_NECK, initial = FALSE) + /datum/station_trait/filled_maint name = "Filled up maintenance" @@ -143,7 +145,8 @@ report_message = "All members of [department_name] have received an implant to notify each other if one of them dies. This should help improve job-safety!" RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn) -/datum/station_trait/deathrattle_department/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/M, joined_late) + +/datum/station_trait/deathrattle_department/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) SIGNAL_HANDLER if(!(job.departments & department_to_apply_to)) @@ -151,7 +154,7 @@ var/obj/item/implant/deathrattle/implant_to_give = new() deathrattle_group.register(implant_to_give) - implant_to_give.implant(living_mob, living_mob, TRUE, TRUE) + implant_to_give.implant(spawned, spawned, TRUE, TRUE) /datum/station_trait/deathrattle_department/service @@ -211,12 +214,13 @@ blacklist = subtypesof(/datum/station_trait/deathrattle_department) RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, .proc/on_job_after_spawn) -/datum/station_trait/deathrattle_all/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/M, joined_late) + +/datum/station_trait/deathrattle_all/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) SIGNAL_HANDLER var/obj/item/implant/deathrattle/implant_to_give = new() deathrattle_group.register(implant_to_give) - implant_to_give.implant(living_mob, living_mob, TRUE, TRUE) + implant_to_give.implant(spawned, spawned, TRUE, TRUE) /datum/station_trait/wallets diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index b8a3d99e41f..b7eb87e0bf9 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -68,18 +68,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) to_remove_string = "(\\L|^)([to_remove_string])(\\L|$)" message = replacetext(message, regex(to_remove_string, "i"), "") - var/power_multiplier = base_multiplier - - if(user.mind) - //Chaplains are very good at speaking with the voice of god - if(user.mind.assigned_role == "Chaplain") - power_multiplier *= 2 - //Command staff has authority - if(user.mind.assigned_role in GLOB.command_positions) - power_multiplier *= 1.4 - //Why are you speaking - if(user.mind.assigned_role == "Mime") - power_multiplier *= 0.5 + var/power_multiplier = base_multiplier * (user.mind?.assigned_role.voice_of_god_power || 1) //Cultists are closer to their gods and are more powerful, but they'll give themselves away if(is_cultie) @@ -88,7 +77,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) //Now get the proper job titles and check for matches. var/job_message = get_full_job_name(message) for(var/mob/living/candidate in candidates) - var/their_role = candidate.mind?.assigned_role + var/their_role = candidate.mind?.assigned_role.title if(their_role && findtext(job_message, their_role)) specific_listeners |= candidate //focus on those with the specified job. "|=" instead "+=" so "Mrs. Capri the Captain" doesn't get affected twice. @@ -154,8 +143,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) cooldown = COOLDOWN_STUN /datum/voice_of_god_command/silence/execute(list/listeners, mob/living/user, power_multiplier = 1, message) - if(user.mind && (user.mind.assigned_role == "Curator" || user.mind.assigned_role == "Mime")) - power_multiplier *= 3 + power_multiplier *= user.mind?.assigned_role?.voice_of_god_silence_power || 1 for(var/mob/living/carbon/target in listeners) target.silent += (10 * power_multiplier) @@ -400,7 +388,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) /datum/voice_of_god_command/honk/execute(list/listeners, mob/living/user, power_multiplier = 1, message) addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(user), 'sound/items/bikehorn.ogg', 300, 1), 2.5 SECONDS) - if(user.mind?.assigned_role == "Clown") + if(is_clown_job(user.mind?.assigned_role)) . = COOLDOWN_STUN //it slips. for(var/mob/living/carbon/target in listeners) target.slip(14 SECONDS * power_multiplier) diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index 2153104c91c..71ad1478565 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -166,7 +166,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) add_hud_to(mob) /datum/atom_hud/alternate_appearance/basic/blessed_aware/mobShouldSee(mob/M) - if(M.mind && (M.mind.assigned_role == "Chaplain")) + if(is_chaplain_job(M.mind?.assigned_role)) return TRUE if (istype(M, /mob/living/simple_animal/hostile/construct/wraith)) return TRUE diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 4495dbbb96c..eed4a3cfb23 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -681,3 +681,8 @@ GLOBAL_LIST_EMPTY(teleportlocs) /// A hook so areas can modify the incoming args (of what??) /area/proc/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags) return flags + + +/// Called when a living mob that spawned here, joining the round, receives the player client. +/area/proc/on_joining_game(mob/living/boarder) + return diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 7ae8a43e3a8..d6dd38e64ac 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -99,10 +99,20 @@ desc = "Weeeeee" dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + /area/shuttle/arrival name = "Arrival Shuttle" area_flags = UNIQUE_AREA// SSjob refers to this area for latejoiners + +/area/shuttle/arrival/on_joining_game(mob/living/boarder) + if(SSshuttle.arrivals?.mode == SHUTTLE_CALL) + var/atom/movable/screen/splash/Spl = new(boarder.client, TRUE) + Spl.Fade(TRUE) + boarder.playsound_local(get_turf(boarder), 'sound/voice/ApproachingTG.ogg', 25) + boarder.update_parallax_teleport() + + /area/shuttle/pod_1 name = "Escape Pod One" area_flags = NONE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index fe1721b1c77..b4eeae7ec9f 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -6,13 +6,13 @@ /datum/dynamic_ruleset/latejoin/trim_candidates() for(var/mob/P in candidates) - if(!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? + if(!P.client || !P.mind || is_unassigned_job(P.mind.assigned_role)) // Are they connected? candidates.Remove(P) else if (P.client.get_remaining_days(minimum_required_age) > 0) candidates.Remove(P) - else if(P.mind.assigned_role in restricted_roles) // Does their job allow for it? + else if(P.mind.assigned_role.title in restricted_roles) // Does their job allow for it? candidates.Remove(P) - else if((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + else if((exclusive_roles.len > 0) && !(P.mind.assigned_role.title in exclusive_roles)) // Is the rule exclusive to their job? candidates.Remove(P) else if(antag_flag_override) if(!(antag_flag_override in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))) @@ -28,7 +28,7 @@ for (var/mob/M in GLOB.alive_player_list) if (M.stat == DEAD) continue // Dead players cannot count as opponents - if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + if (M.mind && (M.mind.assigned_role.title in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role.title in restricted_roles))) job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it var/threat = round(mode.threat_level/10) @@ -96,7 +96,7 @@ return FALSE var/head_check = 0 for(var/mob/player in GLOB.alive_player_list) - if (player.mind.assigned_role in GLOB.command_positions) + if (player.mind.assigned_role.departments & DEPARTMENT_COMMAND) head_check++ return (head_check >= required_heads_of_staff) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index ffb6679af7f..98854b7f000 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -55,13 +55,13 @@ trimmed_list.Remove(M) continue if (M.mind) - if (restrict_ghost_roles && (M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])) // Are they playing a ghost role? + if (restrict_ghost_roles && (M.mind.assigned_role.title in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])) // Are they playing a ghost role? trimmed_list.Remove(M) continue - if (M.mind.assigned_role in restricted_roles) // Does their job allow it? + if (M.mind.assigned_role.title in restricted_roles) // Does their job allow it? trimmed_list.Remove(M) continue - if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + if ((exclusive_roles.len > 0) && !(M.mind.assigned_role.title in exclusive_roles)) // Is the rule exclusive to their job? trimmed_list.Remove(M) continue return trimmed_list @@ -78,7 +78,7 @@ for (var/mob/M in GLOB.alive_player_list) if (M.stat == DEAD || !M.client) continue // Dead/disconnected players cannot count as opponents - if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + if (M.mind && (M.mind.assigned_role.title in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role.title in restricted_roles))) job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it var/threat = round(mode.threat_level/10) @@ -422,8 +422,8 @@ return ..() /datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index) - new_character.mind.special_role = "Nuclear Operative" - new_character.mind.assigned_role = "Nuclear Operative" + new_character.mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + new_character.mind.special_role = ROLE_NUCLEAR_OPERATIVE if (index == 1) // Our first guy is the leader var/datum/antagonist/nukeop/leader/new_role = new nuke_team = new_role.nuke_team @@ -543,7 +543,7 @@ /datum/dynamic_ruleset/midround/from_ghosts/nightmare name = "Nightmare" antag_datum = /datum/antagonist/nightmare - antag_flag = "Nightmare" + antag_flag = ROLE_NIGHTMARE antag_flag_override = ROLE_ALIEN enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") required_enemies = list(2,2,1,1,1,1,1,0,0,0) @@ -570,8 +570,8 @@ var/mob/living/carbon/human/S = new (pick(spawn_locs)) player_mind.transfer_to(S) - player_mind.assigned_role = "Nightmare" - player_mind.special_role = "Nightmare" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nightmare)) + player_mind.special_role = ROLE_NIGHTMARE player_mind.add_antag_datum(/datum/antagonist/nightmare) S.set_species(/datum/species/shadow/nightmare) @@ -589,7 +589,7 @@ /datum/dynamic_ruleset/midround/from_ghosts/space_dragon name = "Space Dragon" antag_datum = /datum/antagonist/space_dragon - antag_flag = "Space Dragon" + antag_flag = ROLE_SPACE_DRAGON antag_flag_override = ROLE_SPACE_DRAGON enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") required_enemies = list(2,2,1,1,1,1,1,0,0,0) @@ -614,8 +614,8 @@ var/mob/living/simple_animal/hostile/space_dragon/S = new (pick(spawn_locs)) player_mind.transfer_to(S) - player_mind.assigned_role = "Space Dragon" - player_mind.special_role = "Space Dragon" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon)) + player_mind.special_role = ROLE_SPACE_DRAGON player_mind.add_antag_datum(/datum/antagonist/space_dragon) playsound(S, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index b05d9b83d3b..41a52444695 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -60,9 +60,7 @@ flags = HIGH_IMPACT_RULESET /datum/dynamic_ruleset/roundstart/malf_ai/ready(forced) - var/datum/job/ai_job = SSjob.GetJob("AI") - if(!ai_job) - return FALSE + var/datum/job/ai_job = SSjob.GetJobType(/datum/job/ai) // If we're not forced, we're going to make sure we can actually have an AI in this shift, if(!forced && min(ai_job.total_positions - ai_job.current_positions, ai_job.spawn_positions) <= 0) @@ -73,7 +71,7 @@ /datum/dynamic_ruleset/roundstart/malf_ai/pre_execute(population) . = ..() - var/datum/job/ai_job = SSjob.GetJob("AI") + var/datum/job/ai_job = SSjob.GetJobType(/datum/job/ai) // Maybe a bit too pedantic, but there should never be more malf AIs than there are available positions, spawn positions or antag cap allocations. var/num_malf = min(get_antag_cap(population), min(ai_job.total_positions - ai_job.current_positions, ai_job.spawn_positions)) for (var/i in 1 to num_malf) @@ -248,7 +246,7 @@ var/mob/M = pick_n_take(candidates) if (M) assigned += M.mind - M.mind.assigned_role = ROLE_WIZARD + M.mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_wizard)) M.mind.special_role = ROLE_WIZARD return TRUE @@ -350,8 +348,8 @@ break var/mob/M = pick_n_take(candidates) assigned += M.mind - M.mind.assigned_role = "Nuclear Operative" - M.mind.special_role = "Nuclear Operative" + M.mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + M.mind.special_role = ROLE_NUCLEAR_OPERATIVE return TRUE /datum/dynamic_ruleset/roundstart/nuclear/execute() @@ -577,8 +575,8 @@ qdel(S) new /obj/machinery/nuclearbomb/syndicate/bananium(T) for(var/datum/mind/V in assigned) - V.assigned_role = "Clown Operative" - V.special_role = "Clown Operative" + V.set_assigned_role(SSjob.GetJobType(/datum/job/clown_operative)) + V.special_role = ROLE_CLOWN_OPERATIVE ////////////////////////////////////////////// diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 2814fc857f9..a622e6cc247 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -150,31 +150,6 @@ GLOBAL_LIST_EMPTY(objectives) update_explanation_text() return target -/datum/objective/proc/find_target_by_role(role, role_type=FALSE,invert=FALSE)//Option sets either to check assigned role or special role. Default to assigned., invert inverts the check, eg: "Don't choose a Ling" - var/list/datum/mind/owners = get_owners() - var/list/possible_targets = list() - for(var/datum/mind/possible_target in get_crewmember_minds()) - if(!(possible_target in owners) && ishuman(possible_target.current)) - var/is_role = FALSE - if(role_type) - if(possible_target.special_role == role) - is_role = TRUE - else - if(possible_target.assigned_role == role) - is_role = TRUE - - if(invert) - if(is_role) - continue - possible_targets += possible_target - break - else if(is_role) - possible_targets += possible_target - break - if(length(possible_targets)) - target = pick(possible_targets) - update_explanation_text() - return target /datum/objective/proc/update_explanation_text() if(team_explanation_text && LAZYLEN(get_owners()) > 1) @@ -195,10 +170,6 @@ GLOBAL_LIST_EMPTY(objectives) var/target_role_type=FALSE martyr_compatible = TRUE -/datum/objective/assassinate/find_target_by_role(role, role_type=FALSE,invert=FALSE) - if(!invert) - target_role_type = role_type - ..() /datum/objective/assassinate/check_completion() return completed || (!considered_alive(target) || considered_afk(target) || considered_exiled(target)) @@ -206,7 +177,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/assassinate/update_explanation_text() ..() if(target?.current) - explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." else explanation_text = "Free Objective" @@ -226,10 +197,6 @@ GLOBAL_LIST_EMPTY(objectives) var/target_role_type=FALSE martyr_compatible = 1 -/datum/objective/mutiny/find_target_by_role(role, role_type=FALSE,invert=FALSE) - if(!invert) - target_role_type = role_type - ..() /datum/objective/mutiny/check_completion() if(!target || !considered_alive(target) || considered_afk(target) || considered_exiled(target)) @@ -240,7 +207,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/mutiny/update_explanation_text() ..() if(target?.current) - explanation_text = "Assassinate or exile [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + explanation_text = "Assassinate or exile [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." else explanation_text = "Free Objective" @@ -249,17 +216,13 @@ GLOBAL_LIST_EMPTY(objectives) var/target_role_type=FALSE martyr_compatible = TRUE -/datum/objective/maroon/find_target_by_role(role, role_type=FALSE,invert=FALSE) - if(!invert) - target_role_type = role_type - ..() /datum/objective/maroon/check_completion() return !target || !considered_alive(target) || (!target.current.onCentCom() && !target.current.onSyndieBase()) /datum/objective/maroon/update_explanation_text() if(target?.current) - explanation_text = "Prevent [target.name], the [!target_role_type ? target.assigned_role : target.special_role], from escaping alive." + explanation_text = "Prevent [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role], from escaping alive." else explanation_text = "Free Objective" @@ -270,10 +233,6 @@ GLOBAL_LIST_EMPTY(objectives) name = "debrain" var/target_role_type=0 -/datum/objective/debrain/find_target_by_role(role, role_type=FALSE,invert=FALSE) - if(!invert) - target_role_type = role_type - ..() /datum/objective/debrain/check_completion() if(!target)//If it's a free objective. @@ -293,7 +252,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/debrain/update_explanation_text() ..() if(target?.current) - explanation_text = "Steal the brain of [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + explanation_text = "Steal the brain of [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." else explanation_text = "Free Objective" @@ -306,11 +265,6 @@ GLOBAL_LIST_EMPTY(objectives) var/target_role_type = FALSE var/human_check = TRUE -/datum/objective/protect/find_target_by_role(role, role_type=FALSE,invert=FALSE) - if(!invert) - target_role_type = role_type - ..() - return target /datum/objective/protect/check_completion() var/obj/item/organ/brain/brain_target @@ -322,7 +276,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/protect/update_explanation_text() ..() if(target?.current) - explanation_text = "Protect [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + explanation_text = "Protect [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." else explanation_text = "Free Objective" @@ -338,10 +292,6 @@ GLOBAL_LIST_EMPTY(objectives) martyr_compatible = TRUE //why not? var/target_role_type -/datum/objective/jailbreak/find_target_by_role(role, role_type, invert=FALSE) - if(!invert) - target_role_type = role_type - return ..() /datum/objective/jailbreak/check_completion() return completed || (considered_escaped(target)) @@ -349,7 +299,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/jailbreak/update_explanation_text() ..() if(target?.current) - explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role : target.special_role] escapes alive and out of custody." + explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role] escapes alive and out of custody." else explanation_text = "Free Objective" @@ -365,7 +315,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/jailbreak/detain/update_explanation_text() ..() if(target?.current) - explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role : target.special_role] is delivered to nanotrasen alive and in custody." + explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role] is delivered to nanotrasen alive and in custody." else explanation_text = "Free Objective" @@ -485,7 +435,7 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/escape/escape_with_identity/update_explanation_text() if(target?.current) target_real_name = target.current.real_name - explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role]" + explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role.title]" var/mob/living/carbon/human/H if(ishuman(target.current)) H = target.current @@ -597,7 +547,7 @@ GLOBAL_LIST_EMPTY(possible_items) if(!is_unique_objective(possible_item.targetitem,dupe_search_range)) continue for(var/datum/mind/M in owners) - if(M.current.mind.assigned_role in possible_item.excludefromjob) + if(M.current.mind.assigned_role.title in possible_item.excludefromjob) continue check_items approved_targets += possible_item if (length(approved_targets)) diff --git a/code/game/machinery/computer/arena.dm b/code/game/machinery/computer/arena.dm index d264cd24418..931d31867c6 100644 --- a/code/game/machinery/computer/arena.dm +++ b/code/game/machinery/computer/arena.dm @@ -188,7 +188,7 @@ if(!isobserver(oldbody)) return var/mob/living/carbon/human/M = new/mob/living/carbon/human(get_turf(spawnpoint)) - oldbody.client.prefs.copy_to(M) + oldbody.client.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) M.set_species(/datum/species/human) // Could use setting per team M.equipOutfit(outfits[team] ? outfits[team] : default_outfit) M.faction += team //In case anyone wants to add team based stuff to arena special effects diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index b43863be3f3..ce035532d66 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -226,9 +226,9 @@ GLOBAL_LIST_EMPTY(cryopod_computers) crew_member["name"] = mob_occupant.real_name - if(mob_occupant.mind && mob_occupant.mind.assigned_role) + if(mob_occupant.mind) // Handle job slot/tater cleanup. - var/job = mob_occupant.mind.assigned_role + var/job = mob_occupant.mind.assigned_role.title crew_member["job"] = job SSjob.FreeRole(job) if(LAZYLEN(mob_occupant.mind.objectives)) @@ -300,12 +300,9 @@ GLOBAL_LIST_EMPTY(cryopod_computers) return if(target == user) - var/datum/antagonist/antag = target.mind.has_antag_datum(/datum/antagonist) - - var/datum/job/target_job = SSjob.GetJob(target.mind.assigned_role) - - if(target_job && target_job.req_admin_notify) + if(target.mind.assigned_role.req_admin_notify) tgui_alert(target, "You're an important role! [AHELP_FIRST_MESSAGE]") + var/datum/antagonist/antag = target.mind.has_antag_datum(/datum/antagonist) if(antag) tgui_alert(target, "You're \a [antag.name]! [AHELP_FIRST_MESSAGE]") diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index d6d76e8e943..2f01db6189d 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -136,7 +136,7 @@ short_desc = "You are a spider." important_info = "Follow your directives at all costs." faction = list("spiders") - assignedrole = "Spider" + spawner_job_path = /datum/job/spider banType = ROLE_ALIEN ready = FALSE radial_based = TRUE diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 30f255c0702..335adef94b9 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -761,7 +761,7 @@ var/intern_threshold = (CONFIG_GET(number/use_low_living_hour_intern_hours) * 60) || (CONFIG_GET(number/use_exp_restrictions_heads_hours) * 60) || INTERN_THRESHOLD_FALLBACK_HOURS * 60 var/playtime = user.client.get_exp_living(pure_numeric = TRUE) - if((intern_threshold >= playtime) && (user.mind?.assigned_role in SSjob.station_jobs)) + if((intern_threshold >= playtime) && (user.mind?.assigned_role.title in SSjob.station_jobs)) is_intern = TRUE update_label() return diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 63e972468f6..ac877c6d3a2 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -139,13 +139,13 @@ /// Accepts a mind to initialize goodies for a piece of mail. /obj/item/mail/proc/initialize_for_recipient(datum/mind/recipient) - name = "[initial(name)] for [recipient.name] ([recipient.assigned_role])" + name = "[initial(name)] for [recipient.name] ([recipient.assigned_role.title])" recipient_ref = WEAKREF(recipient) var/mob/living/body = recipient.current var/list/goodies = generic_goodies - var/datum/job/this_job = SSjob.name_occupations[recipient.assigned_role] + var/datum/job/this_job = recipient.assigned_role if(this_job) if(this_job.paycheck_department && department_colors[this_job.paycheck_department]) color = department_colors[this_job.paycheck_department] @@ -222,7 +222,7 @@ if(human.stat == DEAD || !human.mind) continue // Skip wizards, nuke ops, cyborgs; Centcom does not send them mail - if(!SSjob.GetJob(human.mind.assigned_role) || (human.mind.assigned_role in GLOB.nonhuman_positions)) + if(!(human.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) continue mail_recipients += human.mind diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index e10da7998ee..a7b2699ad5c 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -45,7 +45,7 @@ if(H.stat == DEAD || H == user) continue if(H.mind && (has_job_loyalties || has_role_loyalties)) - if(has_job_loyalties && (H.mind.assigned_role in job_loyalties)) + if(has_job_loyalties && (H.mind.assigned_role.title in job_loyalties)) inspired += H else if(has_role_loyalties && (H.mind.special_role in role_loyalties)) inspired += H diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index a210e2d3086..4ba45a62d72 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -301,6 +301,7 @@ O.updatename(B.client) B.mind.transfer_to(O) + playsound(O.loc, 'sound/voice/liveagain.ogg', 75, TRUE) if(O.mind && O.mind.special_role) O.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.") diff --git a/code/game/objects/structures/fugitive_role_spawners.dm b/code/game/objects/structures/fugitive_role_spawners.dm index afdff7afec9..18b24584094 100644 --- a/code/game/objects/structures/fugitive_role_spawners.dm +++ b/code/game/objects/structures/fugitive_role_spawners.dm @@ -1,7 +1,7 @@ /obj/effect/mob_spawn/human/fugitive - assignedrole = "Fugitive Hunter" + spawner_job_path = /datum/job/fugitive_hunter flavour_text = "" //the flavor text will be the backstory argument called on the antagonist's greet, see hunter.dm for details roundstart = FALSE death = FALSE diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 9c57a48d29c..d8f9f3fae07 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -17,7 +17,7 @@ Your goal is to protect the vault you are assigned to, cultivate the seeds passed onto you, \ and eventually bring life to this desolate planet while waiting for contact from your creators. \ Estimated time of last contact: Deployment, 5000 millennia ago." - assignedrole = "Lifebringer" + spawner_job_path = /datum/job/lifebringer /obj/effect/mob_spawn/human/seed_vault/special(mob/living/new_spawn) var/plant_name = pick("Tomato", "Potato", "Broccoli", "Carrot", "Ambrosia", "Pumpkin", "Ivy", "Kudzu", "Banana", "Moss", "Flower", "Bloom", "Root", "Bark", "Glowshroom", "Petal", "Leaf", \ @@ -89,7 +89,7 @@ flavour_text = "The wastes are sacred ground, its monsters a blessed bounty. \ You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. \ Fresh sacrifices for your nest." - assignedrole = "Ash Walker" + spawner_job_path = /datum/job/ash_walker var/datum/team/ashwalkers/team var/obj/structure/ash_walker_eggshell/eggshell @@ -149,7 +149,7 @@ short_desc = "You are cursed." flavour_text = "Years ago, you sacrificed the lives of your trusted friends and the humanity of yourself to reach the Wish Granter. Though you \ did so, it has come at a cost: your very body rejects the light, dooming you to wander endlessly in this horrible wasteland." - assignedrole = "Exile" + spawner_job_path = /datum/job/exile /obj/effect/mob_spawn/human/exile/Destroy() new/obj/structure/fluff/empty_sleeper(get_turf(src)) @@ -230,9 +230,9 @@ else H.fully_replace_character_name(null, name) if(has_owner) - new_spawn.mind.assigned_role = "Servant Golem" + new_spawn.mind.set_assigned_role(SSjob.GetJobType(/datum/job/servant_golem)) else - new_spawn.mind.assigned_role = "Free Golem" + new_spawn.mind.set_assigned_role(SSjob.GetJobType(/datum/job/free_golem)) /obj/effect/mob_spawn/human/golem/attack_hand(mob/user, list/modifiers) . = ..() @@ -283,7 +283,7 @@ flavour_text = "Each day you barely scrape by, and between the terrible conditions of your makeshift shelter, \ the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \ the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you got here... " - assignedrole = "Hermit" + spawner_job_path = /datum/job/hermit /obj/effect/mob_spawn/human/hermit/Initialize(mapload) . = ..() @@ -329,7 +329,7 @@ mob_species = /datum/species/human short_desc = "You've been hunting polar bears for 40 years now! What do these 'NaniteTrans' newcomers want?" flavour_text = "You were fine hunting polar bears and taming wolves out here on your own, but now that there are corporate stooges around, you need to watch your step." - assignedrole = "Hermit" + spawner_job_path = /datum/job/hermit /datum/outfit/hermit name = "Lavaland hermit" @@ -353,7 +353,7 @@ short_desc = "You're a prisoner, sentenced to hard work in one of Nanotrasen's labor camps, but it seems as \ though fate has other plans for you." flavour_text = "Good. It seems as though your ship crashed. You remember that you were convicted of " - assignedrole = "Escaped Prisoner" + spawner_job_path = /datum/job/escaped_prisoner /obj/effect/mob_spawn/human/prisoner_transport/special(mob/living/L) L.fully_replace_character_name(null,"NTP #LL-0[rand(111,999)]") //Nanotrasen Prisoner #Lavaland-(numbers) @@ -392,7 +392,7 @@ short_desc = "You are a staff member of a top-of-the-line space hotel!" flavour_text = "You are a staff member of a top-of-the-line space hotel! Cater to guests, advertise the hotel, and make sure the manager doesn't fire you." important_info = "Do NOT leave the hotel, as that is grounds for contract termination." - assignedrole = "Hotel Staff" + spawner_job_path = /datum/job/hotel_staff /datum/outfit/hotelstaff name = "Hotel Staff" @@ -432,7 +432,7 @@ icon = 'icons/obj/machines/sleeper.dmi' icon_state = "sleeper_s" outfit = /datum/outfit/syndicate_empty - assignedrole = "Space Syndicate" //I know this is really dumb, but Syndicate operative is nuke ops + spawner_job_path = /datum/job/space_syndicate /datum/outfit/syndicate_empty name = "Syndicate Operative Empty" @@ -519,7 +519,7 @@ id = /obj/item/card/id/away/old/sec r_pocket = /obj/item/restraints/handcuffs l_pocket = /obj/item/assembly/flash/handheld - assignedrole = "Ancient Crew" + spawner_job_path = /datum/job/ancient_crew /obj/effect/mob_spawn/human/oldsec/Destroy() new/obj/structure/showcase/machinery/oldpod/used(drop_location()) @@ -545,7 +545,7 @@ id = /obj/item/card/id/away/old/eng gloves = /obj/item/clothing/gloves/color/fyellow/old l_pocket = /obj/item/tank/internals/emergency_oxygen - assignedrole = "Ancient Crew" + spawner_job_path = /datum/job/ancient_crew /obj/effect/mob_spawn/human/oldeng/Destroy() new/obj/structure/showcase/machinery/oldpod/used(drop_location()) @@ -570,7 +570,7 @@ shoes = /obj/item/clothing/shoes/laceup id = /obj/item/card/id/away/old/sci l_pocket = /obj/item/stack/medical/bruise_pack - assignedrole = "Ancient Crew" + spawner_job_path = /datum/job/ancient_crew /obj/effect/mob_spawn/human/oldsci/Destroy() new/obj/structure/showcase/machinery/oldpod/used(drop_location()) @@ -593,7 +593,7 @@ show_flavour = FALSE //Flavour only exists for spawners menu short_desc = "You are a space pirate." flavour_text = "The station refused to pay for your protection, protect the ship, siphon the credits from the station and raid it for even more loot." - assignedrole = "Space Pirate" + spawner_job_path = /datum/job/space_pirate ///Rank of the pirate on the ship, it's used in generating pirate names! var/rank = "Deserter" ///Whether or not it will spawn a fluff structure upon opening. @@ -683,14 +683,15 @@ flavour_text = "Your ship docks after a long time somewhere in hostile space, reporting a malfunction. You are stuck here, with Nanotrasen station nearby. Fix the ship, find a way to power it and follow your captain's orders." important_info = "Obey orders given by your captain. DO NOT let the ship fall into enemy hands." outfit = /datum/outfit/syndicatespace/syndicrew - assignedrole = ROLE_SYNDICATE_CYBERSUN + spawner_job_path = /datum/job/syndicate_cybersun /datum/outfit/syndicatespace/syndicrew/post_equip(mob/living/carbon/human/H) H.faction |= ROLE_SYNDICATE /obj/effect/mob_spawn/human/syndicatespace/special(mob/living/new_spawn) new_spawn.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) - var/policy = get_policy(assignedrole) + var/datum/job/spawn_job = SSjob.GetJobType(spawner_job_path) + var/policy = get_policy(spawn_job.policy_index) if(policy) to_chat(new_spawn, span_bold("[policy]")) @@ -700,7 +701,7 @@ flavour_text = "Your ship docks after a long time somewhere in hostile space, reporting a malfunction. You are stuck here, with Nanotrasen station nearby. Command your crew and turn your ship into the most protected fortress." important_info = "Protect the ship and secret documents in your backpack with your own life." outfit = /datum/outfit/syndicatespace/syndicaptain - assignedrole = ROLE_SYNDICATE_CYBERSUN_CAPTAIN + spawner_job_path = /datum/job/syndicate_cybersun_captain /datum/outfit/syndicatespace/syndicaptain/post_equip(mob/living/carbon/human/H) H.faction |= ROLE_SYNDICATE @@ -749,7 +750,7 @@ icon_state = "sleeper" short_desc = "You're, like, totally a dudebro, bruh." flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot chicks, y'knaw?" - assignedrole = "Beach Bum" + spawner_job_path = /datum/job/beach_bum /obj/effect/mob_spawn/human/beach/alive/lifeguard short_desc = "You're a spunky lifeguard!" @@ -785,7 +786,7 @@ icon_state = "sleeper" short_desc = "You are a space bartender!" flavour_text = "Time to mix drinks and change lives. Smoking space drugs makes it easier to understand your patrons' odd dialect." - assignedrole = "Space Bartender" + spawner_job_path = /datum/job/space_bartender /datum/outfit/spacebartender name = "Space Bartender" @@ -811,7 +812,7 @@ icon_state = "remains" short_desc = "By unknown powers, your skeletal remains have been reanimated!" flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path." - assignedrole = "Skeleton" + spawner_job_path = /datum/job/skeleton /obj/effect/mob_spawn/human/skeleton/alive/special(mob/living/new_spawn) to_chat(new_spawn, "You have this horrible lurching feeling deep down that your binding to this world will fail if you abandon this zone... Were you reanimated to protect something?") @@ -842,7 +843,7 @@ permanent = TRUE uses = -1 outfit = /datum/outfit/spacebartender - assignedrole = "Space Bar Patron" + spawner_job_path = /datum/job/space_bar_patron /obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user, list/modifiers) var/despawn = tgui_alert(usr, "Return to cryosleep? (Warning, Your mob will be deleted!)", null, list("Yes", "No")) @@ -886,7 +887,7 @@ icon = 'icons/obj/machines/sleeper.dmi' icon_state = "sleeper" short_desc = "You are a space doctor!" - assignedrole = "Space Doctor" + spawner_job_path = /datum/job/space_doctor /obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/doctor) . = ..() diff --git a/code/game/objects/structures/life_candle.dm b/code/game/objects/structures/life_candle.dm index 671ce261e0e..988203a7eeb 100644 --- a/code/game/objects/structures/life_candle.dm +++ b/code/game/objects/structures/life_candle.dm @@ -85,8 +85,7 @@ if(!body) body = new mob_type(T) var/mob/ghostie = mind.get_ghost(TRUE) - if(ghostie.client && ghostie.client.prefs) - ghostie.client.prefs.copy_to(body) + ghostie.client?.prefs?.safe_transfer_prefs_to(body) mind.transfer_to(body) else body.forceMove(T) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 1138cba4f4e..b58fdb32df9 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -827,8 +827,7 @@ dat += "" - for(var/j in SSjob.occupations) - var/datum/job/job = j + for(var/datum/job/job as anything in SSjob.joinable_occupations) count++ var/J_title = html_encode(job.title) var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions)) diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm index bf2109b16c3..4955e126361 100644 --- a/code/modules/admin/antag_panel.dm +++ b/code/modules/admin/antag_panel.dm @@ -99,7 +99,7 @@ GLOBAL_VAR(antag_prototypes) var/out = "[name][(current && (current.real_name!=name))?" (as [current.real_name])":""]
" out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
" - out += "Assigned role: [assigned_role]. Edit
" + out += "Assigned role: [assigned_role.title]. Edit
" out += "Faction and special role: [special_role]
" var/special_statuses = get_special_statuses() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 17088f47a49..ebb7603025b 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -916,7 +916,7 @@ //Job + antagonist if(M.mind) - special_role_description = "Role: [M.mind.assigned_role]; Antagonist: " + special_role_description = "Role: [M.mind.assigned_role.title]; Antagonist: " var/i = 0 for(var/datum/antagonist/A in M.mind.antag_datums) special_role_description += "[A.name]" @@ -966,7 +966,7 @@ var/Add = href_list["addjobslot"] - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job as anything in SSjob.joinable_occupations) if(job.title == Add) job.total_positions += 1 break @@ -980,7 +980,7 @@ var/Add = href_list["customjobslot"] - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job as anything in SSjob.joinable_occupations) if(job.title == Add) var/newtime = null newtime = input(usr, "How many jebs do you want?", "Add wanted posters", "[newtime]") as num|null @@ -998,7 +998,7 @@ var/Remove = href_list["removejobslot"] - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job as anything in SSjob.joinable_occupations) if(job.title == Remove && job.total_positions - job.current_positions > 0) job.total_positions -= 1 break @@ -1011,7 +1011,7 @@ var/Unlimit = href_list["unlimitjobslot"] - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job as anything in SSjob.joinable_occupations) if(job.title == Unlimit) job.total_positions = -1 break @@ -1024,7 +1024,7 @@ var/Limit = href_list["limitjobslot"] - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job as anything in SSjob.joinable_occupations) if(job.title == Limit) job.total_positions = job.current_positions break diff --git a/code/modules/admin/verbs/ai_triumvirate.dm b/code/modules/admin/verbs/ai_triumvirate.dm index b7beadd4d8d..1cc7c01a8a0 100644 --- a/code/modules/admin/verbs/ai_triumvirate.dm +++ b/code/modules/admin/verbs/ai_triumvirate.dm @@ -16,7 +16,7 @@ GLOBAL_DATUM(triple_ai_controller, /datum/triple_ai_controller) /datum/triple_ai_controller/proc/on_occupations_divided(datum/source) SIGNAL_HANDLER - for(var/datum/job/ai/ai_datum in SSjob.occupations) + for(var/datum/job/ai/ai_datum in SSjob.joinable_occupations) ai_datum.spawn_positions = 3 for(var/obj/effect/landmark/start/ai/secondary/secondary_ai_spawn in GLOB.start_landmarks_list) secondary_ai_spawn.latejoin_active = TRUE @@ -35,10 +35,10 @@ GLOBAL_DATUM(triple_ai_controller, /datum/triple_ai_controller) to_chat(usr, "This option is currently only usable during pregame. This may change at a later date.", confidential = TRUE) return - var/datum/job/job = SSjob.GetJob("AI") + var/datum/job/job = SSjob.GetJobType(/datum/job/ai) if(!job) to_chat(usr, "Unable to locate the AI job", confidential = TRUE) - return + CRASH("triple_ai() called, no /datum/job/ai to be found.") if(!GLOB.triple_ai_controller) GLOB.triple_ai_controller = new() diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm index fdbf33dd777..81c22cfd73a 100644 --- a/code/modules/admin/verbs/anonymousnames.dm +++ b/code/modules/admin/verbs/anonymousnames.dm @@ -88,7 +88,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) /datum/anonymous_theme/proc/anonymous_all_players() var/datum/anonymous_theme/theme = GLOB.current_anonymous_theme for(var/mob/living/player in GLOB.player_list) - if(!player.mind || (!ishuman(player) && !issilicon(player)) || !SSjob.GetJob(player.mind.assigned_role)) + if(!player.mind || (!ishuman(player) && !issilicon(player)) || player.mind.assigned_role.faction != FACTION_STATION) continue if(issilicon(player)) player.fully_replace_character_name(player.real_name, theme.anonymous_ai_name(isAI(player))) @@ -109,13 +109,14 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) /datum/anonymous_theme/proc/restore_all_players() priority_announce("Names and Identities have been restored.", "Identity Restoration", SSstation.announcer.get_rand_alert_sound()) for(var/mob/living/player in GLOB.player_list) - if(!player.mind || (!ishuman(player) && !issilicon(player)) || !SSjob.GetJob(player.mind.assigned_role)) + if(!player.mind || (!ishuman(player) && !issilicon(player)) || player.mind.assigned_role.faction != FACTION_STATION) continue var/old_name = player.real_name //before restoration if(issilicon(player)) player.apply_pref_name("[isAI(player) ? "ai" : "cyborg"]", player.client) else - player.client.prefs.copy_to(player, antagonist = (LAZYLEN(player.mind.antag_datums) > 0), is_latejoiner = FALSE) + player.client.prefs.sanitize_chosen_prefs() // Just in case they changed unlawfully. + player.client.prefs.apply_prefs_to(player) // This is not sound logic, as the prefs may have changed since then. player.fully_replace_character_name(old_name, player.real_name) //this changes IDs and PDAs and whatnot /** @@ -153,7 +154,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) priority_announce("As punishment for this station's poor productivity when compared to neighbor stations, names and identities will be restricted until further notice.", "Finance Report", SSstation.announcer.get_rand_alert_sound()) /datum/anonymous_theme/employees/anonymous_name(mob/target) - var/is_head_of_staff = (target.mind.assigned_role in GLOB.command_positions) + var/is_head_of_staff = target.mind.assigned_role.departments & DEPARTMENT_COMMAND var/name = "[is_head_of_staff ? "Manager" : "Employee"] " for(var/i in 1 to 6) if(prob(30) || i == 1) diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm index 591ef53d4ef..7fe396a59f6 100644 --- a/code/modules/admin/verbs/ert.dm +++ b/code/modules/admin/verbs/ert.dm @@ -120,7 +120,7 @@ if(isobserver(usr)) var/mob/living/carbon/human/admin_officer = new (spawnpoints[1]) var/chosen_outfit = usr.client?.prefs?.brief_outfit - usr.client.prefs.copy_to(admin_officer) + usr.client.prefs.safe_transfer_prefs_to(admin_officer, is_antag = TRUE) admin_officer.equipOutfit(chosen_outfit) admin_officer.key = usr.key else @@ -175,7 +175,7 @@ //Spawn the body var/mob/living/carbon/human/ert_operative = new ertemplate.mobtype(spawnloc) - chosen_candidate.client.prefs.copy_to(ert_operative) + chosen_candidate.client.prefs.safe_transfer_prefs_to(ert_operative, is_antag = TRUE) ert_operative.key = chosen_candidate.key if(ertemplate.enforce_human || !(ert_operative.dna.species.changesource_flags & ERT_SPAWN)) // Don't want any exploding plasmemes @@ -194,7 +194,7 @@ ert_antag.random_names = ertemplate.random_names ert_operative.mind.add_antag_datum(ert_antag,ert_team) - ert_operative.mind.assigned_role = ert_antag.name + ert_operative.mind.set_assigned_role(SSjob.GetJobType(ert_antag.ert_job_path)) //Logging and cleanup log_game("[key_name(ert_operative)] has been selected as an [ert_antag.name]") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 16511eac815..30b3dab47c1 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -305,7 +305,7 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) for(var/obj/item/I in D) qdel(I) randomize_human(D) - JB.equip(D, TRUE, FALSE) + D.dress_up_as_job(JB, TRUE) COMPILE_OVERLAYS(D) var/icon/I = icon(getFlatIcon(D), frame = 1) final.Insert(I, JB.title) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index faa216b8ef3..e2346562a9e 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -235,54 +235,6 @@ SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Mute [feedback_string]", "[P.muted & mute_type]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -//I use this proc for respawn character too. /N -/proc/create_xeno(ckey) - if(!ckey) - var/list/candidates = list() - for(var/mob/M in GLOB.player_list) - if(M.stat != DEAD) - continue //we are not dead! - if(!(ROLE_ALIEN in M.client.prefs.be_special)) - continue //we don't want to be an alium - if(M.client.is_afk()) - continue //we are afk - if(M.mind && M.mind.current && M.mind.current.stat != DEAD) - continue //we have a live body we are tied to - candidates += M.ckey - if(candidates.len) - ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in sortKey(candidates) - else - to_chat(usr, span_danger("Error: create_xeno(): no suitable candidates."), confidential = TRUE) - if(!istext(ckey)) - return FALSE - - var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Praetorian","Hunter","Sentinel","Drone","Larva") - var/obj/effect/landmark/spawn_here = GLOB.xeno_spawn.len ? pick(GLOB.xeno_spawn) : null - var/mob/living/carbon/alien/new_xeno - switch(alien_caste) - if("Queen") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(spawn_here) - if("Praetorian") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(spawn_here) - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here) - if("Larva") - new_xeno = new /mob/living/carbon/alien/larva(spawn_here) - else - return FALSE - if(!spawn_here) - SSjob.SendToLateJoin(new_xeno, FALSE) - - new_xeno.ckey = ckey - var/msg = span_notice("[key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste].") - message_admins(msg) - admin_ticket_log(new_xeno, msg) - return TRUE - /* If a guy was gibbed and you want to revive him, this is a good way to do so. Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. @@ -310,43 +262,8 @@ Traitors and the like can also be revived with the previous role mostly intact. return if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something - //Check if they were an alien - if(G_found.mind.assigned_role == ROLE_ALIEN) - if(tgui_alert(usr,"This character appears to have been an alien. Would you like to respawn them as such?",,list("Yes","No"))=="Yes") - var/turf/T - if(GLOB.xeno_spawn.len) - T = pick(GLOB.xeno_spawn) - - var/mob/living/carbon/alien/new_xeno - switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were. - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(T) - if("Praetorian") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(T) - if("Queen") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(T) - else//If we don't know what special role they have, for whatever reason, or they're a larva. - create_xeno(G_found.ckey) - return - - if(!T) - SSjob.SendToLateJoin(new_xeno, FALSE) - - //Now to give them their mind back. - G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_xeno.key = G_found.key - to_chat(new_xeno, "You have been fully respawned. Enjoy the game.", confidential = TRUE) - var/msg = span_adminnotice("[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno.") - message_admins(msg) - admin_ticket_log(new_xeno, msg) - return //all done. The ghost is auto-deleted - //check if they were a monkey - else if(findtext(G_found.real_name,"monkey")) + if(findtext(G_found.real_name,"monkey")) if(tgui_alert(usr,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No"))=="Yes") var/mob/living/carbon/human/species/monkey/new_monkey = new SSjob.SendToLateJoin(new_monkey) @@ -359,7 +276,7 @@ Traitors and the like can also be revived with the previous role mostly intact. return //all done. The ghost is auto-deleted - //Ok, it's not a xeno or a monkey. So, spawn a human. + //Ok, it's not a monkey. So, spawn a human. var/mob/living/carbon/human/new_character = new//The mob being spawned. SSjob.SendToLateJoin(new_character) @@ -367,7 +284,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something /*Try and locate a record for the person being respawned through GLOB.data_core. This isn't an exact science but it does the trick more often than not.*/ - var/id = md5("[G_found.real_name][G_found.mind.assigned_role]") + var/id = md5("[G_found.real_name][G_found.mind.assigned_role.title]") record_found = find_record("id", id, GLOB.data_core.locked) @@ -377,9 +294,7 @@ Traitors and the like can also be revived with the previous role mostly intact. new_character.age = record_found.fields["age"] new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], null, record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) else - var/datum/preferences/A = new() - A.copy_to(new_character) - A.real_name = G_found.real_name + new_character.randomize_human_appearance() new_character.dna.update_dna_identity() new_character.name = new_character.real_name @@ -388,8 +303,8 @@ Traitors and the like can also be revived with the previous role mostly intact. G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use else new_character.mind_initialize() - if(!new_character.mind.assigned_role) - new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role. + if(is_unassigned_job(new_character.mind.assigned_role)) + new_character.mind.set_assigned_role(SSjob.GetJobType(SSjob.overflow_role)) new_character.key = G_found.key @@ -406,10 +321,9 @@ Traitors and the like can also be revived with the previous role mostly intact. //Now for special roles and equipment. var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(/datum/antagonist/traitor) if(traitordatum) - SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1) + SSjob.EquipRank(new_character, new_character.mind.assigned_role, new_character.client) traitordatum.equip() - switch(new_character.mind.special_role) if(ROLE_WIZARD) new_character.forceMove(pick(GLOB.wizardstart)) @@ -429,23 +343,23 @@ Traitors and the like can also be revived with the previous role mostly intact. new_character.forceMove(pick(ninja_spawn)) else//They may also be a cyborg or AI. - switch(new_character.mind.assigned_role) - if("Cyborg")//More rigging to make em' work and check if they're traitor. + switch(new_character.mind.assigned_role.type) + if(/datum/job/cyborg)//More rigging to make em' work and check if they're traitor. new_character = new_character.Robotize(TRUE) - if("AI") + if(/datum/job/ai) new_character = new_character.AIize() else - SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them. + if(!traitordatum) // Already equipped there. + SSjob.EquipRank(new_character, new_character.mind.assigned_role, new_character.client)//Or we simply equip them. //Announces the character on all the systems, based on the record. - if(!issilicon(new_character))//If they are not a cyborg/AI. - if(!record_found&&new_character.mind.assigned_role!=new_character.mind.special_role)//If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway. - //Power to the user! - if(tgui_alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,list("No","Yes"))=="Yes") - GLOB.data_core.manifest_inject(new_character) + if(!record_found && (new_character.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) + //Power to the user! + if(tgui_alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,list("No","Yes"))=="Yes") + GLOB.data_core.manifest_inject(new_character) - if(tgui_alert(new_character,"Would you like an active AI to announce this character?",,list("No","Yes"))=="Yes") - AnnounceArrival(new_character, new_character.mind.assigned_role) + if(tgui_alert(new_character,"Would you like an active AI to announce this character?",,list("No","Yes"))=="Yes") + AnnounceArrival(new_character, new_character.mind.assigned_role.title) var/msg = span_adminnotice("[admin] has respawned [player_key] as [new_character.real_name].") message_admins(msg) diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index 3bd8235db15..7aa1238c464 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -86,11 +86,9 @@ if("infinite_sec") if(!is_debugger) return - var/datum/job/J = SSjob.GetJob("Security Officer") - if(!J) - return - J.total_positions = -1 - J.spawn_positions = -1 + var/datum/job/sec_job = SSjob.GetJobType(/datum/job/security_officer) + sec_job.total_positions = -1 + sec_job.spawn_positions = -1 message_admins("[key_name_admin(holder)] has removed the cap on security officers.") //Buttons for helpful stuff. This is where people land in the tgui if("clear_virus") @@ -607,7 +605,7 @@ if (length(players)) var/mob/chosen = players[1] if (chosen.client) - chosen.client.prefs.copy_to(spawnedMob) + chosen.client.prefs.safe_transfer_prefs_to(spawnedMob, is_antag = TRUE) spawnedMob.key = chosen.key players -= chosen if (ishuman(spawnedMob) && ispath(humanoutfit, /datum/outfit)) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 54fd4e61d9d..9922c969a28 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -108,16 +108,19 @@ GLOBAL_LIST_EMPTY(antagonists) hud.leave_hud(mob_override) set_antag_hud(mob_override, null) -// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects + +/// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects /datum/antagonist/proc/handle_clown_mutation(mob/living/mob_override, message, removing = TRUE) - var/mob/living/carbon/human/H = mob_override - if(H && istype(H) && owner.assigned_role == "Clown") - if(removing) // They're a clown becoming an antag, remove clumsy - H.dna.remove_mutation(CLOWNMUT) - if(!silent && message) - to_chat(H, span_boldnotice("[message]")) - else - H.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy + if(!ishuman(mob_override) || !is_clown_job(owner.assigned_role)) + return + var/mob/living/carbon/human/human_override = mob_override + if(removing) // They're a clown becoming an antag, remove clumsy + human_override.dna.remove_mutation(CLOWNMUT) + if(!silent && message) + to_chat(human_override, span_boldnotice("[message]")) + else + human_override.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy + //Assign default team and creates one for one of a kind team antagonists /datum/antagonist/proc/create_team(datum/team/team) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 92e75040fa2..a530c0befe1 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -72,7 +72,7 @@ /obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user) new /obj/effect/particle_effect/smoke(T) var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) - C.prefs.copy_to(M) + C.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) M.key = C.key var/datum/mind/app_mind = M.mind @@ -87,10 +87,8 @@ app.wiz_team = master_wizard.wiz_team master_wizard.wiz_team.add_member(app_mind) app_mind.add_antag_datum(app) - //TODO Kill these if possible - app_mind.assigned_role = "Apprentice" - app_mind.special_role = "apprentice" - // + app_mind.set_assigned_role(SSjob.GetJobType(/datum/job/wizard_apprentice)) + app_mind.special_role = ROLE_WIZARD_APPRENTICE SEND_SOUND(M, sound('sound/effects/magic.ogg')) ///////////BORGS AND OPERATIVES @@ -105,7 +103,7 @@ icon = 'icons/obj/device.dmi' icon_state = "locator" var/borg_to_spawn - var/special_role_name = "Nuclear Operative" ///The name of the special role given to the recruit + var/special_role_name = ROLE_NUCLEAR_OPERATIVE ///The name of the special role given to the recruit var/datum/outfit/syndicate/outfit = /datum/outfit/syndicate/no_crystals ///The applied outfit var/datum/antagonist/nukeop/antag_datum = /datum/antagonist/nukeop ///The antag datam applied /// Style used by the droppod @@ -147,7 +145,7 @@ /obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user) var/mob/living/carbon/human/nukie = new() var/obj/structure/closet/supplypod/pod = setup_pod() - C.prefs.copy_to(nukie) + C.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) nukie.ckey = C.key var/datum/mind/op_mind = nukie.mind @@ -165,7 +163,7 @@ /obj/item/antag_spawner/nuke_ops/clown name = "clown operative beacon" desc = "A single-use beacon designed to quickly launch reinforcement clown operatives into the field." - special_role_name = "Clown Operative" + special_role_name = ROLE_CLOWN_OPERATIVE outfit = /datum/outfit/syndicate/clownop/no_crystals antag_datum = /datum/antagonist/nukeop/clownop pod_style = STYLE_HONK @@ -265,8 +263,8 @@ var/obj/effect/dummy/phased_mob/holder = new /obj/effect/dummy/phased_mob(T) var/mob/living/simple_animal/hostile/imp/slaughter/S = new demon_type(holder) S.key = C.key - S.mind.assigned_role = S.name - S.mind.special_role = S.name + S.mind.set_assigned_role(SSjob.GetJobType(/datum/job/slaughter_demon)) + S.mind.special_role = ROLE_SLAUGHTER_DEMON S.mind.add_antag_datum(antag_type) to_chat(S, S.playstyle_string) to_chat(S, "You are currently not currently in the same plane of existence as the station. \ diff --git a/code/modules/antagonists/abductor/abductee/abductee_objectives.dm b/code/modules/antagonists/abductor/abductee/abductee_objectives.dm index f1883196448..2ef97101ff1 100644 --- a/code/modules/antagonists/abductor/abductee/abductee_objectives.dm +++ b/code/modules/antagonists/abductor/abductee/abductee_objectives.dm @@ -31,12 +31,11 @@ explanation_text = "Capture" /datum/objective/abductee/capture/New() - var/list/jobs = SSjob.occupations.Copy() - for(var/X in jobs) - var/datum/job/J = X - if(J.current_positions < 1) - jobs -= J - if(jobs.len > 0) + var/list/jobs = SSjob.joinable_occupations.Copy() + for(var/datum/job/job as anything in jobs) + if(job.current_positions < 1) + jobs -= job + if(length(jobs) > 0) var/datum/job/target = pick(jobs) explanation_text += " a [target.title]." else diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index 74d02ea8bf7..2f792e77f40 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -16,6 +16,8 @@ GLOBAL_LIST_INIT(possible_abductor_names, list("Alpha","Beta","Gamma","Delta","E var/outfit var/landmark_type var/greet_text + /// Type path for the associated job datum. + var/role_job = /datum/job/abductor_agent /datum/antagonist/abductor/agent @@ -33,10 +35,12 @@ GLOBAL_LIST_INIT(possible_abductor_names, list("Alpha","Beta","Gamma","Delta","E landmark_type = /obj/effect/landmark/abductor/scientist greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans." show_in_antagpanel = TRUE + role_job = /datum/job/abductor_scientist /datum/antagonist/abductor/scientist/onemanteam name = "Abductor Solo" outfit = /datum/outfit/abductor/scientist/onemanteam + role_job = /datum/job/abductor_solo /datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team) if(!new_team) @@ -49,8 +53,8 @@ GLOBAL_LIST_INIT(possible_abductor_names, list("Alpha","Beta","Gamma","Delta","E return team /datum/antagonist/abductor/on_gain() - owner.special_role = "[name]" - owner.assigned_role = "[name]" + owner.set_assigned_role(SSjob.GetJobType(role_job)) + owner.special_role = ROLE_ABDUCTOR objectives += team.objectives finalize_abductor() ADD_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST) diff --git a/code/modules/antagonists/creep/creep.dm b/code/modules/antagonists/creep/creep.dm index 7fe55e45677..61c16c3a6d1 100644 --- a/code/modules/antagonists/creep/creep.dm +++ b/code/modules/antagonists/creep/creep.dm @@ -60,7 +60,7 @@ objectives_left += "heirloom" // If they have no coworkers, jealousy will pick someone else on the station. This will never be a free objective. - if(obsessionmind.assigned_role && obsessionmind.assigned_role != "Captain") + if(!is_captain_job(obsessionmind.assigned_role)) objectives_left += "jealous" for(var/i in 1 to 3) @@ -140,7 +140,7 @@ /datum/objective/assassinate/obsessed/update_explanation_text() ..() if(target?.current) - explanation_text = "Murder [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + explanation_text = "Murder [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." else message_admins("WARNING! [ADMIN_LOOKUPFLW(owner)] obsessed objectives forged without an obsession!") explanation_text = "Free Objective" @@ -156,55 +156,30 @@ else explanation_text = "Free Objective" + /datum/objective/assassinate/jealous/proc/find_coworker(datum/mind/oldmind)//returning null = free objective - if(!oldmind.assigned_role) + if(is_unassigned_job(oldmind.assigned_role)) return var/list/viable_coworkers = list() var/list/all_coworkers = list() - var/chosen_department - var/their_chosen_department - //note that command and sillycone are gone because borgs can't be obsessions and the heads have their respective department. Sorry cap, your place is more with centcom or something - if(oldmind.assigned_role in GLOB.security_positions) - chosen_department = "security" - if(oldmind.assigned_role in GLOB.engineering_positions) - chosen_department = "engineering" - if(oldmind.assigned_role in GLOB.medical_positions) - chosen_department = "medical" - if(oldmind.assigned_role in GLOB.science_positions) - chosen_department = "science" - if(oldmind.assigned_role in GLOB.supply_positions) - chosen_department = "supply" - if(oldmind.assigned_role in GLOB.service_positions) - chosen_department = "service" - for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(!H.mind) + var/our_departments = oldmind.assigned_role.departments + for(var/mob/living/carbon/human/human_alive in GLOB.alive_mob_list) + if(!human_alive.mind) continue - if(!SSjob.GetJob(H.mind.assigned_role) || H == oldmind.current || H.mind.has_antag_datum(/datum/antagonist/obsessed)) + if(human_alive == oldmind.current || human_alive.mind.assigned_role.faction != FACTION_STATION || human_alive.mind.has_antag_datum(/datum/antagonist/obsessed)) continue //the jealousy target has to have a job, and not be the obsession or obsessed. - all_coworkers += H.mind - //this won't be called often thankfully. - if(H.mind.assigned_role in GLOB.security_positions) - their_chosen_department = "security" - if(H.mind.assigned_role in GLOB.engineering_positions) - their_chosen_department = "engineering" - if(H.mind.assigned_role in GLOB.medical_positions) - their_chosen_department = "medical" - if(H.mind.assigned_role in GLOB.science_positions) - their_chosen_department = "science" - if(H.mind.assigned_role in GLOB.supply_positions) - their_chosen_department = "supply" - if(H.mind.assigned_role in GLOB.service_positions) - their_chosen_department = "service" - if(their_chosen_department != chosen_department) + all_coworkers += human_alive.mind + if(!(our_departments & human_alive.mind.assigned_role.departments)) continue - viable_coworkers += H.mind + viable_coworkers += human_alive.mind - if(viable_coworkers.len > 0)//find someone in the same department + if(length(viable_coworkers))//find someone in the same department target = pick(viable_coworkers) - else if(all_coworkers.len > 0)//find someone who works on the station + else if(length(all_coworkers))//find someone who works on the station target = pick(all_coworkers) return oldmind + /datum/objective/spendtime //spend some time around someone, handled by the obsessed trauma since that ticks name = "spendtime" var/timer = 1800 //5 minutes diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 00ade2c08f1..a9e92c5f684 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -288,7 +288,7 @@ human.apply_overlay(HALO_LAYER) /datum/team/cult/proc/make_image(datum/objective/sacrifice/sac_objective) - var/datum/job/job_of_sacrifice = SSjob.GetJob(sac_objective.target.assigned_role) + var/datum/job/job_of_sacrifice = sac_objective.target.assigned_role var/datum/preferences/prefs_of_sacrifice = sac_objective.target.current.client.prefs var/icon/reshape = get_flat_human_icon(null, job_of_sacrifice, prefs_of_sacrifice, list(SOUTH)) reshape.Shift(SOUTH, 4) @@ -341,7 +341,7 @@ /datum/objective/sacrifice/update_explanation_text() if(target) - explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking an Offer rune with [target.p_them()] on it and three acolytes around it." + explanation_text = "Sacrifice [target], the [target.assigned_role.title] via invoking an Offer rune with [target.p_them()] on it and three acolytes around it." else explanation_text = "The veil has already been weakened here, proceed to the final objective." diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm index e1803ee246b..145ccd48610 100644 --- a/code/modules/antagonists/disease/disease_datum.dm +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -6,8 +6,8 @@ var/disease_name = "" /datum/antagonist/disease/on_gain() - owner.special_role = "Sentient Disease" - owner.assigned_role = "Sentient Disease" + owner.set_assigned_role(SSjob.GetJobType(/datum/job/sentient_disease)) + owner.special_role = ROLE_SENTIENT_DISEASE var/datum/objective/O = new /datum/objective/disease_infect() O.owner = owner objectives += O diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm index 9b12dc7cdd7..587f7e6557f 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm @@ -289,7 +289,7 @@ break if(!targeted) break - targets["[targeted.current.real_name] the [targeted.assigned_role][is_teammate ? " (ally)" : ""]"] = targeted.current + targets["[targeted.current.real_name] the [targeted.assigned_role.title][is_teammate ? " (ally)" : ""]"] = targeted.current heart.target = targets[input(user,"Choose your next target","Target") in targets] qdel(temp_objective) if(heart.target) diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 89f5defeae3..8ca4556d093 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -5,6 +5,11 @@ /datum/antagonist/ert name = "Emergency Response Officer" + can_elimination_hijack = ELIMINATION_PREVENT + show_in_antagpanel = FALSE + show_to_ghosts = TRUE + antag_moodlet = /datum/mood_event/focused + suicide_cry = "FOR NANOTRASEN!!" var/datum/team/ert/ert_team var/leader = FALSE var/datum/outfit/outfit = /datum/outfit/centcom/ert/security @@ -15,11 +20,9 @@ var/rip_and_tear = FALSE var/equip_ert = TRUE var/forge_objectives_for_ert = TRUE - can_elimination_hijack = ELIMINATION_PREVENT - show_in_antagpanel = FALSE - show_to_ghosts = TRUE - antag_moodlet = /datum/mood_event/focused - suicide_cry = "FOR NANOTRASEN!!" + /// Typepath indicating the kind of job datum this ert member will have. + var/ert_job_path = /datum/job/ert_generic + /datum/antagonist/ert/on_gain() if(random_names) diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm index 2f7d4770e9c..76af56865b8 100644 --- a/code/modules/antagonists/gang/gang.dm +++ b/code/modules/antagonists/gang/gang.dm @@ -267,15 +267,15 @@ free_clothes = list(/obj/item/clothing/head/beanie/purple, /obj/item/clothing/under/color/lightpurple, /obj/item/toy/crayon/spraycan) - var/list/cop_roles = list("Security Officer", "Warden", "Detective", "Head of Security") gang_objective = "We're looking to make a deal with the security pigs on this station after the shift. We scratch their back, they scratch ours. You feel me? Keep all of security safe from any trouble, and make sure they get out alive." antag_hud_name = "Ballas" /datum/antagonist/gang/purple/check_gang_objective() - for(var/mob/M in GLOB.player_list) - if(M.mind.assigned_role in cop_roles) - if(!considered_alive(M) && !M.suiciding) - return FALSE + for(var/mob/player as anything in GLOB.player_list) + if(!(player.mind.assigned_role.departments & DEPARTMENT_SECURITY)) + continue + if(!player.suiciding && !considered_alive(player)) + return FALSE return TRUE /datum/antagonist/gang/green @@ -361,10 +361,11 @@ if(istype(M.current.loc, /obj/structure/closet/crate/coffin)) continue return FALSE - for(var/mob/M in GLOB.player_list) - if(M.mind.assigned_role == "Chaplain") - if(!considered_alive(M) && !M.suiciding) - return FALSE + for(var/mob/player as anything in GLOB.player_list) + if(!is_chaplain_job(player.mind.assigned_role)) + continue + if(!player.suiciding && !considered_alive(player)) + return FALSE return TRUE /datum/antagonist/gang/tunnel_snakes @@ -449,10 +450,11 @@ antag_hud_name = "Monarch" /datum/antagonist/gang/henchmen/check_gang_objective() // gotta arch dr. venture indirectly - for(var/mob/M in GLOB.player_list) - if(M.mind.assigned_role == "Research Director") - if(considered_alive(M)) - return FALSE + for(var/mob/player as anything in GLOB.player_list) + if(!is_research_director_job(player.mind.assigned_role)) + continue + if(!player.suiciding && considered_alive(player)) + return FALSE return TRUE /datum/antagonist/gang/yakuza diff --git a/code/modules/antagonists/gang/handler.dm b/code/modules/antagonists/gang/handler.dm index 1a374b3a859..4421ff68ecd 100644 --- a/code/modules/antagonists/gang/handler.dm +++ b/code/modules/antagonists/gang/handler.dm @@ -480,14 +480,14 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) //Spawn the body var/mob/living/carbon/human/cop = new(spawnloc) - chosen_candidate.client.prefs.copy_to(cop) + chosen_candidate.client.prefs.safe_transfer_prefs_to(cop, is_antag = TRUE) cop.key = chosen_candidate.key //Give antag datum var/datum/antagonist/ert/families/ert_antag = new cops_to_send cop.mind.add_antag_datum(ert_antag) - cop.mind.assigned_role = ert_antag.name + cop.mind.set_assigned_role(SSjob.GetJobType(ert_antag.ert_job_path)) SSjob.SendToLateJoin(cop) //Logging and cleanup diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index ca498f952d3..bbb1cbfaecb 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -226,8 +226,8 @@ return MAP_ERROR var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(GLOB.xeno_spawn)) player_mind.transfer_to(S) - player_mind.assigned_role = "Morph" - player_mind.special_role = "Morph" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/morph)) + player_mind.special_role = ROLE_MORPH player_mind.add_antag_datum(/datum/antagonist/morph) SEND_SOUND(S, sound('sound/magic/mutate.ogg')) message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a morph by an event.") diff --git a/code/modules/antagonists/nukeop/clownop.dm b/code/modules/antagonists/nukeop/clownop.dm index f97e091afe9..32beaa42f7d 100644 --- a/code/modules/antagonists/nukeop/clownop.dm +++ b/code/modules/antagonists/nukeop/clownop.dm @@ -7,7 +7,7 @@ suicide_cry = "HAPPY BIRTHDAY!!" /datum/antagonist/nukeop/clownop/admin_add(datum/mind/new_owner,mob/admin) - new_owner.assigned_role = "Clown Operative" + new_owner.set_assigned_role(SSjob.GetJobType(/datum/job/clown_operative)) new_owner.add_antag_datum(src) message_admins("[key_name_admin(admin)] has clown op'ed [key_name_admin(new_owner)].") log_admin("[key_name(admin)] has clown op'ed [key_name(new_owner)].") diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 008e1f172e9..45129657e5b 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -1,5 +1,5 @@ /datum/antagonist/nukeop - name = "Nuclear Operative" + name = ROLE_NUCLEAR_OPERATIVE roundend_category = "syndicate operatives" //just in case antagpanel_category = "NukeOp" job_rank = ROLE_OPERATIVE @@ -123,7 +123,7 @@ nuke_team = new_team /datum/antagonist/nukeop/admin_add(datum/mind/new_owner,mob/admin) - new_owner.assigned_role = ROLE_SYNDICATE + new_owner.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) new_owner.add_antag_datum(src) message_admins("[key_name_admin(admin)] has nuke op'ed [key_name_admin(new_owner)].") log_admin("[key_name(admin)] has nuke op'ed [key_name(new_owner)].") diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index b5f7d94c943..c2afbe08cf6 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -107,7 +107,7 @@ to_chat(src, "Be sure to read the wiki page to learn more.") if(!generated_objectives_and_spells) generated_objectives_and_spells = TRUE - mind.assigned_role = ROLE_REVENANT + mind.set_assigned_role(SSjob.GetJobType(/datum/job/revenant)) mind.special_role = ROLE_REVENANT SEND_SOUND(src, sound('sound/effects/ghost.ogg')) mind.add_antag_datum(/datum/antagonist/revenant) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 8cfdd76d19e..88308173ac6 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -22,7 +22,7 @@ /datum/antagonist/rev/can_be_owned(datum/mind/new_owner) . = ..() if(.) - if(new_owner.assigned_role in GLOB.command_positions) + if(new_owner.assigned_role.departments & DEPARTMENT_COMMAND) return FALSE if(new_owner.unconvertable) return FALSE @@ -417,7 +417,7 @@ if (isnull(mind)) continue - if (!(mind.assigned_role in GLOB.command_positions + GLOB.security_positions)) + if (!(mind.assigned_role.departments & (DEPARTMENT_SECURITY|DEPARTMENT_COMMAND))) continue if (mind in ex_revs + ex_headrevs) diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index d784ee96fbf..5887b364318 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -35,8 +35,8 @@ var/obj/effect/dummy/phased_mob/holder = new /obj/effect/dummy/phased_mob((pick(spawn_locs))) var/mob/living/simple_animal/hostile/imp/slaughter/S = new (holder) player_mind.transfer_to(S) - player_mind.assigned_role = "Slaughter Demon" - player_mind.special_role = "Slaughter Demon" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/slaughter_demon)) + player_mind.special_role = ROLE_SLAUGHTER_DEMON player_mind.add_antag_datum(/datum/antagonist/slaughter) to_chat(S, S.playstyle_string) to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm index f64994abe8f..b220d6ebf9a 100644 --- a/code/modules/antagonists/space_ninja/space_ninja.dm +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -118,12 +118,12 @@ if(give_equipment) equip_space_ninja(owner.current) - owner.current.mind.assigned_role = ROLE_NINJA + owner.current.mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_ninja)) owner.current.mind.special_role = ROLE_NINJA return ..() /datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin) - new_owner.assigned_role = ROLE_NINJA + new_owner.set_assigned_role(SSjob.GetJobType(/datum/job/space_ninja)) new_owner.special_role = ROLE_NINJA new_owner.add_antag_datum(src) message_admins("[key_name_admin(admin)] has ninja'ed [key_name_admin(new_owner)].") diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index de90d732cbc..9cac0e7e940 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -126,7 +126,7 @@ objectives += kill_objective return - if(prob(DOWNLOAD_PROB) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist", "Geneticist"))) + if(prob(DOWNLOAD_PROB) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role.departments & DEPARTMENT_SCIENCE)) var/datum/objective/download/download_objective = new download_objective.owner = owner download_objective.gen_amount_goal() diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index 9385e2bf3c0..c6ea5185076 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -681,7 +681,7 @@ owner = user return if(user != owner) - if(user.mind.special_role == "apprentice") + if(user.mind.special_role == ROLE_WIZARD_APPRENTICE) to_chat(user, "If you got caught sneaking a peek from your teacher's spellbook, you'd likely be expelled from the Wizard Academy. Better not.") else to_chat(user, span_warning("The [name] does not recognize you as its owner and refuses to open!")) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 9263d62e26e..329e150380a 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -32,7 +32,8 @@ var/burn_damage = 0 var/datum/disease/disease = null //Do they start with a pre-spawned disease? var/mob_color //Change the mob's color - var/assignedrole + /// Typepath indicating the kind of job datum this ert member will have. + var/spawner_job_path = /datum/job/ghost_role var/show_flavour = TRUE var/banType = ROLE_LAVALAND var/ghost_usable = TRUE @@ -41,6 +42,7 @@ /// If the spawner uses radials var/radial_based = FALSE + //ATTACK GHOST IGNORING PARENT RETURN VALUE /obj/effect/mob_spawn/attack_ghost(mob/user) if(!SSticker.HasRoundStarted() || !loc || !ghost_usable) @@ -137,8 +139,7 @@ var/datum/objective/O = new/datum/objective(objective) O.owner = MM A.objectives += O - if(assignedrole) - M.mind.assigned_role = assignedrole + M.mind.set_assigned_role(SSjob.GetJobType(spawner_job_path)) special(M) MM.name = M.real_name if(uses > 0) @@ -155,7 +156,7 @@ var/datum/outfit/outfit = /datum/outfit //If this is a path, it will be instanced in Initialize() var/disable_pda = TRUE var/disable_sensors = TRUE - assignedrole = "Ghost Role" + spawner_job_path = /datum/job/ghost_role var/husk = null //these vars are for lazy mappers to override parts of the outfit @@ -450,7 +451,7 @@ name = "rotting corpse" mob_name = "zombie" mob_species = /datum/species/zombie - assignedrole = "Zombie" + spawner_job_path = /datum/job/zombie /obj/effect/mob_spawn/human/abductor name = "abductor" diff --git a/code/modules/capture_the_flag/capture_the_flag.dm b/code/modules/capture_the_flag/capture_the_flag.dm index 9bd0ad23eba..6f836cad196 100644 --- a/code/modules/capture_the_flag/capture_the_flag.dm +++ b/code/modules/capture_the_flag/capture_the_flag.dm @@ -376,7 +376,7 @@ return //picked nothing, admin disabled it, cheating to respawn faster, cheating to respawn... while in game? chosen_class = ctf_gear[result] var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(src)) - new_team_member.prefs.copy_to(M) + new_team_member.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) M.set_species(/datum/species/synth) M.key = new_team_member.key M.faction += team diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 9aac18a97f3..6063ea43cc0 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -81,7 +81,20 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/eye_color = "000" //Eye color var/datum/species/pref_species = new /datum/species/human() //Mutant race var/list/features = list("mcolor" = "FFF", "ethcolor" = "9c3030", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "wings" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain", "moth_antennae" = "Plain", "moth_markings" = "None") - var/list/randomise = list(RANDOM_UNDERWEAR = TRUE, RANDOM_UNDERWEAR_COLOR = TRUE, RANDOM_UNDERSHIRT = TRUE, RANDOM_SOCKS = TRUE, RANDOM_BACKPACK = TRUE, RANDOM_JUMPSUIT_STYLE = TRUE, RANDOM_HAIRSTYLE = TRUE, RANDOM_HAIR_COLOR = TRUE, RANDOM_FACIAL_HAIRSTYLE = TRUE, RANDOM_FACIAL_HAIR_COLOR = TRUE, RANDOM_SKIN_TONE = TRUE, RANDOM_EYE_COLOR = TRUE) + var/list/randomise = list( + RANDOM_UNDERWEAR = TRUE, + RANDOM_UNDERWEAR_COLOR = TRUE, + RANDOM_UNDERSHIRT = TRUE, + RANDOM_SOCKS = TRUE, + RANDOM_BACKPACK = TRUE, + RANDOM_JUMPSUIT_STYLE = TRUE, + RANDOM_HAIRSTYLE = TRUE, + RANDOM_HAIR_COLOR = TRUE, + RANDOM_FACIAL_HAIRSTYLE = TRUE, + RANDOM_FACIAL_HAIR_COLOR = TRUE, + RANDOM_SKIN_TONE = TRUE, + RANDOM_EYE_COLOR = TRUE, + ) var/phobia = "spiders" var/list/custom_names = list() @@ -133,9 +146,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/action_buttons_screen_locs = list() - ///This var stores the amount of points the owner will get for making it out alive. - var/hardcore_survival_score = 0 - ///Someone thought we were nice! We get a little heart in OOC until we join the server past the below time (we can keep it until the end of the round otherwise) var/hearted ///If we have a hearted commendations, we honor it every time the player loads preferences until this time has been passed @@ -167,7 +177,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(load_character()) return //we couldn't load character data so just randomize the character appearance + name - random_character() //let's create a random character then - rather than a fat, bald and naked man. + randomise_appearance_prefs() //let's create a random character then - rather than a fat, bald and naked man. key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys C?.set_macros() real_name = pref_species.random_name(gender,1) @@ -883,7 +893,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/width = widthPerColumn var/HTML = "
" - if(SSjob.occupations.len <= 0) + if(length(SSjob.joinable_occupations) <= 0) HTML += "The job SSticker is not yet finished creating jobs, please try again later" HTML += "
Done

" // Easier to press up here. @@ -898,8 +908,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. var/datum/job/lastJob + var/datum/job/overflow_role = SSjob.GetJobType(SSjob.overflow_role) - for(var/datum/job/job in sortList(SSjob.occupations, /proc/cmp_job_display_asc)) + for(var/datum/job/job as anything in sortList(SSjob.joinable_occupations, /proc/cmp_job_display_asc)) index += 1 if(index >= limit) @@ -925,7 +936,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/available_in_days = job.available_in_days(user.client) HTML += "[rank]
" continue - if((job_preferences[SSjob.overflow_role] == JP_LOW) && (rank != SSjob.overflow_role) && !is_banned_from(user.ckey, SSjob.overflow_role)) + if((job_preferences[overflow_role.title] == JP_LOW) && (rank != overflow_role.title) && !is_banned_from(user.ckey, overflow_role.title)) HTML += "[rank]" continue if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs @@ -964,8 +975,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) HTML += "" - if(rank == SSjob.overflow_role)//Overflow is special - if(job_preferences[SSjob.overflow_role] == JP_LOW) + if(rank == overflow_role.title)//Overflow is special + if(job_preferences[overflow_role.title] == JP_LOW) HTML += "Yes" else HTML += "No" @@ -981,7 +992,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) HTML += "
\[IN [(available_in_days)] DAYS\]
" HTML += "" - var/message = "Be an [SSjob.overflow_role] if preferences unavailable" + var/message = "Be an [overflow_role.title] if preferences unavailable" if(joblessrole == BERANDOMJOB) message = "Get random job if preferences unavailable" else if(joblessrole == RETURNTOLOBBY) @@ -1009,11 +1020,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) return TRUE /datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) - if(!SSjob || SSjob.occupations.len <= 0) + if(!SSjob || length(SSjob.joinable_occupations) <= 0) return var/datum/job/job = SSjob.GetJob(role) - if(!job) + if(!job || !(job.job_flags & JOB_NEW_PLAYER_JOINABLE)) user << browse(null, "window=mob_occupation") ShowChoices(user) return @@ -1021,7 +1032,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if (!isnum(desiredLvl)) to_chat(user, span_danger("UpdateJobPreference - desired level was not a number. Please notify coders!")) ShowChoices(user) - return + CRASH("UpdateJobPreference called with desiredLvl value of [isnull(desiredLvl) ? "null" : desiredLvl]") var/jpval = null switch(desiredLvl) @@ -1032,7 +1043,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(1) jpval = JP_HIGH - if(role == SSjob.overflow_role) + if(job.type == SSjob.overflow_role) if(job_preferences[job.title] == JP_LOW) jpval = null else @@ -1158,7 +1169,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("random") switch(joblessrole) if(RETURNTOLOBBY) - if(is_banned_from(user.ckey, SSjob.overflow_role)) + var/datum/job/overflow_role = SSjob.GetJobType(SSjob.overflow_role) + if(is_banned_from(user.ckey, overflow_role.title)) joblessrole = BERANDOMJOB else joblessrole = BEOVERFLOW @@ -1248,7 +1260,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("suit") jumpsuit_style = pick(GLOB.jumpsuitlist) if("all") - random_character(gender) + apply_character_randomization_prefs() if("input") @@ -1856,8 +1868,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("changeslot") if(!load_character(text2num(href_list["num"]))) - random_character() - real_name = random_unique_name(gender) + randomise_appearance_prefs() save_character() if("tab") @@ -1873,37 +1884,33 @@ GLOBAL_LIST_EMPTY(preferences_datums) ShowChoices(user) return 1 -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE, character_setup = FALSE, antagonist = FALSE, is_latejoiner = TRUE) - hardcore_survival_score = 0 //Set to 0 to prevent you getting points from last another time. +/// Sanitization checks to be performed before using these preferences. +/datum/preferences/proc/sanitize_chosen_prefs() + if(!(pref_species.id in GLOB.roundstart_races) && !(pref_species.id in (CONFIG_GET(keyed_list/roundstart_no_hard_check)))) + pref_species = new /datum/species/human + save_character() - if((randomise[RANDOM_SPECIES] || randomise[RANDOM_HARDCORE]) && !character_setup) + if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == SPECIES_HUMAN)) + var/firstspace = findtext(real_name, " ") + var/name_length = length(real_name) + if(!firstspace) //we need a surname + real_name += " [pick(GLOB.last_names)]" + else if(firstspace == name_length) + real_name += "[pick(GLOB.last_names)]" - random_species() - if((randomise[RANDOM_BODY] || (randomise[RANDOM_BODY_ANTAG] && antagonist) || randomise[RANDOM_HARDCORE]) && !character_setup) - slot_randomized = TRUE - random_character(gender, antagonist) +/// Sanitizes the preferences, applies the randomization prefs, and then applies the preference to the human mob. +/datum/preferences/proc/safe_transfer_prefs_to(mob/living/carbon/human/character, icon_updates = TRUE, is_antag = FALSE) + apply_character_randomization_prefs(is_antag) + sanitize_chosen_prefs() + apply_prefs_to(character, icon_updates) - if((randomise[RANDOM_NAME] || (randomise[RANDOM_NAME_ANTAG] && antagonist) || randomise[RANDOM_HARDCORE]) && !character_setup) - slot_randomized = TRUE - real_name = pref_species.random_name(gender) - - if(randomise[RANDOM_HARDCORE] && parent.mob.mind && !character_setup) - if(can_be_random_hardcore()) - hardcore_random_setup(character, antagonist, is_latejoiner) - - if(roundstart_checks) - if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == SPECIES_HUMAN)) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(GLOB.last_names)]" - else if(firstspace == name_length) - real_name += "[pick(GLOB.last_names)]" +/// Applies the given preferences to a human mob. +/datum/preferences/proc/apply_prefs_to(mob/living/carbon/human/character, icon_updates = TRUE) character.real_name = real_name - character.name = character.real_name + character.name = real_name character.gender = gender character.age = age @@ -1932,15 +1939,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.jumpsuit_style = jumpsuit_style - var/datum/species/chosen_species - chosen_species = pref_species.type - if(roundstart_checks && !(pref_species.id in GLOB.roundstart_races) && !(pref_species.id in (CONFIG_GET(keyed_list/roundstart_no_hard_check)))) - chosen_species = /datum/species/human - pref_species = new /datum/species/human - save_character() - character.dna.features = features.Copy() - character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) + character.set_species(pref_species.type, icon_update = FALSE, pref_load = TRUE) character.dna.real_name = character.real_name if(pref_species.mutant_bodyparts["tail_lizard"]) @@ -1953,15 +1953,19 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.update_hair() character.update_body_parts() -/datum/preferences/proc/can_be_random_hardcore() - if(parent.mob.mind.assigned_role in GLOB.command_positions) //No command staff + +/// Returns whether the parent mob should have the random hardcore settings enabled. Assumes it has a mind. +/datum/preferences/proc/should_be_random_hardcore(datum/job/job, datum/mind/mind) + if(!randomise[RANDOM_HARDCORE]) return FALSE - for(var/A in parent.mob.mind.antag_datums) - var/datum/antagonist/antag + if(job.departments & DEPARTMENT_COMMAND) //No command staff + return FALSE + for(var/datum/antagonist/antag as anything in mind.antag_datums) if(antag.get_team()) //No team antags return FALSE return TRUE + /datum/preferences/proc/get_default_name(name_id) switch(name_id) if("human") diff --git a/code/modules/clothing/outfits/event.dm b/code/modules/clothing/outfits/event.dm index a35cbccebe0..8ab4478dc00 100644 --- a/code/modules/clothing/outfits/event.dm +++ b/code/modules/clothing/outfits/event.dm @@ -18,8 +18,8 @@ if(visualsOnly) return H.fully_replace_character_name(H.real_name, "Santa Claus") - H.mind.assigned_role = "Santa" - H.mind.special_role = "Santa" + H.mind.set_assigned_role(SSjob.GetJobType(/datum/job/santa)) + H.mind.special_role = ROLE_SANTA H.hairstyle = "Long Hair 3" H.facial_hairstyle = "Beard (Full)" diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm index 04ad4d0611a..9221741feef 100644 --- a/code/modules/clothing/outfits/vr.dm +++ b/code/modules/clothing/outfits/vr.dm @@ -8,7 +8,7 @@ shoes = /obj/item/clothing/shoes/sneakers/black /datum/outfit/vr/pre_equip(mob/living/carbon/human/H) - H.dna.species.before_equip_job(null, H) + H.dna.species.pre_equip_species_outfit(null, H) /datum/outfit/vr/syndicate name = "Syndicate VR Operative - Basic" diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index f6760fbeb0c..184ab5797af 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -112,13 +112,13 @@ if(slot == ITEM_SLOT_FEET) if(enabled_waddle) user.AddElement(/datum/element/waddling) - if(user.mind && user.mind.assigned_role == "Clown") + if(is_clown_job(user.mind?.assigned_role)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "clownshoes", /datum/mood_event/clownshoes) /obj/item/clothing/shoes/clown_shoes/dropped(mob/user) . = ..() user.RemoveElement(/datum/element/waddling) - if(user.mind && user.mind.assigned_role == "Clown") + if(is_clown_job(user.mind?.assigned_role)) SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "clownshoes") /obj/item/clothing/shoes/clown_shoes/CtrlClick(mob/living/user) diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index a283b206e22..84822dfaa97 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -704,8 +704,7 @@ /obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) if(!..() || !ishuman(M)) return FALSE - var/mob/living/carbon/human/H = M - if(H.mind.assigned_role == "Clown") + if(is_clown_job(M.mind.assigned_role)) return TRUE else return FALSE diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index ee8c5ed48e8..8abf0718875 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -67,10 +67,14 @@ while(spawncount > 0 && vents.len && candidates.len) var/obj/vent = pick_n_take(vents) - var/client/C = pick_n_take(candidates) - + var/client/candidate_client = pick_n_take(candidates) + var/datum/mind/candidate_mind = candidate_client.mob.mind + if(!candidate_mind) + continue var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) - new_xeno.key = C.key + candidate_mind.transfer_to(new_xeno) + candidate_mind.set_assigned_role(SSjob.GetJobType(/datum/job/xenomorph)) + candidate_mind.special_role = ROLE_ALIEN new_xeno.move_into_vent(vent) spawncount-- diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index eda231ce6f5..7350fd682fb 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -14,7 +14,7 @@ continue if(!H.getorgan(/obj/item/organ/brain)) // If only I had a brain continue - if(!SSjob.GetJob(H.mind.assigned_role) || (H.mind.assigned_role in GLOB.nonhuman_positions)) //please stop giving my centcom admin gimmicks full body paralysis + if(!(H.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) //please stop giving my centcom admin gimmicks full body paralysis continue traumatize(H) announce_to_ghosts(H) diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index 2a5292b4b88..f46775fc102 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -11,7 +11,7 @@ priority_announce("A recent bureaucratic error in the Organic Resources Department may result in personnel shortages in some departments and redundant staffing in others.", "Paperwork Mishap Alert") /datum/round_event/bureaucratic_error/start() - var/list/jobs = SSjob.occupations.Copy() + var/list/jobs = SSjob.joinable_occupations.Copy() if(prob(33)) // Only allows latejoining as a single role. Add latejoin AI bluespace pods for fun later. var/datum/job/overflow = pick_n_take(jobs) overflow.spawn_positions = -1 @@ -22,8 +22,7 @@ continue current.total_positions = 0 else // Adds/removes a random amount of job slots from all jobs. - for(var/job in jobs) - var/datum/job/current = job + for(var/datum/job/current as anything in jobs) if(!current.allow_bureaucratic_error) continue var/ran = rand(-2,4) diff --git a/code/modules/events/creep_awakening.dm b/code/modules/events/creep_awakening.dm index b8842119ba4..6e9720ea1fc 100644 --- a/code/modules/events/creep_awakening.dm +++ b/code/modules/events/creep_awakening.dm @@ -13,7 +13,7 @@ continue if(H.stat == DEAD) continue - if(!SSjob.GetJob(H.mind.assigned_role) || (H.mind.assigned_role in GLOB.nonhuman_positions)) //only station jobs sans nonhuman roles, prevents ashwalkers trying to stalk with crewmembers they never met + if(!(H.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) //only station jobs sans nonhuman roles, prevents ashwalkers trying to stalk with crewmembers they never met continue if(H.mind.has_antag_datum(/datum/antagonist/obsessed)) continue diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index e3e2b4ff63b..accf534cc3f 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -6,7 +6,7 @@ /datum/round_event/fake_virus/start() var/list/fake_virus_victims = list() for(var/mob/living/carbon/human/victim in shuffle(GLOB.player_list)) - if(victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_CRITICAL_CONDITION) || !SSjob.GetJob(victim.mind.assigned_role) || (victim.mind.assigned_role in GLOB.nonhuman_positions)) + if(victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_CRITICAL_CONDITION) || !(victim.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) continue fake_virus_victims += victim diff --git a/code/modules/events/fugitive_spawning.dm b/code/modules/events/fugitive_spawning.dm index 1705e2dc566..b392387f8dd 100644 --- a/code/modules/events/fugitive_spawning.dm +++ b/code/modules/events/fugitive_spawning.dm @@ -65,8 +65,8 @@ player_mind.active = TRUE var/mob/living/carbon/human/S = new(landing_turf) player_mind.transfer_to(S) - player_mind.assigned_role = "Fugitive" - player_mind.special_role = "Fugitive" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/fugitive)) + player_mind.special_role = ROLE_FUGITIVE player_mind.add_antag_datum(/datum/antagonist/fugitive) var/datum/antagonist/fugitive/fugitiveantag = player_mind.has_antag_datum(/datum/antagonist/fugitive) INVOKE_ASYNC(fugitiveantag, /datum/antagonist/fugitive.proc/greet, backstory) //some fugitives have a sleep on their greet, so we don't want to stop the entire antag granting proc with fluff diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index fc4b660d5cb..5e398a236d3 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -10,7 +10,7 @@ for(var/mob/living/carbon/human/victim in shuffle(GLOB.player_list)) if(victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_CRITICAL_CONDITION) || !victim.can_heartattack() || victim.has_status_effect(STATUS_EFFECT_EXERCISED) || (/datum/disease/heart_failure in victim.diseases) || victim.undergoing_cardiac_arrest()) continue - if(!SSjob.GetJob(victim.mind.assigned_role) || (victim.mind.assigned_role in GLOB.nonhuman_positions))//only crewmembers can get one, a bit unfair for some ghost roles and it wastes the event + if(!(victim.mind.assigned_role.job_flags & JOB_CREW_MEMBER))//only crewmembers can get one, a bit unfair for some ghost roles and it wastes the event continue if(victim.satiety <= -60) //Multiple junk food items recently heart_attack_contestants[victim] = 3 diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm index eb01dc77204..92af1b424e5 100644 --- a/code/modules/events/nightmare.dm +++ b/code/modules/events/nightmare.dm @@ -33,8 +33,8 @@ var/mob/living/carbon/human/S = new ((pick(spawn_locs))) player_mind.transfer_to(S) - player_mind.assigned_role = "Nightmare" - player_mind.special_role = "Nightmare" + player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nightmare)) + player_mind.special_role = ROLE_NIGHTMARE player_mind.add_antag_datum(/datum/antagonist/nightmare) S.set_species(/datum/species/shadow/nightmare) playsound(S, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) diff --git a/code/modules/events/operative.dm b/code/modules/events/operative.dm index af876cd436c..a4a7f05abd0 100644 --- a/code/modules/events/operative.dm +++ b/code/modules/events/operative.dm @@ -24,12 +24,11 @@ return MAP_ERROR var/mob/living/carbon/human/operative = new(pick(spawn_locs)) - var/datum/preferences/A = new - A.copy_to(operative) + operative.randomize_human_appearance(~RANDOMIZE_SPECIES) operative.dna.update_dna_identity() var/datum/mind/Mind = new /datum/mind(selected.key) - Mind.assigned_role = "Lone Operative" - Mind.special_role = "Lone Operative" + Mind.set_assigned_role(SSjob.GetJobType(/datum/job/lone_operative)) + Mind.special_role = ROLE_LONE_OPERATIVE Mind.active = TRUE Mind.transfer_to(operative) Mind.add_antag_datum(/datum/antagonist/nukeop/lone) diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 5d155de4385..2ae710bafd8 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -440,15 +440,14 @@ /datum/export/pirate/ransom/get_cost(atom/movable/AM) var/mob/living/carbon/human/H = AM - if(H.stat != CONSCIOUS || !H.mind || !H.mind.assigned_role) //mint condition only + if(H.stat != CONSCIOUS || !H.mind) //mint condition only return 0 else if("pirate" in H.faction) //can't ransom your fellow pirates to CentCom! return 0 + else if(H.mind.assigned_role.title in GLOB.command_positions) + return 3000 else - if(H.mind.assigned_role in GLOB.command_positions) - return 3000 - else - return 1000 + return 1000 /datum/export/pirate/parrot cost = 2000 diff --git a/code/modules/events/space_dragon.dm b/code/modules/events/space_dragon.dm index 869aa90197b..0f106e7210f 100644 --- a/code/modules/events/space_dragon.dm +++ b/code/modules/events/space_dragon.dm @@ -34,8 +34,8 @@ var/mob/living/simple_animal/hostile/space_dragon/dragon = new (pick(spawn_locs)) dragon.key = key - dragon.mind.assigned_role = "Space Dragon" - dragon.mind.special_role = "Space Dragon" + dragon.mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon)) + dragon.mind.special_role = ROLE_SPACE_DRAGON dragon.mind.add_antag_datum(/datum/antagonist/space_dragon) playsound(dragon, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) message_admins("[ADMIN_LOOKUPFLW(dragon)] has been made into a Space Dragon by an event.") diff --git a/code/modules/events/space_ninja.dm b/code/modules/events/space_ninja.dm index 0f2f3860903..c81aa033e0d 100644 --- a/code/modules/events/space_ninja.dm +++ b/code/modules/events/space_ninja.dm @@ -45,8 +45,9 @@ /proc/create_space_ninja(spawn_loc) var/mob/living/carbon/human/new_ninja = new(spawn_loc) - var/datum/preferences/random_human_options = new()//Randomize appearance for the ninja. - random_human_options.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" - random_human_options.copy_to(new_ninja) + new_ninja.randomize_human_appearance(~(RANDOMIZE_NAME|RANDOMIZE_SPECIES)) + var/new_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" + new_ninja.name = new_name + new_ninja.real_name = new_name new_ninja.dna.update_dna_identity() return new_ninja diff --git a/code/modules/events/wizard/departmentrevolt.dm b/code/modules/events/wizard/departmentrevolt.dm index 3f05aba548b..b80e63d1dd1 100644 --- a/code/modules/events/wizard/departmentrevolt.dm +++ b/code/modules/events/wizard/departmentrevolt.dm @@ -89,19 +89,16 @@ department_target = pick(independent_departments) nation.generate_nation_objectives(dangerous, department_target) - for(var/i in GLOB.human_list) - var/mob/living/carbon/human/possible_separatist = i + for(var/mob/living/carbon/human/possible_separatist as anything in GLOB.human_list) if(!possible_separatist.mind) continue var/datum/mind/separatist_mind = possible_separatist.mind - if(!separatist_mind.assigned_role) + if(!(separatist_mind.assigned_role.title in jobs_to_revolt)) continue - for(var/job in jobs_to_revolt) - if(separatist_mind.assigned_role == job) - citizens += possible_separatist - separatist_mind.add_antag_datum(/datum/antagonist/separatist, nation, department) - nation.add_member(separatist_mind) - possible_separatist.log_message("Was made into a separatist, long live [nation_name]!", LOG_ATTACK, color="red") + citizens += possible_separatist + separatist_mind.add_antag_datum(/datum/antagonist/separatist, nation, department) + nation.add_member(separatist_mind) + possible_separatist.log_message("Was made into a separatist, long live [nation_name]!", LOG_ATTACK, color="red") if(citizens.len) var/jobs_english_list = english_list(jobs_to_revolt) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index a3a480f8655..68675c9509b 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -377,7 +377,7 @@ var/list/pineapple_pizza_liker = pizza_types.Copy() pineapple_pizza_liker -= /obj/item/food/pizza/pineapple pizza_preferences[nommer.ckey] = pickweight(pineapple_pizza_liker) - else if(nommer.mind && nommer.mind.assigned_role == "Botanist") + else if(nommer.mind?.assigned_role.title == /datum/job/botanist) pizza_preferences[nommer.ckey] = /obj/item/food/pizza/dank else pizza_preferences[nommer.ckey] = pickweight(pizza_types) diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index fac8e157e9f..e92d473a693 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -188,7 +188,7 @@ /datum/holiday/april_fools/celebrate() . = ..() - SSjob.set_overflow_role("Clown") + SSjob.set_overflow_role(/datum/job/clown) SSticker.login_music = 'sound/ambience/clown.ogg' for(var/i in GLOB.new_player_list) var/mob/dead/new_player/P = i diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index b05d48d22f4..bc280270f46 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -1,5 +1,5 @@ /datum/job - //The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this. + /// The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this. var/title = "NOPE" /// Innate skill levels unlocked at roundstart. Based on config.jobs_have_minimal_access config setting, for example with a skeleton crew. Format is list(/datum/skill/foo = SKILL_EXP_NOVICE) with exp as an integer or as per code/_DEFINES/skills.dm @@ -7,38 +7,40 @@ /// Innate skill levels unlocked at roundstart. Based on config.jobs_have_minimal_access config setting, for example with a full crew. Format is list(/datum/skill/foo = SKILL_EXP_NOVICE) with exp as an integer or as per code/_DEFINES/skills.dm var/list/minimal_skills - //Determines who can demote this position + /// Determines who can demote this position var/department_head = list() - //Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. + /// Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. var/list/head_announce = null - //Bitflags for the job + /// Bitflags for the job var/auto_deadmin_role_flags = NONE - //Players will be allowed to spawn in as jobs that are set to "Station" - var/faction = "None" + /// Players will be allowed to spawn in as jobs that are set to "Station" + var/faction = FACTION_NONE - //How many players can be this job + /// How many players can be this job var/total_positions = 0 - //How many players can spawn in as this job + /// How many players can spawn in as this job var/spawn_positions = 0 - //How many players have this job + /// How many players have this job var/current_positions = 0 - //Supervisors, who this person answers to directly + /// Supervisors, who this person answers to directly var/supervisors = "" - //Sellection screen color + /// Selection screen color var/selection_color = "#ffffff" + /// What kind of mob type joining players with this job as their assigned role are spawned as. + var/spawn_type = /mob/living/carbon/human - //If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. + /// If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. var/req_admin_notify - //If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) + /// If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) var/minimal_player_age = 0 var/outfit = null @@ -83,6 +85,18 @@ /// List of family heirlooms this job can get with the family heirloom quirk. List of types. var/list/family_heirlooms + /// All values = (JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK) + var/job_flags = NONE + + /// Multiplier for general usage of the voice of god. + var/voice_of_god_power = 1 + /// Multiplier for the silence command of the voice of god. + var/voice_of_god_silence_power = 1 + + /// String. If set to a non-empty one, it will be the key for the policy text value to show this role on spawn. + var/policy_index = "" + + /datum/job/New() . = ..() var/list/jobs_changes = get_map_changes() @@ -105,26 +119,24 @@ return job_changes[endpart] -//Only override this proc -//H is usually a human unless an /equip override transformed it -/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) - //do actions on H but send messages to M as the key may not have been transferred_yet - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_SPAWN, src, H, M, latejoin) - if(mind_traits) - for(var/t in mind_traits) - ADD_TRAIT(H.mind, t, JOB_TRAIT) - var/obj/item/organ/liver/liver = H.getorganslot(ORGAN_SLOT_LIVER) +/// Executes after the mob has been spawned in the map. Client might not be yet in the mob, and is thus a separate variable. +/datum/job/proc/after_spawn(mob/living/spawned, client/player_client) + SHOULD_CALL_PARENT(TRUE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_SPAWN, src, spawned, player_client) + for(var/trait in mind_traits) + ADD_TRAIT(spawned.mind, trait, JOB_TRAIT) + var/obj/item/organ/liver/liver = spawned.getorganslot(ORGAN_SLOT_LIVER) if(liver) - for(var/t in liver_traits) - ADD_TRAIT(liver, t, JOB_TRAIT) + for(var/trait in liver_traits) + ADD_TRAIT(liver, trait, JOB_TRAIT) + + if(!ishuman(spawned)) + return var/list/roundstart_experience - if(!ishuman(H)) - return - if(!config) //Needed for robots. roundstart_experience = minimal_skills @@ -134,48 +146,39 @@ roundstart_experience = skills if(roundstart_experience) - var/mob/living/carbon/human/experiencer = H + var/mob/living/carbon/human/experiencer = spawned for(var/i in roundstart_experience) experiencer.mind.adjust_experience(i, roundstart_experience[i], TRUE) -/datum/job/proc/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - if(head_announce) - announce_head(H, head_announce) -/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever. - return FALSE +/datum/job/proc/announce_job(mob/living/joining_mob) + if(head_announce) + announce_head(joining_mob, head_announce) + //Used for a special check of whether to allow a client to latejoin as this job. /datum/job/proc/special_check_latejoin(client/C) return TRUE -//Don't override this unless the job transforms into a non-human (Silicons do this for example) -/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source, is_captain = FALSE) - if(!H) - return FALSE - if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions)) - if(H.dna.species.id != SPECIES_HUMAN) - H.set_species(/datum/species/human) - H.apply_pref_name("human", preference_source) - if(!visualsOnly) - var/datum/bank_account/bank_account = new(H.real_name, src, H.dna.species.payday_modifier) - bank_account.payday(STARTING_PAYCHECKS, TRUE) - H.account_id = bank_account.account_id - //Equip the rest of the gear - H.dna.species.before_equip_job(src, H, visualsOnly) +/mob/living/proc/on_job_equipping(datum/job/equipping) + return - if(outfit_override || outfit) - H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) +/mob/living/carbon/human/on_job_equipping(datum/job/equipping) + var/datum/bank_account/bank_account = new(real_name, equipping, dna.species.payday_modifier) + bank_account.payday(STARTING_PAYCHECKS, TRUE) + account_id = bank_account.account_id - if(!visualsOnly && is_captain) - var/is_acting_captain = (title != "Captain") - SSjob.promote_to_captain(H, is_acting_captain) + dress_up_as_job(equipping) - H.dna.species.after_equip_job(src, H, visualsOnly) - if(!visualsOnly && announce) - announce(H, is_captain) +/mob/living/proc/dress_up_as_job(datum/job/equipping, visual_only = FALSE) + return + +/mob/living/carbon/human/dress_up_as_job(datum/job/equipping, visual_only = FALSE) + dna.species.pre_equip_species_outfit(equipping, src, visual_only) + equipOutfit(equipping.outfit, visual_only) + /datum/job/proc/announce_head(mob/living/carbon/human/H, channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. if(H && GLOB.announcement_systems.len) @@ -302,3 +305,143 @@ /// An overridable getter for more dynamic goodies. /datum/job/proc/get_mail_goodies(mob/recipient) return mail_goodies + + +/datum/job/proc/award_service(client/winner, award) + return + + +/datum/job/proc/get_captaincy_announcement(mob/living/captain) + return "Due to extreme staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + + +/// Returns an atom where the mob should spawn in. +/datum/job/proc/get_roundstart_spawn_point() + if(random_spawns_possible) + if(HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS)) + return get_latejoin_spawn_point() + if(HAS_TRAIT(SSstation, STATION_TRAIT_RANDOM_ARRIVALS)) + return get_safe_random_station_turf(typesof(/area/hallway)) || get_latejoin_spawn_point() + if(HAS_TRAIT(SSstation, STATION_TRAIT_HANGOVER)) + var/obj/effect/landmark/start/hangover_spawn_point + for(var/obj/effect/landmark/start/hangover/hangover_landmark in GLOB.start_landmarks_list) + hangover_spawn_point = hangover_landmark + if(hangover_landmark.used) //so we can revert to spawning them on top of eachother if something goes wrong + continue + hangover_landmark.used = TRUE + break + return hangover_spawn_point || get_latejoin_spawn_point() + if(length(GLOB.jobspawn_overrides[title])) + return pick(GLOB.jobspawn_overrides[title]) + var/obj/effect/landmark/start/spawn_point = get_default_roundstart_spawn_point() + if(!spawn_point) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper + return get_latejoin_spawn_point() + return spawn_point + + +/// Handles finding and picking a valid roundstart effect landmark spawn point, in case no uncommon different spawning events occur. +/datum/job/proc/get_default_roundstart_spawn_point() + for(var/obj/effect/landmark/start/spawn_point as anything in GLOB.start_landmarks_list) + if(spawn_point.name != title) + continue + . = spawn_point + if(spawn_point.used) //so we can revert to spawning them on top of eachother if something goes wrong + continue + spawn_point.used = TRUE + break + if(!.) + log_world("Couldn't find a round start spawn point for [title]") + + +/// Finds a valid latejoin spawn point, checking for events and special conditions. +/datum/job/proc/get_latejoin_spawn_point() + if(length(GLOB.jobspawn_overrides[title])) //We're doing something special today. + return pick(GLOB.jobspawn_overrides[title]) + if(length(SSjob.latejoin_trackers)) + return pick(SSjob.latejoin_trackers) + return SSjob.get_last_resort_spawn_points() + + +/// Called after a successful latejoin spawn. +/datum/job/proc/after_latejoin_spawn(mob/living/spawning) + SHOULD_CALL_PARENT(TRUE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN, src, spawning) + + +/// Spawns the mob to be played as, taking into account preferences and the desired spawn point. +/datum/job/proc/get_spawn_mob(client/player_client, atom/spawn_point) + var/mob/living/spawn_instance + if(ispath(spawn_type, /mob/living/silicon/ai)) + // This is unfortunately necessary because of snowflake AI init code. To be refactored. + spawn_instance = new spawn_type(get_turf(spawn_point), null, player_client.mob) + else + spawn_instance = new spawn_type(player_client.mob.loc) + spawn_point.JoinPlayerHere(spawn_instance, TRUE) + spawn_instance.apply_prefs_job(player_client, src) + if(!player_client) + qdel(spawn_instance) + return // Disconnected while checking for the appearance ban. + return spawn_instance + + +/// Applies the preference options to the spawning mob, taking the job into account. Assumes the client has the proper mind. +/mob/living/proc/apply_prefs_job(client/player_client, datum/job/job) + + +/mob/living/carbon/human/apply_prefs_job(client/player_client, datum/job/job) + var/fully_randomize = GLOB.current_anonymous_theme || player_client.prefs.should_be_random_hardcore(job, player_client.mob.mind) || is_banned_from(player_client.ckey, "Appearance") + if(!player_client) + return // Disconnected while checking for the appearance ban. + if(fully_randomize) + if(CONFIG_GET(flag/enforce_human_authority) && (job.departments & DEPARTMENT_COMMAND)) + if(player_client.prefs.pref_species.id != SPECIES_HUMAN) + player_client.prefs.pref_species = new /datum/species/human + player_client.prefs.randomise_appearance_prefs(~RANDOMIZE_SPECIES) + else + player_client.prefs.randomise_appearance_prefs() + player_client.prefs.apply_prefs_to(src) + if(GLOB.current_anonymous_theme) + fully_replace_character_name(null, GLOB.current_anonymous_theme.anonymous_name(src)) + else + var/is_antag = (player_client.mob.mind in GLOB.pre_setup_antags) + if(CONFIG_GET(flag/enforce_human_authority) && (job.departments & DEPARTMENT_COMMAND)) + player_client.prefs.randomise[RANDOM_SPECIES] = FALSE + if(player_client.prefs.pref_species.id != SPECIES_HUMAN) + player_client.prefs.pref_species = new /datum/species/human + player_client.prefs.safe_transfer_prefs_to(src, TRUE, is_antag) + if(CONFIG_GET(flag/force_random_names)) + player_client.prefs.real_name = player_client.prefs.pref_species.random_name(player_client.prefs.gender, TRUE) + dna.update_dna_identity() + + +/mob/living/silicon/ai/apply_prefs_job(client/player_client, datum/job/job) + if(GLOB.current_anonymous_theme) + fully_replace_character_name(real_name, GLOB.current_anonymous_theme.anonymous_ai_name(TRUE)) + return + apply_pref_name("ai", player_client) // This proc already checks if the player is appearance banned. + set_core_display_icon(null, player_client) + + +/mob/living/silicon/robot/apply_prefs_job(client/player_client, datum/job/job) + if(mmi) + var/organic_name + if(GLOB.current_anonymous_theme) + organic_name = GLOB.current_anonymous_theme.anonymous_name(src) + else if(player_client.prefs.randomise[RANDOM_NAME] || CONFIG_GET(flag/force_random_names) || is_banned_from(player_client.ckey, "Appearance")) + if(!player_client) + return // Disconnected while checking the appearance ban. + organic_name = player_client.prefs.pref_species.random_name(player_client.prefs.gender, TRUE) + else + if(!player_client) + return // Disconnected while checking the appearance ban. + organic_name = player_client.prefs.real_name + + mmi.name = "[initial(mmi.name)]: [organic_name]" + if(mmi.brain) + mmi.brain.name = "[organic_name]'s brain" + if(mmi.brainmob) + mmi.brainmob.real_name = organic_name //the name of the brain inside the cyborg is the robotized human's name. + mmi.brainmob.name = organic_name + // If this checks fails, then the name will have been handled during initialization. + if(!GLOB.current_anonymous_theme && player_client.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME) + apply_pref_name("cyborg", player_client) diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index d7cfe8ddd1e..ffb9e640bf5 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -1,11 +1,12 @@ /datum/job/ai title = "AI" auto_deadmin_role_flags = DEADMIN_POSITION_SILICON - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 - selection_color = "#ccffcc" supervisors = "your laws" + selection_color = "#ccffcc" + spawn_type = /mob/living/silicon/ai req_admin_notify = TRUE minimal_player_age = 30 exp_requirements = 180 @@ -15,44 +16,56 @@ allow_bureaucratic_error = FALSE departments = DEPARTMENT_SILICON random_spawns_possible = FALSE + job_flags = JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK var/do_special_check = TRUE -/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null) - if(visualsOnly) - CRASH("dynamic preview is unsupported") - . = H.AIize(latejoin,preference_source) -/datum/job/ai/after_spawn(mob/H, mob/M, latejoin) +/datum/job/ai/after_spawn(mob/living/spawned, client/player_client) . = ..() - if(latejoin) - var/obj/structure/ai_core/latejoin_inactive/lateJoinCore - for(var/obj/structure/ai_core/latejoin_inactive/P in GLOB.latejoin_ai_cores) - if(P.is_available()) - lateJoinCore = P - GLOB.latejoin_ai_cores -= P - break - if(lateJoinCore) - lateJoinCore.available = FALSE - H.forceMove(lateJoinCore.loc) - qdel(lateJoinCore) - var/mob/living/silicon/ai/AI = H - if(GLOB.current_anonymous_theme) - AI.fully_replace_character_name(AI.real_name, GLOB.current_anonymous_theme.anonymous_ai_name(TRUE)) - else - AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. //what is this no energy attitude man - AI.set_core_display_icon(null, M.client) - //we may have been created after our borg if(SSticker.current_state == GAME_STATE_SETTING_UP) for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) if(!R.connected_ai) R.TryConnectToAI() - if(latejoin) - announce(AI) -/datum/job/ai/override_latejoin_spawn() - return TRUE +/datum/job/ai/get_roundstart_spawn_point() + return get_latejoin_spawn_point() + + +/datum/job/ai/get_latejoin_spawn_point() + var/list/primary_spawn_points = list() // Ideal locations. + var/list/secondary_spawn_points = list() // Fallback locations. + for(var/obj/effect/landmark/start/ai/spawn_point in GLOB.landmarks_list) + if(spawn_point.used) + secondary_spawn_points += list(spawn_point) + continue + if(spawn_point.primary_ai) + primary_spawn_points = list(spawn_point) + break // Bingo. + primary_spawn_points += spawn_point + var/obj/effect/landmark/start/ai/chosen_spawn_point + if(length(primary_spawn_points)) + chosen_spawn_point = pick(primary_spawn_points) + else if(length(secondary_spawn_points)) + chosen_spawn_point = pick(secondary_spawn_points) + else + CRASH("Failed to find any AI spawn points.") + chosen_spawn_point.used = TRUE + return chosen_spawn_point + + +/datum/job/ai/get_latejoin_spawn_point() + for(var/obj/structure/ai_core/latejoin_inactive/inactive_core as anything in GLOB.latejoin_ai_cores) + if(!inactive_core.is_available()) + continue + GLOB.latejoin_ai_cores -= inactive_core + inactive_core.available = FALSE + . = inactive_core.loc + qdel(inactive_core) + return + return ..() + /datum/job/ai/special_check_latejoin(client/C) if(!do_special_check) @@ -64,9 +77,12 @@ return TRUE return FALSE -/datum/job/ai/announce(mob/living/silicon/ai/AI) + +/datum/job/ai/announce_job(mob/living/joining_mob) . = ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)].")) + if(SSticker.HasRoundStarted()) + minor_announce("[joining_mob] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(joining_mob)].") + /datum/job/ai/config_check() return CONFIG_GET(flag/allow_ai) diff --git a/code/modules/jobs/job_types/antagonists/abductor_agent.dm b/code/modules/jobs/job_types/antagonists/abductor_agent.dm new file mode 100644 index 00000000000..d08b15e2447 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/abductor_agent.dm @@ -0,0 +1,2 @@ +/datum/job/abductor_agent + title = "Abductor Agent" diff --git a/code/modules/jobs/job_types/antagonists/abductor_scientist.dm b/code/modules/jobs/job_types/antagonists/abductor_scientist.dm new file mode 100644 index 00000000000..a7224080c53 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/abductor_scientist.dm @@ -0,0 +1,2 @@ +/datum/job/abductor_scientist + title = "Abductor Scientist" diff --git a/code/modules/jobs/job_types/antagonists/abductor_solo.dm b/code/modules/jobs/job_types/antagonists/abductor_solo.dm new file mode 100644 index 00000000000..feac2e7657e --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/abductor_solo.dm @@ -0,0 +1,2 @@ +/datum/job/abductor_solo + title = "Abductor Solo" diff --git a/code/modules/jobs/job_types/antagonists/clown_operative.dm b/code/modules/jobs/job_types/antagonists/clown_operative.dm new file mode 100644 index 00000000000..7c1a333da2c --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/clown_operative.dm @@ -0,0 +1,2 @@ +/datum/job/clown_operative + title = ROLE_CLOWN_OPERATIVE diff --git a/code/modules/jobs/job_types/antagonists/lone_operative.dm b/code/modules/jobs/job_types/antagonists/lone_operative.dm new file mode 100644 index 00000000000..53bab251b1b --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/lone_operative.dm @@ -0,0 +1,2 @@ +/datum/job/lone_operative + title = ROLE_LONE_OPERATIVE diff --git a/code/modules/jobs/job_types/antagonists/morph.dm b/code/modules/jobs/job_types/antagonists/morph.dm new file mode 100644 index 00000000000..033191572ca --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/morph.dm @@ -0,0 +1,2 @@ +/datum/job/morph + title = ROLE_MORPH diff --git a/code/modules/jobs/job_types/antagonists/nightmare.dm b/code/modules/jobs/job_types/antagonists/nightmare.dm new file mode 100644 index 00000000000..47d16f47ecd --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/nightmare.dm @@ -0,0 +1,2 @@ +/datum/job/nightmare + title = ROLE_NIGHTMARE diff --git a/code/modules/jobs/job_types/antagonists/nuclear_operative.dm b/code/modules/jobs/job_types/antagonists/nuclear_operative.dm new file mode 100644 index 00000000000..3c45f61e051 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/nuclear_operative.dm @@ -0,0 +1,10 @@ +/datum/job/nuclear_operative + title = ROLE_NUCLEAR_OPERATIVE + + +/datum/job/nuclear_operative/get_roundstart_spawn_point() + return pick(GLOB.nukeop_start) + + +/datum/job/nuclear_operative/get_latejoin_spawn_point() + return pick(GLOB.nukeop_start) diff --git a/code/modules/jobs/job_types/antagonists/revenant.dm b/code/modules/jobs/job_types/antagonists/revenant.dm new file mode 100644 index 00000000000..0f25ddd35c8 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/revenant.dm @@ -0,0 +1,2 @@ +/datum/job/revenant + title = ROLE_REVENANT diff --git a/code/modules/jobs/job_types/antagonists/sentient_disease.dm b/code/modules/jobs/job_types/antagonists/sentient_disease.dm new file mode 100644 index 00000000000..4c91ae4ffa1 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/sentient_disease.dm @@ -0,0 +1,2 @@ +/datum/job/sentient_disease + title = ROLE_SENTIENT_DISEASE diff --git a/code/modules/jobs/job_types/antagonists/slaughter_demon.dm b/code/modules/jobs/job_types/antagonists/slaughter_demon.dm new file mode 100644 index 00000000000..f209d4ac2af --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/slaughter_demon.dm @@ -0,0 +1,2 @@ +/datum/job/slaughter_demon + title = ROLE_SLAUGHTER_DEMON diff --git a/code/modules/jobs/job_types/antagonists/space_dragon.dm b/code/modules/jobs/job_types/antagonists/space_dragon.dm new file mode 100644 index 00000000000..0e5b0ef87f1 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/space_dragon.dm @@ -0,0 +1,2 @@ +/datum/job/space_dragon + title = ROLE_SPACE_DRAGON diff --git a/code/modules/jobs/job_types/antagonists/space_ninja.dm b/code/modules/jobs/job_types/antagonists/space_ninja.dm new file mode 100644 index 00000000000..269d6cb882c --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/space_ninja.dm @@ -0,0 +1,2 @@ +/datum/job/space_ninja + title = ROLE_NINJA diff --git a/code/modules/jobs/job_types/antagonists/space_wizard.dm b/code/modules/jobs/job_types/antagonists/space_wizard.dm new file mode 100644 index 00000000000..71250636c2c --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/space_wizard.dm @@ -0,0 +1,3 @@ +/datum/job/space_wizard + title = ROLE_WIZARD + faction = ROLE_WIZARD diff --git a/code/modules/jobs/job_types/antagonists/wizard_apprentice.dm b/code/modules/jobs/job_types/antagonists/wizard_apprentice.dm new file mode 100644 index 00000000000..b4d318f438b --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/wizard_apprentice.dm @@ -0,0 +1,3 @@ +/datum/job/wizard_apprentice + title = "Apprentice" //Turns out that ROLE_WIZARD_APPRENTICE is lower-case, and DB stuff is linked to it. + faction = ROLE_WIZARD diff --git a/code/modules/jobs/job_types/antagonists/xenomorph.dm b/code/modules/jobs/job_types/antagonists/xenomorph.dm new file mode 100644 index 00000000000..a354a517ac6 --- /dev/null +++ b/code/modules/jobs/job_types/antagonists/xenomorph.dm @@ -0,0 +1,2 @@ +/datum/job/xenomorph + title = ROLE_ALIEN diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm index b99e3132a23..0de04858c7a 100644 --- a/code/modules/jobs/job_types/assistant.dm +++ b/code/modules/jobs/job_types/assistant.dm @@ -3,7 +3,7 @@ Assistant */ /datum/job/assistant title = "Assistant" - faction = "Station" + faction = FACTION_STATION total_positions = 5 spawn_positions = 5 supervisors = "absolutely everyone" @@ -29,6 +29,9 @@ Assistant /obj/item/crowbar/large = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/assistant name = "Assistant" jobtype = /datum/job/assistant diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 01019a318e5..eeb3a77d03b 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -1,7 +1,7 @@ /datum/job/atmospheric_technician title = "Atmospheric Technician" department_head = list("Chief Engineer") - faction = "Station" + faction = FACTION_STATION total_positions = 3 spawn_positions = 2 supervisors = "the chief engineer" @@ -23,6 +23,9 @@ family_heirlooms = list(/obj/item/lighter, /obj/item/lighter/greyscale, /obj/item/storage/box/matches) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/atmos name = "Atmospheric Technician" jobtype = /datum/job/atmospheric_technician diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm index fd06f8c7ccc..b576fdffa60 100644 --- a/code/modules/jobs/job_types/bartender.dm +++ b/code/modules/jobs/job_types/bartender.dm @@ -1,7 +1,7 @@ /datum/job/bartender title = "Bartender" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -25,6 +25,20 @@ /obj/item/stack/sheet/mineral/uranium = 10, ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + +/datum/job/bartender/award_service(client/winner, award) + winner.give_award(award, winner.mob) + + var/datum/venue/bar = SSrestaurant.all_venues[/datum/venue/bar] + var/award_score = bar.total_income + var/award_status = winner.get_award_status(/datum/award/score/bartender_tourist_score) + if(award_score - award_status > 0) + award_score -= award_status + winner.give_award(/datum/award/score/bartender_tourist_score, winner.mob, award_score) + + /datum/outfit/job/bartender name = "Bartender" jobtype = /datum/job/bartender diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm index ea6de611f4a..e7368c10896 100644 --- a/code/modules/jobs/job_types/botanist.dm +++ b/code/modules/jobs/job_types/botanist.dm @@ -1,7 +1,7 @@ /datum/job/botanist title = "Botanist" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 3 spawn_positions = 2 supervisors = "the head of personnel" @@ -27,6 +27,9 @@ /obj/item/food/monkeycube/bee = 2 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/botanist name = "Botanist" jobtype = /datum/job/botanist diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 30655be96d4..15d729beec9 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -2,7 +2,7 @@ title = "Captain" auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY department_head = list("CentCom") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "Nanotrasen officials and Space law" @@ -32,10 +32,14 @@ /obj/item/reagent_containers/food/drinks/bottle/champagne = 10 ) -/datum/job/captain/announce(mob/living/carbon/human/H, announce_captaincy = TRUE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/captain/get_captaincy_announcement(mob/living/captain) + return "Captain [captain.real_name] on deck!" + /datum/outfit/job/captain name = "Captain" diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm index da781bd2979..3e9ea2a8420 100644 --- a/code/modules/jobs/job_types/cargo_technician.dm +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -1,7 +1,7 @@ /datum/job/cargo_technician title = "Cargo Technician" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 3 spawn_positions = 2 supervisors = "the quartermaster and the head of personnel" @@ -26,6 +26,9 @@ /obj/item/gun/ballistic/rifle/boltaction = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/cargo_tech name = "Cargo Technician" jobtype = /datum/job/cargo_technician diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm index 1fb33215bfc..4f96d64046b 100644 --- a/code/modules/jobs/job_types/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain.dm @@ -1,7 +1,7 @@ /datum/job/chaplain title = "Chaplain" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -26,9 +26,16 @@ /obj/item/toy/plush/ratplush = 1 ) -/datum/job/chaplain/after_spawn(mob/living/H, mob/M) - . = ..() + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + voice_of_god_power = 2 //Chaplains are very good at speaking with the voice of god + + +/datum/job/chaplain/after_spawn(mob/living/spawned, client/player_client) + . = ..() + if(!ishuman(spawned)) + return + var/mob/living/carbon/human/H = spawned var/obj/item/storage/book/bible/booze/B = new if(GLOB.religion) @@ -53,18 +60,18 @@ H.mind.holy_role = HOLY_ROLE_HIGHPRIEST var/new_religion = DEFAULT_RELIGION - if(M.client && M.client.prefs.custom_names["religion"]) - new_religion = M.client.prefs.custom_names["religion"] + if(player_client?.prefs.custom_names["religion"]) + new_religion = player_client.prefs.custom_names["religion"] var/new_deity = DEFAULT_DEITY - if(M.client && M.client.prefs.custom_names["deity"]) - new_deity = M.client.prefs.custom_names["deity"] + if(player_client?.prefs.custom_names["deity"]) + new_deity = player_client.prefs.custom_names["deity"] B.deity_name = new_deity var/new_bible = DEFAULT_BIBLE - if(M.client && M.client.prefs.custom_names["bible"]) - new_bible = M.client.prefs.custom_names["bible"] + if(player_client?.prefs.custom_names["bible"]) + new_bible = player_client.prefs.custom_names["bible"] switch(lowertext(new_religion)) if("homosexuality", "gay", "penis", "ass", "cock", "cocks") diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index 257f4591ad6..082cd4dece6 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -1,7 +1,7 @@ /datum/job/chemist title = "Chemist" department_head = list("Chief Medical Officer") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" @@ -30,6 +30,9 @@ /obj/item/paper/secretrecipe = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/chemist name = "Chemist" jobtype = /datum/job/chemist diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index bd5d1a7e992..e8eac766f5a 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -3,7 +3,7 @@ auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") head_announce = list("Engineering") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the captain" @@ -37,10 +37,14 @@ /obj/effect/spawner/lootdrop/space/fancytool/engineonly = 3 ) -/datum/job/chief_engineer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/chief_engineer/get_captaincy_announcement(mob/living/captain) + return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + /datum/outfit/job/ce name = "Chief Engineer" diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 3f0ccf5a2f7..6963d00ddfc 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -3,7 +3,7 @@ department_head = list("Captain") auto_deadmin_role_flags = DEADMIN_POSITION_HEAD head_announce = list(RADIO_CHANNEL_MEDICAL) - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the captain" @@ -34,10 +34,14 @@ ) family_heirlooms = list(/obj/item/storage/firstaid/ancient/heirloom) -/datum/job/chief_medical_officer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/chief_medical_officer/get_captaincy_announcement(mob/living/captain) + return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + /datum/outfit/job/cmo name = "Chief Medical Officer" diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm index ca17d874b58..babd996ec49 100644 --- a/code/modules/jobs/job_types/clown.dm +++ b/code/modules/jobs/job_types/clown.dm @@ -1,7 +1,7 @@ /datum/job/clown title = "Clown" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -28,9 +28,15 @@ family_heirlooms = list(/obj/item/bikehorn/golden) -/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + +/datum/job/clown/after_spawn(mob/living/spawned, client/player_client) . = ..() - H.apply_pref_name("clown", M.client) + if(!ishuman(spawned)) + return + spawned.apply_pref_name("clown", player_client) + /datum/outfit/job/clown name = "Clown" diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index f1cb63a7ab7..58062a85c9d 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -1,7 +1,7 @@ /datum/job/cook title = "Cook" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 1 supervisors = "the head of personnel" @@ -24,6 +24,9 @@ family_heirlooms = list(/obj/item/reagent_containers/food/condiment/saltshaker, /obj/item/kitchen/rollingpin, /obj/item/clothing/head/chefhat) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/job/cook/New() . = ..() var/list/job_changes = SSmapping.config.job_changes @@ -64,6 +67,18 @@ /obj/item/kitchen/knife/butcher = 2 ) + +/datum/job/cook/award_service(client/winner, award) + winner.give_award(award, winner.mob) + + var/datum/venue/restaurant = SSrestaurant.all_venues[/datum/venue/restaurant] + var/award_score = restaurant.total_income + var/award_status = winner.get_award_status(/datum/award/score/chef_tourist_score) + if(award_score > award_status) + award_score -= award_status + winner.give_award(/datum/award/score/chef_tourist_score, winner.mob, award_score) + + /datum/outfit/job/cook name = "Cook" jobtype = /datum/job/cook diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index a80b2900830..de6b764cf69 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -1,7 +1,7 @@ /datum/job/curator title = "Curator" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -18,6 +18,11 @@ family_heirlooms = list(/obj/item/pen/fountain, /obj/item/storage/pill_bottle/dice) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_silence_power = 3 + + /datum/outfit/job/curator name = "Curator" jobtype = /datum/job/curator diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm index cc741a7a3aa..ad2e2adf59c 100644 --- a/code/modules/jobs/job_types/cyborg.dm +++ b/code/modules/jobs/job_types/cyborg.dm @@ -1,11 +1,12 @@ /datum/job/cyborg title = "Cyborg" auto_deadmin_role_flags = DEADMIN_POSITION_SILICON - faction = "Station" + faction = FACTION_STATION total_positions = 0 spawn_positions = 1 supervisors = "your laws and the AI" //Nodrak selection_color = "#ddffdd" + spawn_type = /mob/living/silicon/robot minimal_player_age = 21 exp_requirements = 120 exp_type = EXP_TYPE_CREW @@ -13,15 +14,17 @@ display_order = JOB_DISPLAY_ORDER_CYBORG departments = DEPARTMENT_SILICON random_spawns_possible = FALSE + job_flags = JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK -/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source = null) - if(visualsOnly) - CRASH("dynamic preview is unsupported") - return H.Robotize(FALSE, latejoin) -/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M) - R.updatename(M.client) - R.gender = NEUTER +/datum/job/cyborg/after_spawn(mob/living/spawned, client/player_client) + . = ..() + if(!iscyborg(spawned)) + return + spawned.gender = NEUTER + var/mob/living/silicon/robot/robot_spawn = spawned + robot_spawn.notify_ai(NEW_BORG) + /datum/job/cyborg/radio_help_message(mob/M) to_chat(M, "Prefix your message with :b to speak with other cyborgs and AI.") diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index 8dff7c6f5ed..3cb5e9ce83b 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -2,7 +2,7 @@ title = "Detective" auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY department_head = list("Head of Security") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of security" @@ -36,6 +36,9 @@ family_heirlooms = list(/obj/item/reagent_containers/food/drinks/bottle/whiskey) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/detective name = "Detective" jobtype = /datum/job/detective diff --git a/code/modules/jobs/job_types/ert/ert_generic.dm b/code/modules/jobs/job_types/ert/ert_generic.dm new file mode 100644 index 00000000000..4758ac75b28 --- /dev/null +++ b/code/modules/jobs/job_types/ert/ert_generic.dm @@ -0,0 +1,2 @@ +/datum/job/ert_generic + title = "ERT Generic" diff --git a/code/modules/jobs/job_types/event/fugitive.dm b/code/modules/jobs/job_types/event/fugitive.dm new file mode 100644 index 00000000000..5df01d4d358 --- /dev/null +++ b/code/modules/jobs/job_types/event/fugitive.dm @@ -0,0 +1,2 @@ +/datum/job/fugitive + title = ROLE_FUGITIVE diff --git a/code/modules/jobs/job_types/event/santa.dm b/code/modules/jobs/job_types/event/santa.dm new file mode 100644 index 00000000000..d6382215a7d --- /dev/null +++ b/code/modules/jobs/job_types/event/santa.dm @@ -0,0 +1,2 @@ +/datum/job/santa + title = ROLE_SANTA diff --git a/code/modules/jobs/job_types/free_golem.dm b/code/modules/jobs/job_types/free_golem.dm new file mode 100644 index 00000000000..1fcfca7048b --- /dev/null +++ b/code/modules/jobs/job_types/free_golem.dm @@ -0,0 +1,2 @@ +/datum/job/free_golem + title = ROLE_FREE_GOLEM diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm index d7ec5d92f95..b62c3cdbf27 100644 --- a/code/modules/jobs/job_types/geneticist.dm +++ b/code/modules/jobs/job_types/geneticist.dm @@ -1,7 +1,7 @@ /datum/job/geneticist title = "Geneticist" department_head = list("Research Director") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 2 supervisors = "the research director" @@ -25,6 +25,9 @@ family_heirlooms = list(/obj/item/clothing/under/shorts/purple) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/geneticist name = "Geneticist" jobtype = /datum/job/geneticist diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 12ab9d2a30f..8d400d2c9d8 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -3,7 +3,7 @@ auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") head_announce = list(RADIO_CHANNEL_SUPPLY, RADIO_CHANNEL_SERVICE) - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the captain" @@ -33,10 +33,14 @@ family_heirlooms = list(/obj/item/reagent_containers/food/drinks/trophy/silver_cup) -/datum/job/head_of_personnel/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/head_of_personnel/get_captaincy_announcement(mob/living/captain) + return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + /datum/outfit/job/hop name = "Head of Personnel" diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 1cae68fe922..d77fe30b7d9 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -3,7 +3,7 @@ auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY department_head = list("Captain") head_announce = list(RADIO_CHANNEL_SECURITY) - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the captain" @@ -29,10 +29,14 @@ family_heirlooms = list(/obj/item/book/manual/wiki/security_space_law) -/datum/job/head_of_security/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/head_of_security/get_captaincy_announcement(mob/living/captain) + return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + /datum/outfit/job/hos name = "Head of Security" diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm index 759c73e3cef..5a0d5d5ccd5 100644 --- a/code/modules/jobs/job_types/janitor.dm +++ b/code/modules/jobs/job_types/janitor.dm @@ -1,7 +1,7 @@ /datum/job/janitor title = "Janitor" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 1 supervisors = "the head of personnel" @@ -24,6 +24,9 @@ /obj/item/lightreplacer = 10 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/janitor name = "Janitor" jobtype = /datum/job/janitor diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm index 35774a530f1..5753238055a 100644 --- a/code/modules/jobs/job_types/lawyer.dm +++ b/code/modules/jobs/job_types/lawyer.dm @@ -1,7 +1,7 @@ /datum/job/lawyer title = "Lawyer" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 2 supervisors = "the head of personnel" @@ -22,6 +22,9 @@ family_heirlooms = list(/obj/item/gavelhammer, /obj/item/book/manual/wiki/security_space_law) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/lawyer name = "Lawyer" jobtype = /datum/job/lawyer diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index 257f8c280cc..4f736116ed2 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -1,7 +1,7 @@ /datum/job/doctor title = "Medical Doctor" department_head = list("Chief Medical Officer") - faction = "Station" + faction = FACTION_STATION total_positions = 5 spawn_positions = 3 supervisors = "the chief medical officer" @@ -31,6 +31,9 @@ /obj/effect/spawner/lootdrop/memeorgans = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/doctor name = "Medical Doctor" jobtype = /datum/job/doctor diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm index f78712eee02..6d5afeb4453 100644 --- a/code/modules/jobs/job_types/mime.dm +++ b/code/modules/jobs/job_types/mime.dm @@ -1,7 +1,7 @@ /datum/job/mime title = "Mime" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -25,8 +25,18 @@ /obj/item/book/mimery = 1, ) -/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) - H.apply_pref_name("mime", M.client) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 0.5 //Why are you speaking + voice_of_god_silence_power = 3 + + +/datum/job/mime/after_spawn(mob/living/spawned, client/player_client) + . = ..() + if(!ishuman(spawned)) + return + spawned.apply_pref_name("mime", player_client) + /datum/outfit/job/mime name = "Mime" diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm index f5a97f30758..33943c361ca 100644 --- a/code/modules/jobs/job_types/paramedic.dm +++ b/code/modules/jobs/job_types/paramedic.dm @@ -1,7 +1,7 @@ /datum/job/paramedic title = "Paramedic" department_head = list("Chief Medical Officer") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" @@ -30,6 +30,9 @@ /obj/item/reagent_containers/hypospray/medipen/survival/luxury = 5 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/paramedic name = "Paramedic" jobtype = /datum/job/paramedic diff --git a/code/modules/jobs/job_types/personal_ai.dm b/code/modules/jobs/job_types/personal_ai.dm new file mode 100644 index 00000000000..0f575cbf698 --- /dev/null +++ b/code/modules/jobs/job_types/personal_ai.dm @@ -0,0 +1,2 @@ +/datum/job/personal_ai + title = ROLE_PAI diff --git a/code/modules/jobs/job_types/positronic_brain.dm b/code/modules/jobs/job_types/positronic_brain.dm new file mode 100644 index 00000000000..d51b95dca14 --- /dev/null +++ b/code/modules/jobs/job_types/positronic_brain.dm @@ -0,0 +1,2 @@ +/datum/job/positronic_brain + title = ROLE_POSITRONIC_BRAIN diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index 20265c76e28..035905994c4 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -1,7 +1,7 @@ /datum/job/prisoner title = "Prisoner" department_head = list("The Security Team") - faction = "Station" + faction = FACTION_STATION total_positions = 0 spawn_positions = 2 supervisors = "the security team" @@ -20,6 +20,9 @@ family_heirlooms = list(/obj/item/pen/blue) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/prisoner name = "Prisoner" jobtype = /datum/job/prisoner diff --git a/code/modules/jobs/job_types/psychologist.dm b/code/modules/jobs/job_types/psychologist.dm index 2effa1e4e10..c9e2c27c485 100644 --- a/code/modules/jobs/job_types/psychologist.dm +++ b/code/modules/jobs/job_types/psychologist.dm @@ -1,7 +1,7 @@ /datum/job/psychologist title = "Psychologist" department_head = list("Head of Personnel","Chief Medical Officer") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel and the chief medical officer" @@ -26,6 +26,9 @@ /obj/item/gun/syringe = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/psychologist name = "Psychologist" jobtype = /datum/job/psychologist diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index dd234145cad..99a2be7e117 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -1,7 +1,7 @@ /datum/job/quartermaster title = "Quartermaster" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" @@ -24,10 +24,8 @@ /obj/item/circuitboard/machine/emitter = 3 ) -/datum/job/quartermaster/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to extreme staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + /datum/outfit/job/quartermaster name = "Quartermaster" diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index e3efda19756..a0e1ee6b619 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -3,7 +3,7 @@ auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") head_announce = list("Science") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the captain" @@ -34,10 +34,14 @@ family_heirlooms = list(/obj/item/toy/plush/slimeplushie) -/datum/job/research_director/announce(mob/living/carbon/human/H, announce_captaincy = FALSE) - ..() - if(announce_captaincy) - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!")) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + voice_of_god_power = 1.4 //Command staff has authority + + +/datum/job/research_director/get_captaincy_announcement(mob/living/captain) + return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!" + /datum/outfit/job/rd name = "Research Director" diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index 17abb5a043b..a954f0696f9 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -1,7 +1,7 @@ /datum/job/roboticist title = "Roboticist" department_head = list("Research Director") - faction = "Station" + faction = FACTION_STATION total_positions = 2 spawn_positions = 2 supervisors = "the research director" @@ -27,6 +27,9 @@ family_heirlooms = list(/obj/item/toy/plush/pkplush) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/job/roboticist/New() . = ..() family_heirlooms += subtypesof(/obj/item/toy/mecha) diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm index 9760686722f..f8910371514 100644 --- a/code/modules/jobs/job_types/scientist.dm +++ b/code/modules/jobs/job_types/scientist.dm @@ -1,7 +1,7 @@ /datum/job/scientist title = "Scientist" department_head = list("Research Director") - faction = "Station" + faction = FACTION_STATION total_positions = 5 spawn_positions = 3 supervisors = "the research director" @@ -27,6 +27,9 @@ /obj/item/camera_bug = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/scientist name = "Scientist" jobtype = /datum/job/scientist diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 2cb9fd5cfaf..fd12abfae38 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -2,7 +2,7 @@ title = "Security Officer" auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY department_head = list("Head of Security") - faction = "Station" + faction = FACTION_STATION total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() supervisors = "the head of security, and the head of your assigned department (if applicable)" @@ -34,6 +34,9 @@ /obj/item/melee/baton/boomerang/loaded = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) /** @@ -44,28 +47,28 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S */ GLOBAL_LIST_EMPTY(security_officer_distribution) -/datum/job/security_officer/after_spawn(mob/living/carbon/human/H, mob/M, latejoin = FALSE) + +/datum/job/security_officer/after_latejoin_spawn(mob/living/spawning) . = ..() + if(ishuman(spawning)) + var/department = setup_department(spawning, spawning.client) + if(department) + announce_latejoin(spawning, department, GLOB.security_officer_distribution) - var/department - var/prefered_department = M.client?.prefs?.prefered_security_department - if (!isnull(prefered_department)) - department = get_my_department(H, prefered_department) +/// Returns the department this mob was assigned to, if any. +/datum/job/security_officer/proc/setup_department(mob/living/carbon/human/spawning, client/player_client) + var/department = player_client?.prefs?.prefered_security_department + if (!isnull(department)) + department = get_my_department(spawning, department) - if (latejoin) - announce_latejoin(H, department, GLOB.security_officer_distribution) - - // In the event we're a latejoin, or otherwise aren't in the round-start distributions. - // This is outside the latejoin check because this should theoretically still run if - // a player isn't in the distributions, but isn't a late join. - GLOB.security_officer_distribution[REF(H)] = department + // This should theoretically still run if a player isn't in the distributions, but isn't a late join. + GLOB.security_officer_distribution[REF(spawning)] = department var/ears = null var/accessory = null var/list/dep_trim = null var/destination = null - var/spawn_point = pick(LAZYACCESS(GLOB.department_security_spawns, department)) switch(department) if(SEC_DEPT_SUPPLY) @@ -90,40 +93,42 @@ GLOBAL_LIST_EMPTY(security_officer_distribution) accessory = /obj/item/clothing/accessory/armband/science if(accessory) - var/obj/item/clothing/under/U = H.w_uniform - U.attach_accessory(new accessory) + var/obj/item/clothing/under/worn_under = spawning.w_uniform + worn_under.attach_accessory(new accessory) + if(ears) - if(H.ears) - qdel(H.ears) - H.equip_to_slot_or_del(new ears(H),ITEM_SLOT_EARS) + if(spawning.ears) + qdel(spawning.ears) + spawning.equip_to_slot_or_del(new ears(spawning),ITEM_SLOT_EARS) // If there's a departmental sec trim to apply to the card, overwrite. if(dep_trim) - var/obj/item/card/id/worn_id = H.wear_id + var/obj/item/card/id/worn_id = spawning.wear_id SSid_access.apply_trim_to_card(worn_id, dep_trim) - H.sec_hud_set_ID() + spawning.sec_hud_set_ID() - var/teleport = 0 - if(!CONFIG_GET(flag/sec_start_brig)) - if(destination || spawn_point) - teleport = 1 - if(teleport) - var/turf/T + var/spawn_point = pick(LAZYACCESS(GLOB.department_security_spawns, department)) + + if(!CONFIG_GET(flag/sec_start_brig) && (destination || spawn_point)) if(spawn_point) - T = get_turf(spawn_point) - H.Move(T) + spawning.Move(get_turf(spawn_point)) else var/list/possible_turfs = get_area_turfs(destination) while (length(possible_turfs)) - var/I = rand(1, possible_turfs.len) - var/turf/target = possible_turfs[I] - if (H.Move(target)) + var/random_index = rand(1, length(possible_turfs)) + var/turf/target = possible_turfs[random_index] + if (spawning.Move(target)) break - possible_turfs.Cut(I,I+1) - if(department) - to_chat(M, "You have been assigned to [department]!") - else - to_chat(M, "You have not been assigned to any department. Patrol the halls and help where needed.") + possible_turfs.Cut(random_index, random_index + 1) + + if(player_client) + if(department) + to_chat(player_client, "You have been assigned to [department]!") + else + to_chat(player_client, "You have not been assigned to any department. Patrol the halls and help where needed.") + + return department + /datum/job/security_officer/proc/announce_latejoin( mob/officer, diff --git a/code/modules/jobs/job_types/servant_golem.dm b/code/modules/jobs/job_types/servant_golem.dm new file mode 100644 index 00000000000..dfc76e89476 --- /dev/null +++ b/code/modules/jobs/job_types/servant_golem.dm @@ -0,0 +1,2 @@ +/datum/job/servant_golem + title = ROLE_SERVANT_GOLEM diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 8b6cd8da628..7d9b391b052 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -1,7 +1,7 @@ /datum/job/shaft_miner title = "Shaft Miner" department_head = list("Head of Personnel") - faction = "Station" + faction = FACTION_STATION total_positions = 3 spawn_positions = 3 supervisors = "the quartermaster and the head of personnel" @@ -19,6 +19,9 @@ family_heirlooms = list(/obj/item/pickaxe/mini, /obj/item/shovel) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/miner name = "Shaft Miner" jobtype = /datum/job/shaft_miner diff --git a/code/modules/jobs/job_types/spawner/ancient_crew.dm b/code/modules/jobs/job_types/spawner/ancient_crew.dm new file mode 100644 index 00000000000..69084976806 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/ancient_crew.dm @@ -0,0 +1,3 @@ +/datum/job/ancient_crew + title = ROLE_ANCIENT_CREW + policy_index = ROLE_ANCIENT_CREW diff --git a/code/modules/jobs/job_types/spawner/ash_walker.dm b/code/modules/jobs/job_types/spawner/ash_walker.dm new file mode 100644 index 00000000000..9a57228527f --- /dev/null +++ b/code/modules/jobs/job_types/spawner/ash_walker.dm @@ -0,0 +1,3 @@ +/datum/job/ash_walker + title = ROLE_ASHWALKER + policy_index = ROLE_ASHWALKER diff --git a/code/modules/jobs/job_types/spawner/beach_bum.dm b/code/modules/jobs/job_types/spawner/beach_bum.dm new file mode 100644 index 00000000000..b86edb4d121 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/beach_bum.dm @@ -0,0 +1,3 @@ +/datum/job/beach_bum + title = ROLE_BEACH_BUM + policy_index = ROLE_BEACH_BUM diff --git a/code/modules/jobs/job_types/spawner/escaped_prisoner.dm b/code/modules/jobs/job_types/spawner/escaped_prisoner.dm new file mode 100644 index 00000000000..bb68e5e7f35 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/escaped_prisoner.dm @@ -0,0 +1,3 @@ +/datum/job/escaped_prisoner + title = ROLE_ESCAPED_PRISONER + policy_index = ROLE_ESCAPED_PRISONER diff --git a/code/modules/jobs/job_types/spawner/exile.dm b/code/modules/jobs/job_types/spawner/exile.dm new file mode 100644 index 00000000000..0baf9e9b1b0 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/exile.dm @@ -0,0 +1,3 @@ +/datum/job/exile + title = ROLE_EXILE + policy_index = ROLE_EXILE diff --git a/code/modules/jobs/job_types/spawner/fugitve_hunter.dm b/code/modules/jobs/job_types/spawner/fugitve_hunter.dm new file mode 100644 index 00000000000..4589eedd67e --- /dev/null +++ b/code/modules/jobs/job_types/spawner/fugitve_hunter.dm @@ -0,0 +1,3 @@ +/datum/job/fugitive_hunter + title = ROLE_FUGITIVE_HUNTER + policy_index = ROLE_FUGITIVE_HUNTER diff --git a/code/modules/jobs/job_types/spawner/ghost_role.dm b/code/modules/jobs/job_types/spawner/ghost_role.dm new file mode 100644 index 00000000000..df49b67302e --- /dev/null +++ b/code/modules/jobs/job_types/spawner/ghost_role.dm @@ -0,0 +1,5 @@ +// Generic ghost role. + +/datum/job/ghost_role + title = ROLE_GHOST_ROLE + policy_index = ROLE_GHOST_ROLE diff --git a/code/modules/jobs/job_types/spawner/hermit.dm b/code/modules/jobs/job_types/spawner/hermit.dm new file mode 100644 index 00000000000..3c828bcfb63 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/hermit.dm @@ -0,0 +1,3 @@ +/datum/job/hermit + title = ROLE_HERMIT + policy_index = ROLE_HERMIT diff --git a/code/modules/jobs/job_types/spawner/hotel_staff.dm b/code/modules/jobs/job_types/spawner/hotel_staff.dm new file mode 100644 index 00000000000..3dc3a13571a --- /dev/null +++ b/code/modules/jobs/job_types/spawner/hotel_staff.dm @@ -0,0 +1,3 @@ +/datum/job/hotel_staff + title = ROLE_HOTEL_STAFF + policy_index = ROLE_HOTEL_STAFF diff --git a/code/modules/jobs/job_types/spawner/lavaland_syndicate.dm b/code/modules/jobs/job_types/spawner/lavaland_syndicate.dm new file mode 100644 index 00000000000..a22e798274a --- /dev/null +++ b/code/modules/jobs/job_types/spawner/lavaland_syndicate.dm @@ -0,0 +1,3 @@ +/datum/job/lavaland_syndicate + title = ROLE_LAVALAND_SYNDICATE + policy_index = ROLE_LAVALAND_SYNDICATE diff --git a/code/modules/jobs/job_types/spawner/lifebringer.dm b/code/modules/jobs/job_types/spawner/lifebringer.dm new file mode 100644 index 00000000000..550cbb3c254 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/lifebringer.dm @@ -0,0 +1,3 @@ +/datum/job/lifebringer + title = ROLE_LIFEBRINGER + policy_index = ROLE_LIFEBRINGER diff --git a/code/modules/jobs/job_types/spawner/maintenance_drone.dm b/code/modules/jobs/job_types/spawner/maintenance_drone.dm new file mode 100644 index 00000000000..4d46eb44983 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/maintenance_drone.dm @@ -0,0 +1,3 @@ +/datum/job/maintenance_drone + title = ROLE_MAINTENANCE_DRONE + policy_index = ROLE_MAINTENANCE_DRONE diff --git a/code/modules/jobs/job_types/spawner/skeleton.dm b/code/modules/jobs/job_types/spawner/skeleton.dm new file mode 100644 index 00000000000..9f3c443a0d9 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/skeleton.dm @@ -0,0 +1,3 @@ +/datum/job/skeleton + title = ROLE_SKELETON + policy_index = ROLE_SKELETON diff --git a/code/modules/jobs/job_types/spawner/space_bar_patron.dm b/code/modules/jobs/job_types/spawner/space_bar_patron.dm new file mode 100644 index 00000000000..1d1af939d87 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/space_bar_patron.dm @@ -0,0 +1,3 @@ +/datum/job/space_bar_patron + title = ROLE_SPACE_BAR_PATRON + policy_index = ROLE_SPACE_BAR_PATRON diff --git a/code/modules/jobs/job_types/spawner/space_bartender.dm b/code/modules/jobs/job_types/spawner/space_bartender.dm new file mode 100644 index 00000000000..c28bdd6895a --- /dev/null +++ b/code/modules/jobs/job_types/spawner/space_bartender.dm @@ -0,0 +1,3 @@ +/datum/job/space_bartender + title = ROLE_SPACE_BARTENDER + policy_index = ROLE_SPACE_BARTENDER diff --git a/code/modules/jobs/job_types/spawner/space_doctor.dm b/code/modules/jobs/job_types/spawner/space_doctor.dm new file mode 100644 index 00000000000..b1199263e03 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/space_doctor.dm @@ -0,0 +1,3 @@ +/datum/job/space_doctor + title = ROLE_SPACE_DOCTOR + policy_index = ROLE_SPACE_DOCTOR diff --git a/code/modules/jobs/job_types/spawner/space_pirate.dm b/code/modules/jobs/job_types/spawner/space_pirate.dm new file mode 100644 index 00000000000..cfada841c25 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/space_pirate.dm @@ -0,0 +1,3 @@ +/datum/job/space_pirate + title = ROLE_SPACE_PIRATE + policy_index = ROLE_SPACE_PIRATE diff --git a/code/modules/jobs/job_types/spawner/space_syndicate.dm b/code/modules/jobs/job_types/spawner/space_syndicate.dm new file mode 100644 index 00000000000..8ab88337e50 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/space_syndicate.dm @@ -0,0 +1,3 @@ +/datum/job/space_syndicate + title = ROLE_SPACE_SYNDICATE + policy_index = ROLE_SPACE_SYNDICATE diff --git a/code/modules/jobs/job_types/spawner/spider.dm b/code/modules/jobs/job_types/spawner/spider.dm new file mode 100644 index 00000000000..d55e6f4490d --- /dev/null +++ b/code/modules/jobs/job_types/spawner/spider.dm @@ -0,0 +1,3 @@ +/datum/job/spider + title = ROLE_SPIDER + policy_index = ROLE_SPIDER diff --git a/code/modules/jobs/job_types/spawner/syndicate_cybersun.dm b/code/modules/jobs/job_types/spawner/syndicate_cybersun.dm new file mode 100644 index 00000000000..5deba33fce8 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/syndicate_cybersun.dm @@ -0,0 +1,3 @@ +/datum/job/syndicate_cybersun + title = ROLE_SYNDICATE_CYBERSUN + policy_index = ROLE_SYNDICATE_CYBERSUN diff --git a/code/modules/jobs/job_types/spawner/syndicate_cybersun_captain.dm b/code/modules/jobs/job_types/spawner/syndicate_cybersun_captain.dm new file mode 100644 index 00000000000..697a5908f46 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/syndicate_cybersun_captain.dm @@ -0,0 +1,3 @@ +/datum/job/syndicate_cybersun_captain + title = ROLE_SYNDICATE_CYBERSUN_CAPTAIN + policy_index = ROLE_SYNDICATE_CYBERSUN_CAPTAIN diff --git a/code/modules/jobs/job_types/spawner/zombie.dm b/code/modules/jobs/job_types/spawner/zombie.dm new file mode 100644 index 00000000000..10df7b38bb3 --- /dev/null +++ b/code/modules/jobs/job_types/spawner/zombie.dm @@ -0,0 +1,3 @@ +/datum/job/zombie + title = ROLE_ZOMBIE + policy_index = ROLE_ZOMBIE diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index 690090bdba3..3543df807ad 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -1,7 +1,7 @@ /datum/job/station_engineer title = "Station Engineer" department_head = list("Chief Engineer") - faction = "Station" + faction = FACTION_STATION total_positions = 5 spawn_positions = 5 supervisors = "the chief engineer" @@ -30,6 +30,9 @@ /obj/item/clothing/head/hardhat/red/upgraded = 1 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/engineer name = "Station Engineer" jobtype = /datum/job/station_engineer diff --git a/code/modules/jobs/job_types/unassigned.dm b/code/modules/jobs/job_types/unassigned.dm new file mode 100644 index 00000000000..60fe3fe2ae8 --- /dev/null +++ b/code/modules/jobs/job_types/unassigned.dm @@ -0,0 +1,8 @@ +/** + * This type is used to indicate a lack of a job. + * The mind variable assigned_role will point here by default. + * As any other job datum, this is a singleton. + **/ + +/datum/job/unassigned + title = "Unassigned" diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index b5e6a5e64ce..2018aac3691 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -1,7 +1,7 @@ /datum/job/virologist title = "Virologist" department_head = list("Chief Medical Officer") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the chief medical officer" @@ -31,6 +31,8 @@ /obj/item/stack/sheet/mineral/uranium = 5 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + /datum/outfit/job/virologist name = "Virologist" diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index ba6f7579a7c..d1df59b00a1 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -2,7 +2,7 @@ title = "Warden" auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY department_head = list("Head of Security") - faction = "Station" + faction = FACTION_STATION total_positions = 1 spawn_positions = 1 supervisors = "the head of security" @@ -35,6 +35,9 @@ /obj/item/storage/box/lethalshot = 5 ) + job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE + + /datum/outfit/job/warden name = "Warden" jobtype = /datum/job/warden diff --git a/code/modules/jobs/jobs.dm b/code/modules/jobs/jobs.dm index 91bc2cca361..68fb986a3c0 100644 --- a/code/modules/jobs/jobs.dm +++ b/code/modules/jobs/jobs.dm @@ -99,10 +99,31 @@ GLOBAL_LIST_INIT(exp_jobsmap, list( EXP_TYPE_SERVICE = list("titles" = service_positions) )) +// TO DO: Replace this with job datum flags instead. GLOBAL_LIST_INIT(exp_specialmap, list( EXP_TYPE_LIVING = list(), // all living mobs EXP_TYPE_ANTAG = list(), - EXP_TYPE_SPECIAL = list("Lifebringer","Ash Walker","Exile","Servant Golem","Free Golem","Hermit","Translocated Vet","Escaped Prisoner","Hotel Staff","SuperFriend","Space Syndicate","Ancient Crew","Space Doctor","Space Bartender","Beach Bum","Skeleton","Zombie","Space Bar Patron","Lavaland Syndicate","Maintenance Drone","Ghost Role"), // Ghost roles + EXP_TYPE_SPECIAL = list( + ROLE_LIFEBRINGER, + ROLE_ASHWALKER, + ROLE_EXILE, + ROLE_SERVANT_GOLEM, + ROLE_FREE_GOLEM, + ROLE_HERMIT, + ROLE_ESCAPED_PRISONER, + ROLE_HOTEL_STAFF, + ROLE_SPACE_SYNDICATE, + ROLE_ANCIENT_CREW, + ROLE_SPACE_DOCTOR, + ROLE_SPACE_BARTENDER, + ROLE_BEACH_BUM, + ROLE_SKELETON, + ROLE_ZOMBIE, + ROLE_SPACE_BAR_PATRON, + ROLE_LAVALAND_SYNDICATE, + ROLE_MAINTENANCE_DRONE, + ROLE_GHOST_ROLE, + ), // Ghost roles EXP_TYPE_GHOST = list() // dead people, observers )) GLOBAL_PROTECT(exp_jobsmap) @@ -114,9 +135,9 @@ GLOBAL_PROTECT(exp_specialmap) if(!job_title) return list() - for(var/datum/job/J in SSjob.occupations) - if(J.title == job_title) - return J.department_head //this is a list + for(var/datum/job/job as anything in SSjob.joinable_occupations) + if(job.title == job_title) + return job.department_head //this is a list /proc/get_full_job_name(job) var/static/regex/cap_expand = new("cap(?!tain)") diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index 7bb1b788975..1ec1571ef29 100644 --- a/code/modules/mafia/controller.dm +++ b/code/modules/mafia/controller.dm @@ -580,7 +580,7 @@ mafia_panel.Grant(H) var/client/player_client = GLOB.directory[role.player_key] if(player_client) - player_client.prefs.copy_to(H) + player_client.prefs.safe_transfer_prefs_to(H, is_antag = TRUE) role.body = H player_role_lookup[H] = role H.key = role.player_key diff --git a/code/modules/mob/dead/crew_manifest.dm b/code/modules/mob/dead/crew_manifest.dm index 079be96594f..46d7a262d87 100644 --- a/code/modules/mob/dead/crew_manifest.dm +++ b/code/modules/mob/dead/crew_manifest.dm @@ -40,7 +40,7 @@ list("flag" = DEPARTMENT_SILICON, "name" = "Silicon") ) - for(var/job in SSjob.occupations) + for(var/job in SSjob.joinable_occupations) // Check if there are additional open positions or if there is no limit if ((job["total_positions"] > 0 && job["total_positions"] > job["current_positions"]) || (job["total_positions"] == -1)) for(var/department in departments) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 7a276f4b212..8e92857dfb4 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -1,22 +1,22 @@ #define LINKIFY_READY(string, value) "[string]" /mob/dead/new_player - var/ready = 0 - var/spawning = 0//Referenced when you want to delete the new_player later on in the code. - flags_1 = NONE - invisibility = INVISIBILITY_ABSTRACT - density = FALSE stat = DEAD hud_possible = list() - var/mob/living/new_character //for instant transfer once the round is set up - - //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles + var/ready = FALSE + /// Referenced when you want to delete the new_player later on in the code. + var/spawning = FALSE + /// For instant transfer once the round is set up + var/mob/living/new_character + ///Used to make sure someone doesn't get spammed with messages if they're ineligible for roles. var/ineligible_for_roles = FALSE + + /mob/dead/new_player/Initialize() if(client && SSticker.state == GAME_STATE_STARTUP) var/atom/movable/screen/splash/S = new(client, TRUE, TRUE) @@ -269,14 +269,14 @@ /mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE) var/datum/job/job = SSjob.GetJob(rank) - if(!job) + if(!(job.job_flags & JOB_NEW_PLAYER_JOINABLE)) return JOB_UNAVAILABLE_GENERIC if((job.current_positions >= job.total_positions) && job.total_positions != -1) - if(job.title == "Assistant") + if(is_assistant_job(job)) if(isnum(client.player_age) && client.player_age <= 14) //Newbies can always be assistants return JOB_AVAILABLE - for(var/datum/job/J in SSjob.occupations) - if(J && J.current_positions < J.total_positions && J.title != job.title) + for(var/datum/job/other_job as anything in SSjob.joinable_occupations) + if(other_job.current_positions < other_job.total_positions && other_job != job) return JOB_UNAVAILABLE_SLOTFULL else return JOB_UNAVAILABLE_SLOTFULL @@ -298,7 +298,6 @@ tgui_alert(usr, get_job_unavailable_error_message(error, rank)) return FALSE - var/arrivals_docked = TRUE if(SSshuttle.arrivals) close_spawn_windows() //In case we get held up if(SSshuttle.arrivals.damaged && CONFIG_GET(flag/arrivals_shuttle_require_safe_latejoin)) @@ -307,38 +306,42 @@ if(CONFIG_GET(flag/arrivals_shuttle_require_undocked)) SSshuttle.arrivals.RequireUndocked(src) - arrivals_docked = SSshuttle.arrivals.mode != SHUTTLE_CALL //Remove the player from the join queue if he was in one and reset the timer SSticker.queued_players -= src SSticker.queue_delay = 4 - SSjob.AssignRole(src, rank, 1) - - var/mob/living/character = create_character(TRUE) //creates the human and transfers vars and mind - - var/is_captain = FALSE - // If we don't have an assigned cap yet, check if this person qualifies for some from of captaincy. - if(!SSjob.assigned_captain && ishuman(character) && SSjob.chain_of_command[rank] && !is_banned_from(ckey, list("Captain"))) - is_captain = TRUE - // If we already have a captain, are they a "Captain" rank and are we allowing multiple of them to be assigned? - else if(SSjob.always_promote_captain_job && (rank == "Captain")) - is_captain = TRUE - - var/equip = SSjob.EquipRank(character, rank, TRUE, is_captain) - if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob. - character = equip - var/datum/job/job = SSjob.GetJob(rank) - if(job && !job.override_latejoin_spawn(character)) - SSjob.SendToLateJoin(character) - if(!arrivals_docked) - var/atom/movable/screen/splash/Spl = new(character.client, TRUE) - Spl.Fade(TRUE) - character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25) + SSjob.AssignRole(src, job, TRUE) - character.update_parallax_teleport() + mind.late_joiner = TRUE + var/atom/destination = mind.assigned_role.get_latejoin_spawn_point() + if(!destination) + CRASH("Failed to find a latejoin spawn point.") + var/mob/living/character = create_character(destination) + if(!character) + CRASH("Failed to create a character for latejoin.") + transfer_character() + + SSjob.EquipRank(character, job, character.client) + + #define IS_NOT_CAPTAIN 0 + #define IS_ACTING_CAPTAIN 1 + #define IS_FULL_CAPTAIN 2 + var/is_captain = IS_NOT_CAPTAIN + // If we already have a captain, are they a "Captain" rank and are we allowing multiple of them to be assigned? + if(is_captain_job(job)) + is_captain = IS_FULL_CAPTAIN + // If we don't have an assigned cap yet, check if this person qualifies for some from of captaincy. + else if(!SSjob.assigned_captain && ishuman(character) && SSjob.chain_of_command[rank] && !is_banned_from(ckey, list("Captain"))) + is_captain = IS_ACTING_CAPTAIN + if(is_captain != IS_NOT_CAPTAIN) + minor_announce(job.get_captaincy_announcement(character)) + SSjob.promote_to_captain(character, is_captain == IS_ACTING_CAPTAIN) + #undef IS_NOT_CAPTAIN + #undef IS_ACTING_CAPTAIN + #undef IS_FULL_CAPTAIN SSticker.minds += character.mind character.client.init_verbs() // init verbs for the late join @@ -434,54 +437,37 @@ popup.set_content(jointext(dat, "")) popup.open(FALSE) // 0 is passed to open so that it doesn't use the onclose() proc -/mob/dead/new_player/proc/create_character(transfer_after) - spawning = 1 + +/// Creates, assigns and returns the new_character to spawn as. Assumes a valid mind.assigned_role exists. +/mob/dead/new_player/proc/create_character(atom/destination) + spawning = TRUE close_spawn_windows() - var/mob/living/carbon/human/H = new(loc) - - var/frn = CONFIG_GET(flag/force_random_names) - if(!frn) - frn = is_banned_from(ckey, "Appearance") - if(QDELETED(src)) - return - if(frn) - client.prefs.random_character() - client.prefs.real_name = client.prefs.pref_species.random_name(gender,1) - - var/is_antag - if(mind in GLOB.pre_setup_antags) - is_antag = TRUE - - client.prefs.copy_to(H, antagonist = is_antag, is_latejoiner = transfer_after) - - if(GLOB.current_anonymous_theme)//overrides random name because it achieves the same effect and is an admin enabled event tool - randomize_human(H) - H.fully_replace_character_name(null, GLOB.current_anonymous_theme.anonymous_name(H)) - - H.dna.update_dna_identity() - if(mind) - if(transfer_after) - mind.late_joiner = TRUE - mind.active = FALSE //we wish to transfer the key manually + mind.active = FALSE //we wish to transfer the key manually + var/mob/living/spawning_mob = mind.assigned_role.get_spawn_mob(client, destination) + if(QDELETED(src) || !client) + return // Disconnected while checking for the appearance ban. + if(!isAI(spawning_mob)) // Unfortunately there's still snowflake AI code out there. mind.original_character_slot_index = client.prefs.default_slot - mind.transfer_to(H) //won't transfer key since the mind is not active - mind.set_original_character(H) - - H.name = real_name + mind.transfer_to(spawning_mob) //won't transfer key since the mind is not active + mind.set_original_character(spawning_mob) client.init_verbs() - . = H + . = spawning_mob new_character = . - if(transfer_after) - transfer_character() + /mob/dead/new_player/proc/transfer_character() . = new_character - if(.) - new_character.key = key //Manually transfer the key to log them in, - new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC) - new_character = null - qdel(src) + if(!.) + return + new_character.key = key //Manually transfer the key to log them in, + new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC) + var/area/joined_area = get_area(new_character.loc) + if(joined_area) + joined_area.on_joining_game(new_character) + new_character = null + qdel(src) + /mob/dead/new_player/proc/ViewManifest() if(!client) diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index a36dc2d2bef..d4b97fc22bc 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -1,16 +1,64 @@ +/// Fully randomizes everything in the character. +/datum/preferences/proc/randomise_appearance_prefs(randomise_flags = ALL) + if(randomise_flags & RANDOMIZE_GENDER) + gender = pick(MALE, FEMALE, PLURAL) + switch(gender) + if(MALE, FEMALE) + body_type = gender + else + body_type = pick(MALE, FEMALE) + if(randomise_flags & RANDOMIZE_SPECIES) + var/rando_race = GLOB.species_list[pick(GLOB.roundstart_races)] + pref_species = new rando_race() + if(randomise_flags & RANDOMIZE_NAME) + real_name = pref_species.random_name(gender, TRUE) + if(randomise_flags & RANDOMIZE_AGE) + age = rand(AGE_MIN, AGE_MAX) + if(randomise_flags & RANDOMIZE_UNDERWEAR) + underwear = random_underwear(gender) + if(randomise_flags & RANDOMIZE_UNDERWEAR_COLOR) + underwear_color = random_short_color() + if(randomise_flags & RANDOMIZE_UNDERSHIRT) + undershirt = random_undershirt(gender) + if(randomise_flags & RANDOMIZE_SOCKS) + socks = random_socks() + if(randomise_flags & RANDOMIZE_BACKPACK) + backpack = random_backpack() + if(randomise_flags & RANDOMIZE_JUMPSUIT_STYLE) + jumpsuit_style = pick(GLOB.jumpsuitlist) + if(randomise_flags & RANDOMIZE_HAIRSTYLE) + hairstyle = random_hairstyle(gender) + if(randomise_flags & RANDOMIZE_FACIAL_HAIRSTYLE) + facial_hairstyle = random_facial_hairstyle(gender) + if(randomise_flags & RANDOMIZE_HAIR_COLOR) + hair_color = random_short_color() + if(randomise_flags & RANDOMIZE_FACIAL_HAIR_COLOR) + facial_hair_color = random_short_color() + if(randomise_flags & RANDOMIZE_SKIN_TONE) + skin_tone = random_skin_tone() + if(randomise_flags & RANDOMIZE_EYE_COLOR) + eye_color = random_eye_color() + if(randomise_flags & RANDOMIZE_FEATURES) + features = random_features() - //The mob should have a gender you want before running this proc. Will run fine without H -/datum/preferences/proc/random_character(gender_override, antag_override = FALSE) + +/// Randomizes the character according to preferences. +/datum/preferences/proc/apply_character_randomization_prefs(antag_override = FALSE) + if(!randomise[RANDOM_BODY] && !(antag_override && randomise[RANDOM_BODY_ANTAG])) + return // Prefs say "no, thank you" + if(randomise[RANDOM_GENDER] || antag_override && randomise[RANDOM_GENDER_ANTAG]) + gender = pick(MALE, FEMALE, PLURAL) + switch(gender) + if(MALE, FEMALE) + body_type = gender + else + body_type = pick(MALE, FEMALE) if(randomise[RANDOM_SPECIES]) random_species() - else if(randomise[RANDOM_NAME]) - real_name = pref_species.random_name(gender,1) - if(gender_override && !(randomise[RANDOM_GENDER] || randomise[RANDOM_GENDER_ANTAG] && antag_override)) - gender = gender_override - else - gender = pick(MALE,FEMALE,PLURAL) - if(randomise[RANDOM_AGE] || randomise[RANDOM_AGE_ANTAG] && antag_override) - age = rand(AGE_MIN,AGE_MAX) + else if(randomise[RANDOM_NAME] || antag_override && randomise[RANDOM_NAME_ANTAG]) + real_name = pref_species.random_name(gender, TRUE) + if(randomise[RANDOM_AGE] || antag_override && randomise[RANDOM_AGE_ANTAG]) + age = rand(AGE_MIN, AGE_MAX) if(randomise[RANDOM_UNDERWEAR]) underwear = random_underwear(gender) if(randomise[RANDOM_UNDERWEAR_COLOR]) @@ -35,14 +83,8 @@ skin_tone = random_skin_tone() if(randomise[RANDOM_EYE_COLOR]) eye_color = random_eye_color() - if(!pref_species) - var/rando_race = pick(GLOB.roundstart_races) - pref_species = new rando_race() features = random_features() - if(gender in list(MALE, FEMALE)) - body_type = gender - else - body_type = pick(MALE, FEMALE) + /datum/preferences/proc/random_species() var/random_species_type = GLOB.species_list[pick(GLOB.roundstart_races)] @@ -50,21 +92,22 @@ if(randomise[RANDOM_NAME]) real_name = pref_species.random_name(gender,1) -///Setup a hardcore random character and calculate their hardcore random score -/datum/preferences/proc/hardcore_random_setup(mob/living/carbon/human/character, antagonist, is_latejoiner) - var/rand_gender = pick(list(MALE, FEMALE, PLURAL)) - random_character(rand_gender, antagonist) - select_hardcore_quirks() - hardcore_survival_score = hardcore_survival_score ** 1.2 //30 points would be about 60 score - if(is_latejoiner)//prevent them from cheatintg - hardcore_survival_score = 0 -///Go through all quirks that can be used in hardcore mode and select some based on a random budget. +///Setup the random hardcore quirks and give the character the new score prize. +/datum/preferences/proc/hardcore_random_setup(mob/living/carbon/human/character) + var/next_hardcore_score = select_hardcore_quirks() + character.hardcore_survival_score = next_hardcore_score ** 1.2 //30 points would be about 60 score + + +/** + * Goes through all quirks that can be used in hardcore mode and select some based on a random budget. + * Returns the new value to be gained with this setup, plus the previously earned score. + **/ /datum/preferences/proc/select_hardcore_quirks() + . = 0 var/quirk_budget = rand(8, 35) - all_quirks = list() //empty it out var/list/available_hardcore_quirks = SSquirks.hardcore_quirks.Copy() @@ -102,9 +145,10 @@ all_quirks += initial(picked_quirk.name) quirk_budget -= available_hardcore_quirks[picked_quirk] - hardcore_survival_score += available_hardcore_quirks[picked_quirk] + . += available_hardcore_quirks[picked_quirk] available_hardcore_quirks -= picked_quirk + /datum/preferences/proc/update_preview_icon() // Determine what job is marked as 'High' priority, and dress them up as such. var/datum/job/previewJob @@ -125,11 +169,11 @@ // Set up the dummy for its photoshoot var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) - copy_to(mannequin, 1, TRUE, TRUE) + apply_prefs_to(mannequin, TRUE) if(previewJob) mannequin.job = previewJob.title - previewJob.equip(mannequin, TRUE, preference_source = parent) + mannequin.dress_up_as_job(previewJob, TRUE) COMPILE_OVERLAYS(mannequin) parent.show_character_previews(new /mutable_appearance(mannequin)) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index eb76d763b8d..d142a821596 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -808,13 +808,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp name = client.prefs.real_name /mob/dead/observer/proc/set_ghost_appearance() - if((!client) || (!client.prefs)) + if(!client?.prefs) return - if(client.prefs.randomise[RANDOM_NAME]) - client.prefs.real_name = random_unique_name(gender) - if(client.prefs.randomise[RANDOM_BODY]) - client.prefs.random_character(gender) + client.prefs.apply_character_randomization_prefs() if(HAIR in client.prefs.pref_species.species_traits) hairstyle = client.prefs.hairstyle diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index dcb978da98e..33acf48fef2 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -269,7 +269,7 @@ /mob/living/carbon/human/get_blood_id() if(HAS_TRAIT(src, TRAIT_HUSK)) return - if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS] && mind && mind.assigned_role == "Clown") + if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS] && is_clown_job(mind?.assigned_role)) return /datum/reagent/colorful_reagent if(dna.species.exotic_blood) return dna.species.exotic_blood diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index db407626e0a..8133052e3f6 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -23,7 +23,7 @@ /mob/living/brain/proc/create_dna() stored_dna = new /datum/dna/stored(src) if(!stored_dna.species) - var/rando_race = pick(GLOB.roundstart_races) + var/rando_race = GLOB.species_list[pick(GLOB.roundstart_races)] stored_dna.species = new rando_race() /mob/living/brain/Destroy() diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm index e65e66bf413..273411c5fed 100644 --- a/code/modules/mob/living/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -21,7 +21,7 @@ GLOBAL_VAR(posibrain_notify_cooldown) ///Message sent as a visible message on failure var/fail_message = "The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?" ///Role assigned to the newly created mind - var/new_role = "Positronic Brain" + var/posibrain_job_path = /datum/job/positronic_brain ///Visible message sent when a player possesses the brain var/new_mob_message = "The positronic brain chimes quietly." ///Examine message when the posibrain has no mob @@ -125,7 +125,7 @@ GLOBAL_VAR(posibrain_notify_cooldown) brainmob.timeofhostdeath = C.timeofdeath brainmob.set_stat(CONSCIOUS) if(brainmob.mind) - brainmob.mind.assigned_role = new_role + brainmob.mind.set_assigned_role(SSjob.GetJobType(posibrain_job_path)) if(C.mind) C.mind.transfer_to(brainmob) @@ -148,7 +148,7 @@ GLOBAL_VAR(posibrain_notify_cooldown) var/policy = get_policy(ROLE_POSIBRAIN) if(policy) to_chat(brainmob, policy) - brainmob.mind.assigned_role = new_role + brainmob.mind.set_assigned_role(SSjob.GetJobType(posibrain_job_path)) brainmob.set_stat(CONSCIOUS) visible_message(new_mob_message) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index f11d0d76436..fa1f5208906 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -66,7 +66,7 @@ GLOBAL_LIST_EMPTY(dummy_mob_list) else //even if target isn't a carbon, if they have a client we can make the //dummy look like what their human would look like based on their prefs - target?.client?.prefs?.copy_to(copycat, icon_updates=TRUE, roundstart_checks=FALSE, character_setup=TRUE) + target?.client?.prefs?.apply_prefs_to(copycat, TRUE) return copycat diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c2938d5eb7a..447c63f902c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1007,8 +1007,8 @@ /mob/living/carbon/human/get_exp_list(minutes) . = ..() - if(mind.assigned_role in SSjob.name_occupations) - .[mind.assigned_role] = minutes + if(mind.assigned_role.title in SSjob.name_occupations) + .[mind.assigned_role.title] = minutes /mob/living/carbon/human/monkeybrain ai_controller = /datum/ai_controller/monkey diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4794cbcd465..7fc991fe811 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -663,10 +663,10 @@ ///Overrides the point value that the mob is worth /mob/living/carbon/human/singularity_act() . = 20 - if(mind) - if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") ) + switch(mind?.assigned_role.type) + if(/datum/job/chief_engineer, /datum/job/station_engineer) . = 100 - if(mind.assigned_role == "Clown") + if(/datum/job/clown) . = rand(-1000, 1000) ..() //Called afterwards because getting the mind after getting gibbed is sketchy diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 8b3a4460356..374f4538679 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -238,3 +238,53 @@ destination.undershirt = undershirt destination.socks = socks destination.jumpsuit_style = jumpsuit_style + + +/// Fully randomizes everything according to the given flags. +/mob/living/carbon/human/proc/randomize_human_appearance(randomise_flags = ALL) + if(randomise_flags & RANDOMIZE_GENDER) + gender = pick(MALE, FEMALE, PLURAL) + switch(gender) + if(MALE, FEMALE) + body_type = gender + else + body_type = pick(MALE, FEMALE) + if(randomise_flags & RANDOMIZE_SPECIES) + set_species(GLOB.species_list[pick(GLOB.roundstart_races)], FALSE) + if(randomise_flags & RANDOMIZE_NAME) + var/new_name = dna.species.random_name(gender, TRUE) + name = new_name + real_name = new_name + if(randomise_flags & RANDOMIZE_AGE) + age = rand(AGE_MIN, AGE_MAX) + if(randomise_flags & RANDOMIZE_UNDERWEAR) + underwear = random_underwear(gender) + if(randomise_flags & RANDOMIZE_UNDERWEAR_COLOR) + underwear_color = random_short_color() + if(randomise_flags & RANDOMIZE_UNDERSHIRT) + undershirt = random_undershirt(gender) + if(randomise_flags & RANDOMIZE_SOCKS) + socks = random_socks() + if(randomise_flags & RANDOMIZE_BACKPACK) + backpack = random_backpack() + if(randomise_flags & RANDOMIZE_JUMPSUIT_STYLE) + jumpsuit_style = pick(GLOB.jumpsuitlist) + if(randomise_flags & RANDOMIZE_HAIRSTYLE) + hairstyle = random_hairstyle(gender) + if(randomise_flags & RANDOMIZE_FACIAL_HAIRSTYLE) + facial_hairstyle = random_facial_hairstyle(gender) + if(randomise_flags & RANDOMIZE_HAIR_COLOR) + hair_color = random_short_color() + if(randomise_flags & RANDOMIZE_FACIAL_HAIR_COLOR) + facial_hair_color = random_short_color() + if(randomise_flags & RANDOMIZE_SKIN_TONE) + skin_tone = random_skin_tone() + if(randomise_flags & RANDOMIZE_EYE_COLOR) + eye_color = random_eye_color() + var/obj/item/organ/eyes/organ_eyes = getorgan(/obj/item/organ/eyes) + if(organ_eyes) + if(!initial(organ_eyes.eye_color)) + organ_eyes.eye_color = eye_color + organ_eyes.old_eye_color = eye_color + if(randomise_flags & RANDOMIZE_FEATURES) + dna.features = random_features() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index cf06b7cb1c5..85b437a418a 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1150,11 +1150,11 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.visible_message(span_notice("[H] start putting on [I]..."), span_notice("You start putting on [I]...")) return do_after(H, I.equip_delay_self, target = H) -/datum/species/proc/before_equip_job(datum/job/J, mob/living/carbon/human/H) + +/// Equips the necessary species-relevant gear before putting on the rest of the uniform. +/datum/species/proc/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only = FALSE) return -/datum/species/proc/after_equip_job(datum/job/J, mob/living/carbon/human/H) - H.update_mutant_bodyparts() /datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, delta_time, times_fired) if(chem.type == exotic_blood) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index b5415c1e8c0..acb0b7cba40 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -78,11 +78,13 @@ no_protection = TRUE . = ..() -/datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE) - if(J.plasmaman_outfit) - H.equipOutfit(J.plasmaman_outfit, visualsOnly) - H.internal = H.get_item_for_held_index(2) - H.update_internals_hud_icon(1) + +/datum/species/plasmaman/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only = FALSE) + if(job.plasmaman_outfit) + equipping.equipOutfit(job.plasmaman_outfit, visuals_only) + equipping.internal = equipping.get_item_for_held_index(2) + equipping.update_internals_hud_icon(1) + /datum/species/plasmaman/random_name(gender,unique,lastname) if(unique) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 1b65669e6c2..667f0871aa7 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -521,7 +521,7 @@ All effects don't start immediately, but rather get worse over time; the rate is if(drunkenness >= 11 && slurring < 5) slurring += 0.6 * delta_time - if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director")) + if(mind && (is_scientist_job(mind.assigned_role) || is_research_director_job(mind.assigned_role))) if(SSresearch.science_tech) if(drunkenness >= 12.9 && drunkenness <= 13.8) drunkenness = round(drunkenness, 0.01) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index de7c110560b..e10341c1f78 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1975,7 +1975,7 @@ if(mind && mind.special_role && !(mind.datum_flags & DF_VAR_EDITED)) exp_list[mind.special_role] = minutes - if(mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) - exp_list[mind.assigned_role] = minutes + if(mind.assigned_role.title in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) + exp_list[mind.assigned_role.title] = minutes return exp_list diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 0f2e57680fc..b56ce7538ff 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -49,23 +49,21 @@ //If this body is meant to be a borg controlled by the AI player if(shell) make_shell() + else + //MMI stuff. Held togheter by magic. ~Miauw + if(!mmi?.brainmob) + mmi = new (src) + mmi.brain = new /obj/item/organ/brain(mmi) + mmi.brain.organ_flags |= ORGAN_FROZEN + mmi.brain.name = "[real_name]'s brain" + mmi.name = "[initial(mmi.name)]: [real_name]" + mmi.set_brainmob(new /mob/living/brain(mmi)) + mmi.brainmob.name = src.real_name + mmi.brainmob.real_name = src.real_name + mmi.brainmob.container = mmi + mmi.update_appearance() + setup_default_name() - //MMI stuff. Held togheter by magic. ~Miauw - else if(!mmi || !mmi.brainmob) - mmi = new (src) - mmi.brain = new /obj/item/organ/brain(mmi) - mmi.brain.organ_flags |= ORGAN_FROZEN - mmi.brain.name = "[real_name]'s brain" - mmi.name = "[initial(mmi.name)]: [real_name]" - mmi.set_brainmob(new /mob/living/brain(mmi)) - mmi.brainmob.name = src.real_name - mmi.brainmob.real_name = src.real_name - mmi.brainmob.container = mmi - mmi.update_appearance() - - INVOKE_ASYNC(src, .proc/updatename) - - playsound(loc, 'sound/voice/liveagain.ogg', 75, TRUE) aicamera = new/obj/item/camera/siliconcam/robot_camera(src) toner = tonermax diag_hud_set_borgcell() @@ -163,26 +161,39 @@ model.transform_to(model_list[input_model]) -/mob/living/silicon/robot/proc/updatename(client/C) + +/// Used to setup the a basic and (somewhat) unique name for the robot. +/mob/living/silicon/robot/proc/setup_default_name() + var/new_name + if(GLOB.current_anonymous_theme) //only robotic renames will allow for anything other than the anonymous one + new_name = GLOB.current_anonymous_theme.anonymous_ai_name(FALSE) + else if(custom_name) + new_name = custom_name + else + new_name = get_standard_name() + if(new_name != real_name) + fully_replace_character_name(real_name, new_name) + + +/// Updates the borg name taking the client preferences into account. +/mob/living/silicon/robot/proc/updatename(client/pref_source) if(shell) return - if(!C) - C = client + if(!pref_source) + pref_source = client var/changed_name = "" - if(custom_name) - changed_name = custom_name if(GLOB.current_anonymous_theme) //only robotic renames will allow for anything other than the anonymous one changed_name = GLOB.current_anonymous_theme.anonymous_ai_name(FALSE) - if(!changed_name && C && C.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME) - apply_pref_name("cyborg", C) + else if(custom_name) + changed_name = custom_name + else if(pref_source && pref_source.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME) + apply_pref_name("cyborg", pref_source) return //built in camera handled in proc - if(!changed_name) + else changed_name = get_standard_name() - real_name = changed_name - name = real_name - if(!QDELETED(builtInCamera)) - builtInCamera.c_tag = real_name //update the camera name too + fully_replace_character_name(real_name, changed_name) + /mob/living/silicon/robot/proc/get_standard_name() return "[(designation ? "[designation] " : "")][mmi.braintype]-[ident]" @@ -670,14 +681,17 @@ . = TRUE toggle_headlamp(FALSE, TRUE) //This will reenable borg headlamps if doomsday is currently going on still. + /mob/living/silicon/robot/fully_replace_character_name(oldname, newname) - ..() - if(oldname != real_name) - notify_ai(RENAME, oldname, newname) + . = ..() + if(!.) + return + notify_ai(RENAME, oldname, newname) if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name custom_name = newname + /mob/living/silicon/robot/proc/ResetModel() SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT) uneq_all() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm index 9b18cd5fa2c..d014051dab9 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -26,7 +26,7 @@ short_desc = "You are a Maintenance Drone." flavour_text = "Born out of science, your purpose is to maintain Space Station 13. Maintenance Drones can become the backbone of a healthy station." important_info = "You MUST read and follow your laws carefully." - assignedrole = "Maintenance Drone" + spawner_job_path = /datum/job/maintenance_drone /obj/effect/mob_spawn/drone/Initialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 1d6c85d33cf..6679a856327 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -65,7 +65,7 @@ short_desc = "You are a Syndicate Maintenance Drone." flavour_text = "In a prior life, you maintained a Nanotrasen Research Station. Abducted from your home, you were given some upgrades... and now serve an enemy of your former masters." important_info = "" - assignedrole = null + spawner_job_path = /datum/job/ghost_role /obj/effect/mob_spawn/drone/syndrone/badass name = "badass syndrone shell" @@ -117,7 +117,7 @@ short_desc = "You are a drone on Kosmicheskaya Stantsiya 13." flavour_text = "Something has brought you out of hibernation, and the station is in gross disrepair." important_info = "Build, repair, maintain and improve the station that housed you on activation." - assignedrole = null + spawner_job_path = /datum/job/ghost_role /mob/living/simple_animal/drone/derelict name = "derelict drone" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 380b10d929e..2faf78e7d6f 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -474,13 +474,12 @@ GLOBAL_DATUM(blackbox, /obj/machinery/smartfridge/black_box) /obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user) if(..() && ishuman(user) && !(user in affected_targets)) - var/mob/living/carbon/human/H = user - for(var/obj/item/W in H) - H.dropItemToGround(W) - var/datum/job/clown/C = new /datum/job/clown() - C.equip(H) - qdel(C) - affected_targets.Add(H) + var/mob/living/carbon/human/new_clown = user + for(var/obj/item/to_strip in new_clown) + new_clown.dropItemToGround(to_strip) + new_clown.dress_up_as_job(SSjob.GetJobType(/datum/job/clown)) + affected_targets.Add(new_clown) + /obj/machinery/anomalous_crystal/theme_warp //Warps the area you're in to look like a new one observer_desc = "This crystal warps the area around it to a theme." diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 794b1fc36f7..f86b7815daa 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1052,14 +1052,17 @@ * * Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn */ -/mob/proc/fully_replace_character_name(oldname,newname) +/mob/proc/fully_replace_character_name(oldname, newname) if(!newname) log_message("[src] failed name change from [oldname] as no new name was specified", LOG_OWNERSHIP) return FALSE + if(oldname == newname) + log_message("[src] failed name change as the new name was the same as the old one: [oldname]", LOG_OWNERSHIP) + return FALSE log_message("[src] name changed from [oldname] to [newname]", LOG_OWNERSHIP) - log_played_names(ckey,newname) + log_played_names(ckey, newname) real_name = newname name = newname diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index b5fafd9ed30..1205b60cd89 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -392,14 +392,14 @@ log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.") message_admins("[key_name_admin(usr)] has offered control of ([ADMIN_LOOKUPFLW(M)]) to ghosts") var/poll_message = "Do you want to play as [M.real_name]?" - if(M.mind && M.mind.assigned_role) - poll_message = "[poll_message] Job:[M.mind.assigned_role]." - if(M.mind && M.mind.special_role) - poll_message = "[poll_message] Status:[M.mind.special_role]." - else if(M.mind) - var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/) - if(A) - poll_message = "[poll_message] Status:[A.name]." + if(M.mind) + poll_message = "[poll_message] Job: [M.mind.assigned_role.title]." + if(M.mind.special_role) + poll_message = "[poll_message] Status: [M.mind.special_role]." + else + var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/) + if(A) + poll_message = "[poll_message] Status: [A.name]." var/list/mob/dead/observer/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, FALSE, 100, M) if(LAZYLEN(candidates)) @@ -500,10 +500,11 @@ . = list() . += "[type]" if(mind) - . += mind.assigned_role + if(mind.assigned_role.policy_index) + . += mind.assigned_role.policy_index . += mind.special_role //In case there's something special leftover, try to avoid - for(var/datum/antagonist/A in mind.antag_datums) - . += "[A.type]" + for(var/datum/antagonist/antag_datum as anything in mind.antag_datums) + . += "[antag_datum.type]" ///Can the mob see reagents inside of containers? /mob/proc/can_see_reagents() diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm index 1217b49a9e5..91baf04ab2e 100644 --- a/code/modules/mob/mob_transformation_simple.dm +++ b/code/modules/mob/mob_transformation_simple.dm @@ -47,7 +47,7 @@ D.updateappearance(mutcolor_update=1, mutations_overlay_update=1) else if(ishuman(M)) var/mob/living/carbon/human/H = M - client.prefs.copy_to(H) + client.prefs.safe_transfer_prefs_to(H) H.dna.update_dna_identity() if(mind && isliving(M)) diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm index cbe9941a95d..12ca0072602 100644 --- a/code/modules/modular_computers/file_system/programs/jobmanagement.dm +++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm @@ -37,22 +37,33 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) ..() change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay) + +/datum/computer_file/program/job_management/proc/can_edit_job(datum/job/job) + if(!job || !(job.job_flags & JOB_CREW_MEMBER) || (job.title in blacklisted)) + return FALSE + return TRUE + + /datum/computer_file/program/job_management/proc/can_open_job(datum/job/job) - if(!(job?.title in blacklisted)) - if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100))) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) - return TRUE + if(!can_edit_job(job)) + return FALSE + if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100))) + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) + return TRUE return FALSE + /datum/computer_file/program/job_management/proc/can_close_job(datum/job/job) - if(!(job?.title in blacklisted)) - if(job.total_positions > length(GLOB.player_list) * (max_relative_positions / 100)) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) - return TRUE + if(!can_edit_job(job)) + return FALSE + if(job.total_positions > length(GLOB.player_list) * (max_relative_positions / 100)) + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) + return TRUE return FALSE + /datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui) . = ..() if(.) @@ -95,7 +106,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) return var/priority_target = params["target"] var/datum/job/j = SSjob.GetJob(priority_target) - if(!j) + if(!j || !can_edit_job(j)) return if(j.total_positions <= j.current_positions) return @@ -119,7 +130,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) data["authed"] = authed var/list/pos = list() - for(var/j in SSjob.occupations) + for(var/j in SSjob.joinable_occupations) var/datum/job/job = j if(job.title in blacklisted) continue diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 5089aab7ca7..48be4771801 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -228,7 +228,7 @@ clumsy_check = FALSE /obj/item/gun/ballistic/revolver/reverse/can_trigger_gun(mob/living/user) - if((HAS_TRAIT(user, TRAIT_CLUMSY)) || (user.mind && user.mind.assigned_role == "Clown")) + if(HAS_TRAIT(user, TRAIT_CLUMSY) || is_clown_job(user.mind?.assigned_role)) return ..() if(process_fire(user, user, FALSE, null, BODY_ZONE_HEAD)) user.visible_message(span_warning("[user] somehow manages to shoot [user.p_them()]self in the face!"), span_userdanger("You somehow shoot yourself in the face! How the hell?!")) diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 29fc7b58eb8..89854f7c203 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -147,7 +147,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY)) //clumsy return TRUE if(user.mind) - if(user.mind.assigned_role == "Clown") //traitor clowns can use this, even though they're technically not clumsy + if(is_clown_job(user.mind.assigned_role)) //traitor clowns can use this, even though they're technically not clumsy return TRUE if(user.mind.has_antag_datum(/datum/antagonist/nukeop/clownop)) //clown ops aren't clumsy by default and technically don't have an assigned role of "Clown", but come on, they're basically clowns return TRUE diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 4476e93737f..49643a50136 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -260,7 +260,7 @@ new_mob = new path(M.loc) if("humanoid") - new_mob = new /mob/living/carbon/human(M.loc) + var/mob/living/carbon/human/new_human = new (M.loc) if(prob(50)) var/list/chooseable_races = list() @@ -269,17 +269,16 @@ if(initial(S.changesource_flags) & WABBAJACK) chooseable_races += speciestype - if(chooseable_races.len) - new_mob.set_species(pick(chooseable_races)) + if(length(chooseable_races)) + new_human.set_species(pick(chooseable_races)) - var/datum/preferences/A = new() //Randomize appearance for the human - A.copy_to(new_mob, icon_updates=0) - - var/mob/living/carbon/human/H = new_mob - H.update_body() - H.update_hair() - H.update_body_parts() - H.dna.update_dna_identity() + // Randomize everything but the species, which was already handled above. + new_human.randomize_human_appearance(~RANDOMIZE_SPECIES) + new_human.update_body() + new_human.update_hair() + new_human.update_body_parts() + new_human.dna.update_dna_identity() + new_mob = new_human if(!new_mob) return @@ -575,8 +574,8 @@ /obj/projectile/magic/wipe/proc/possession_test(mob/living/carbon/M) var/datum/brain_trauma/special/imaginary_friend/trapped_owner/trauma = M.gain_trauma(/datum/brain_trauma/special/imaginary_friend/trapped_owner) var/poll_message = "Do you want to play as [M.real_name]?" - if(M.mind && M.mind.assigned_role) - poll_message = "[poll_message] Job:[M.mind.assigned_role]." + if(M.mind) + poll_message = "[poll_message] Job:[M.mind.assigned_role.title]." if(M.mind && M.mind.special_role) poll_message = "[poll_message] Status:[M.mind.special_role]." else if(M.mind) diff --git a/code/modules/religion/religion_structures.dm b/code/modules/religion/religion_structures.dm index c58238b90f6..ef2289de54d 100644 --- a/code/modules/religion/religion_structures.dm +++ b/code/modules/religion/religion_structures.dm @@ -67,7 +67,7 @@ /obj/structure/altar_of_gods/proc/get_chaplains() var/chaplain_string = "" for(var/mob/living/carbon/human/potential_chap in GLOB.player_list) - if(potential_chap.key && potential_chap.mind?.assigned_role == "Chaplain") + if(potential_chap.key && is_chaplain_job(potential_chap.mind?.assigned_role)) if(chaplain_string) chaplain_string += ", " chaplain_string += "[potential_chap] ([potential_chap.key])" diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index b52bf07243f..67a7261c104 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -120,7 +120,7 @@ flavour_text = "Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile." important_info = "The base is rigged with explosives, DO NOT abandon it or let it fall into enemy hands!" outfit = /datum/outfit/lavaland_syndicate - assignedrole = "Lavaland Syndicate" + spawner_job_path = /datum/job/lavaland_syndicate /obj/effect/mob_spawn/human/lavaland_syndicate/special(mob/living/new_spawn) new_spawn.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index fc645e3158d..e75359d7536 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -492,7 +492,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) name = "Doctor Hilbert" mob_name = "Doctor Hilbert" mob_gender = "male" - assignedrole = null + spawner_job_path = /datum/job/ghost_role ghost_usable = FALSE oxy_damage = 500 mob_species = /datum/species/skeleton diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 34416d6f737..25f765b81d0 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -268,7 +268,7 @@ // the shuttle system doesn't know who these people are, but they // must be important, surely var/obj/item/card/id/ID = new(src) - var/datum/job/J = pick(SSjob.occupations) + var/datum/job/J = pick(SSjob.joinable_occupations) ID.registered_name = S.random_name(pick(MALE, FEMALE)) ID.assignment = J.title diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index c049371edea..5764c990e5f 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -215,8 +215,8 @@ /obj/structure/table/wood/bar/proc/is_barstaff(mob/living/user) . = FALSE if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.mind && H.mind.assigned_role == "Bartender") + var/mob/living/carbon/human/human_user = user + if(is_bartender_job(human_user.mind?.assigned_role)) return TRUE var/obj/item/card/id/ID = user.get_idcard(FALSE) diff --git a/code/modules/unit_tests/security_officer_distribution.dm b/code/modules/unit_tests/security_officer_distribution.dm index 0b2ad98b878..c5906feea6a 100644 --- a/code/modules/unit_tests/security_officer_distribution.dm +++ b/code/modules/unit_tests/security_officer_distribution.dm @@ -59,7 +59,7 @@ var/mob/living/carbon/human/new_character = allocate(/mob/living/carbon/human) new_character.mind_initialize() - new_character.mind.assigned_role = "Security Officer" + new_character.mind.set_assigned_role(SSjob.GetJobType(/datum/job/security_officer)) new_player.new_character = new_character new_player.mock_client = mock_client diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 8aed6dc52b3..78c125daed8 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -39,7 +39,7 @@ /obj/vehicle/sealed/car/clowncar/auto_assign_occupant_flags(mob/M) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.mind?.assigned_role == "Clown") //Ensures only clowns can drive the car. (Including more at once) + if(is_clown_job(H.mind?.assigned_role)) //Ensures only clowns can drive the car. (Including more at once) add_control_flags(H, VEHICLE_CONTROL_DRIVE) RegisterSignal(H, COMSIG_MOB_CLICKON, .proc/fire_cannon_at) M.log_message("has entered [src] as a possible driver", LOG_ATTACK) diff --git a/tgstation.dme b/tgstation.dme index cb93d1b161c..e19bda9ea86 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2372,6 +2372,7 @@ #include "code\modules\jobs\job_types\curator.dm" #include "code\modules\jobs\job_types\cyborg.dm" #include "code\modules\jobs\job_types\detective.dm" +#include "code\modules\jobs\job_types\free_golem.dm" #include "code\modules\jobs\job_types\geneticist.dm" #include "code\modules\jobs\job_types\head_of_personnel.dm" #include "code\modules\jobs\job_types\head_of_security.dm" @@ -2380,6 +2381,8 @@ #include "code\modules\jobs\job_types\medical_doctor.dm" #include "code\modules\jobs\job_types\mime.dm" #include "code\modules\jobs\job_types\paramedic.dm" +#include "code\modules\jobs\job_types\personal_ai.dm" +#include "code\modules\jobs\job_types\positronic_brain.dm" #include "code\modules\jobs\job_types\prisoner.dm" #include "code\modules\jobs\job_types\psychologist.dm" #include "code\modules\jobs\job_types\quartermaster.dm" @@ -2387,10 +2390,53 @@ #include "code\modules\jobs\job_types\roboticist.dm" #include "code\modules\jobs\job_types\scientist.dm" #include "code\modules\jobs\job_types\security_officer.dm" +#include "code\modules\jobs\job_types\servant_golem.dm" #include "code\modules\jobs\job_types\shaft_miner.dm" #include "code\modules\jobs\job_types\station_engineer.dm" +#include "code\modules\jobs\job_types\unassigned.dm" #include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" +#include "code\modules\jobs\job_types\antagonists\abductor_agent.dm" +#include "code\modules\jobs\job_types\antagonists\abductor_scientist.dm" +#include "code\modules\jobs\job_types\antagonists\abductor_solo.dm" +#include "code\modules\jobs\job_types\antagonists\clown_operative.dm" +#include "code\modules\jobs\job_types\antagonists\lone_operative.dm" +#include "code\modules\jobs\job_types\antagonists\morph.dm" +#include "code\modules\jobs\job_types\antagonists\nightmare.dm" +#include "code\modules\jobs\job_types\antagonists\nuclear_operative.dm" +#include "code\modules\jobs\job_types\antagonists\revenant.dm" +#include "code\modules\jobs\job_types\antagonists\sentient_disease.dm" +#include "code\modules\jobs\job_types\antagonists\slaughter_demon.dm" +#include "code\modules\jobs\job_types\antagonists\space_dragon.dm" +#include "code\modules\jobs\job_types\antagonists\space_ninja.dm" +#include "code\modules\jobs\job_types\antagonists\space_wizard.dm" +#include "code\modules\jobs\job_types\antagonists\wizard_apprentice.dm" +#include "code\modules\jobs\job_types\antagonists\xenomorph.dm" +#include "code\modules\jobs\job_types\ert\ert_generic.dm" +#include "code\modules\jobs\job_types\event\fugitive.dm" +#include "code\modules\jobs\job_types\event\santa.dm" +#include "code\modules\jobs\job_types\spawner\ancient_crew.dm" +#include "code\modules\jobs\job_types\spawner\ash_walker.dm" +#include "code\modules\jobs\job_types\spawner\beach_bum.dm" +#include "code\modules\jobs\job_types\spawner\escaped_prisoner.dm" +#include "code\modules\jobs\job_types\spawner\exile.dm" +#include "code\modules\jobs\job_types\spawner\fugitve_hunter.dm" +#include "code\modules\jobs\job_types\spawner\ghost_role.dm" +#include "code\modules\jobs\job_types\spawner\hermit.dm" +#include "code\modules\jobs\job_types\spawner\hotel_staff.dm" +#include "code\modules\jobs\job_types\spawner\lavaland_syndicate.dm" +#include "code\modules\jobs\job_types\spawner\lifebringer.dm" +#include "code\modules\jobs\job_types\spawner\maintenance_drone.dm" +#include "code\modules\jobs\job_types\spawner\skeleton.dm" +#include "code\modules\jobs\job_types\spawner\space_bar_patron.dm" +#include "code\modules\jobs\job_types\spawner\space_bartender.dm" +#include "code\modules\jobs\job_types\spawner\space_doctor.dm" +#include "code\modules\jobs\job_types\spawner\space_pirate.dm" +#include "code\modules\jobs\job_types\spawner\space_syndicate.dm" +#include "code\modules\jobs\job_types\spawner\spider.dm" +#include "code\modules\jobs\job_types\spawner\syndicate_cybersun.dm" +#include "code\modules\jobs\job_types\spawner\syndicate_cybersun_captain.dm" +#include "code\modules\jobs\job_types\spawner\zombie.dm" #include "code\modules\keybindings\bindings_atom.dm" #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm"