diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 600164cb3ce..e1c99b62507 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -509,7 +509,7 @@
A = A.loc
return A.loc
-
+/* - SKYRAT EDIT MOVAL - MOVED TO ALTTITLEPREFS
/proc/AnnounceArrival(mob/living/carbon/human/character, rank)
if(!SSticker.IsRoundInProgress() || QDELETED(character))
return
@@ -524,7 +524,7 @@
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
-
+*/
/proc/lavaland_equipment_pressure_check(turf/T)
. = FALSE
if(!istype(T))
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index c49e9dbad3a..c68ac7d7b0e 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -547,8 +547,12 @@ SUBSYSTEM_DEF(job)
if(living_mob.mind)
living_mob.mind.assigned_role = rank
+ //SKYRAT EDIT ADD - ALTERNATE JOB TITLES
+ var/display_rank = rank
+ if(M.client && M.client.prefs && M.client.prefs.alt_titles_preferences[rank])
+ display_rank = M.client.prefs.alt_titles_preferences[rank]
to_chat(M, "You are the [rank].")
- var/list/packed_items
+ var/list/packed_items //SKYRAT CHANGE ADDITION - CUSTOMIZATION
if(job)
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
if (M.client && job.no_dresscode && job.loadout)
@@ -570,7 +574,7 @@ SUBSYSTEM_DEF(job)
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.")
+ to_chat(M, "As the [display_rank] you answer directly to [job.supervisors]. Special circumstances may change this. Your role is that of a [rank]. Regardless of what your job title may be, please work to fulfil that role.") //SKYRAT EDIT - ALTERNATE JOB TITLES
job.radio_help_message(M)
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.")
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index e8717180d5f..39b0b2668dc 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -138,7 +138,7 @@
var/datum/data/record/foundrecord = find_record("name", name, GLOB.data_core.general)
if(foundrecord)
foundrecord.fields["rank"] = assignment
-
+/* SKYRAT EDIT MOVAL - OVERWRITTEN IN ALTJOBTITLES
/datum/datacore/proc/get_manifest()
var/list/manifest_out = list(
"Command",
@@ -194,6 +194,7 @@
if (!manifest_out[department])
manifest_out -= department
return manifest_out
+*/
/datum/datacore/proc/get_manifest_html(monochrome = FALSE)
var/list/manifest = get_manifest()
@@ -235,7 +236,12 @@
assignment = H.job
else
assignment = "Unassigned"
-
+ //SKYRAT EDIT ADD - ALTERNATE JOB TITLES
+ if(H.client && H.client.prefs && H.client.prefs.alt_titles_preferences[assignment]) // latejoin
+ assignment = H.client.prefs.alt_titles_preferences[assignment]
+ else if(C && C.prefs && C.prefs.alt_titles_preferences[assignment]) // roundstart - yes both do separate things i don't fucking know why but they do and if they're not both there then they don't fucking work leave me ALONE
+ assignment = C.prefs.alt_titles_preferences[assignment]
+ //SKYRAT EDIT ADD END
var/static/record_id_num = 1001
var/id = num2hex(record_id_num++,6)
if(!C)
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index d1862e9fcb4..30263186492 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -177,7 +177,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
if (id_card)
entry["name"] = id_card.registered_name
entry["assignment"] = id_card.assignment
- entry["ijob"] = jobs[id_card.assignment]
+ entry["ijob"] = jobs[id_card.real_title] //SKYRAT EDIT - ALTERNATE JOB TITLES, original = entry["ijob"] = jobs[id_card.assignment]
// Binary living/dead status
if (sensor_mode >= SENSOR_LIVING)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index fe6a80bb746..a4034ba5dba 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -172,6 +172,8 @@
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
+ get_alt_title_pref(preference_source) //SKYRAT EDIT ADD - gets alt titles for round start (yes this is fucking spaghetti it's not my fault you can't access a mob's client before their ID sets the job)
+
//Equip the rest of the gear
H.dna.species.before_equip_job(src, H, visualsOnly)
@@ -187,12 +189,12 @@
if(!visualsOnly && announce)
announce(H, is_captain)
-
+/* SKYRAT EDIT MOVAL - MOVED TO ALTTITLEPREFS
/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)
//timer because these should come after the captain announcement
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1))
-
+*/
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/job/proc/player_old_enough(client/C)
if(available_in_days(C) == 0)
@@ -284,6 +286,9 @@
C.registered_name = H.real_name
if(H.age)
C.registered_age = H.age
+ J.get_id_titles(H, C) // SKYRAT EDIT ADD - ALT TITLES
+ // C.assignment = J.title - SKYRAT EDIT - OVERWRITTEN IN ALT TITLES
+
C.update_label()
C.update_icon()
var/datum/bank_account/B = SSeconomy.bank_accounts_by_id["[H.account_id]"]
@@ -295,13 +300,13 @@
var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot)
if(istype(PDA))
PDA.owner = H.real_name
- PDA.ownjob = J.title
+ J.get_pda_titles(H, PDA) // SKYRAT EDIT ADD - ALT TITLES
+ // PDA.ownjob = J.title - SKYRAT EDIT - OVERWRITTEN IN ALT TITLES
PDA.update_label()
if(H.client?.prefs.playtime_reward_cloak)
neck = /obj/item/clothing/neck/cloak/skill_reward/playing
-
/datum/outfit/job/get_chameleon_disguise_info()
var/list/types = ..()
types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 06505ff7e76..124de1d7d26 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -102,6 +102,13 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
var/obj/item/card/id/worn_id = H.wear_id
SSid_access.apply_trim_to_card(worn_id, dep_trim)
H.sec_hud_set_ID()
+ //SKYRAT EDIT ADD - ALT TITLES
+ if(H.client && H.client.prefs && H.client.prefs.alt_titles_preferences[title])
+ worn_id.assignment = H.client.prefs.alt_titles_preferences[title]
+ worn_id.update_label()
+ else if (alt_title_pref)
+ worn_id.assignment = alt_title_pref
+ worn_id.update_label()
var/teleport = 0
if(!CONFIG_GET(flag/sec_start_brig))
diff --git a/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm b/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm
index 2afd6e36d2f..f0c93a8bd3c 100644
--- a/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm
+++ b/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm
@@ -452,10 +452,15 @@
var/command_bold = ""
if(job in GLOB.command_positions)
command_bold = " command"
+ var/jobline = "[job_datum.title] ([job_datum.current_positions])"
if(job_datum in SSjob.prioritized_jobs)
- dept_dat += "[job_datum.title] ([job_datum.current_positions])"
- else
- dept_dat += "[job_datum.title] ([job_datum.current_positions])"
+ jobline = "[jobline]"
+ if(client && client.prefs && client.prefs.alt_titles_preferences[job_datum.title])
+ jobline = "[jobline]
(as [client.prefs.alt_titles_preferences[job_datum.title]])"
+
+ jobline = "[jobline]"
+ dept_dat += jobline
+
if(!dept_dat.len)
dept_dat += "No positions open."
dat += jointext(dept_dat, "")
diff --git a/modular_skyrat/modules/altjobtitles/code/_job.dm b/modular_skyrat/modules/altjobtitles/code/_job.dm
new file mode 100644
index 00000000000..b4c04f4c71b
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/code/_job.dm
@@ -0,0 +1,161 @@
+/datum/job
+ var/alt_title_pref
+
+/datum/job/proc/get_alt_title_pref(client/preference_source)
+ if(preference_source && preference_source.prefs && preference_source.prefs.alt_titles_preferences[title])
+ alt_title_pref = preference_source.prefs.alt_titles_preferences[title]
+ else
+ alt_title_pref = title
+
+/datum/job/proc/get_id_titles(mob/living/carbon/human/H, obj/item/card/id/ID)
+ ID.real_title = title
+ if(H.client && H.client.prefs && H.client.prefs.alt_titles_preferences[title])
+ ID.assignment = H.client.prefs.alt_titles_preferences[title]
+ else if (alt_title_pref)
+ ID.assignment = alt_title_pref
+ else
+ ID.assignment = title
+
+/datum/job/proc/get_pda_titles(mob/living/carbon/human/H, obj/item/pda/PDA)
+ if(H.client && H.client.prefs && H.client.prefs.alt_titles_preferences[title])
+ PDA.ownjob = H.client.prefs.alt_titles_preferences[title]
+ else if (alt_title_pref)
+ PDA.ownjob = alt_title_pref
+ else
+ PDA.ownjob = title
+
+/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)
+ if(alt_title_pref)
+ //timer because these should come after the captain announcement
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, alt_title_pref, channels), 1))
+ else
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1))
+
+//Command
+/datum/job/captain
+ alt_titles = list("Station Commander", "Commanding Officer", "Site Manager")
+
+/datum/job/head_of_personnel
+ alt_titles = list("Executive Officer", "Employment Officer", "Crew Supervisor")
+
+/datum/job/head_of_security
+ alt_titles = list("Security Commander")
+
+/datum/job/chief_engineer
+ alt_titles = list("Engineering Foreman")
+
+/datum/job/research_director
+ alt_titles = list("Silicon Administrator", "Lead Researcher", "Biorobotics Director", "Research Supervisor")
+
+/datum/job/quartermaster
+ alt_titles = list("Deck Chief", "Cargo Foreman")
+
+/datum/job/chief_medical_officer
+ alt_titles = list("Medical Director")
+
+//Engineering
+/datum/job/station_engineer
+ alt_titles = list("Emergency Damage Control Technician", "Electrician", "Engine Technician", "EVA Technician")
+
+/datum/job/atmospheric_technician
+ alt_titles = list("Life Support Technician", "Emergency Fire Technician")
+
+//Medical
+/datum/job/doctor
+ alt_titles = list("Surgeon", "Nurse")
+
+/datum/job/paramedic
+ alt_titles = list("Emergency Medical Technician", "Search and Rescue Technician")
+
+/datum/job/virologist
+ alt_titles = list("Pathologist")
+
+/datum/job/chemist
+ alt_titles = list("Pharmacist", "Pharmacologist")
+
+//Science
+/datum/job/scientist
+ alt_titles = list("Circuitry Designer", "Xenobiologist", "Cytologist", "Nanomachine Programmer", "Plasma Researcher", "Anomalist", "Lab Technician")
+
+/datum/job/roboticist
+ alt_titles = list("Biomechanical Engineer", "Mechatronic Engineer")
+
+/datum/job/geneticist
+ alt_titles = list("Mutation Researcher")
+
+//Cargo
+/datum/job/cargo_technician
+ alt_titles = list("Deck Worker", "Mailman")
+
+/datum/job/shaft_miner
+ alt_titles = list("Excavator")
+
+//Service
+/datum/job/bartender
+ alt_titles = list("Mixologist")
+
+/datum/job/cook
+ alt_titles = list("Chef", "Butcher", "Culinary Artist", "Sous-Chef")
+
+/datum/job/janitor
+ alt_titles = list("Custodian", "Custodial Technicial", "Sanitation Technician")
+
+/datum/job/curator
+ alt_titles = list("Librarian", "Journalist", "Archivist")
+
+/datum/job/psychologist
+ alt_titles = list("Psychiatrist", "Therapist", "Counsellor")
+
+/datum/job/lawyer
+ alt_titles = list("Internal Affairs Agent", "Human Resources Agent")
+
+/datum/job/chaplain
+ alt_titles = list("Priest", "Preacher")
+
+/datum/job/mime
+ alt_titles = list("Pantomimist")
+
+/datum/job/clown
+ alt_titles = list("Jester")
+
+/datum/job/prisoner
+ alt_titles = list("Minimum Security Prisoner", "Maximum Security Prisoner", "SuperMax Security Prisoner", "Protective Custody Prisoner")
+
+/datum/job/assistant
+ alt_titles = list("Civilian", "Tourist", "Businessman", "Trader", "Entertainer", "Off-Duty Staff")
+
+/datum/job/botanist
+ alt_titles = list("Hydroponicist", "Gardener", "Botanical Researcher", "Herbalist")
+
+//Security
+/datum/job/warden
+ alt_titles = list("Brig Sergeant", "Dispatch Officer")
+
+/datum/job/detective
+ alt_titles = list("Forensic Technician", "Private Investigator", "Forensic Scientist")
+
+/datum/job/security_officer
+ alt_titles = list("Security Operative", "Peacekeeper")
+
+/datum/job/security_sergeant
+ alt_titles = list("Security Squad Leader", "Security Task Force Leader", "Security Fireteam Leader")
+
+/datum/job/security_medic
+ alt_titles = list("Field Medic", "Security Corpsman", "Brig Physician")
+
+/datum/job/junior_officer
+ alt_titles = list("Station Police", "Civil Protection Officer")
+
+/datum/job/brigoff
+ alt_titles = list("Brig Officer", "Prison Guard")
+
+/datum/job/blueshield
+ alt_titles = list("Command Bodyguard")
+
+//Silicon
+/datum/job/ai
+ alt_titles = list("Station Intelligence", "Automated Overseer")
+
+/datum/job/cyborg
+ alt_titles = list("Robot", "Android")
diff --git a/modular_skyrat/modules/altjobtitles/code/cards_ids.dm b/modular_skyrat/modules/altjobtitles/code/cards_ids.dm
new file mode 100644
index 00000000000..cb27fd5c6d9
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/code/cards_ids.dm
@@ -0,0 +1,2 @@
+/obj/item/card/id
+ var/real_title
diff --git a/modular_skyrat/modules/altjobtitles/code/datacore.dm b/modular_skyrat/modules/altjobtitles/code/datacore.dm
new file mode 100644
index 00000000000..ecff2a6f27d
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/code/datacore.dm
@@ -0,0 +1,55 @@
+/datum/datacore/proc/get_manifest()
+ var/list/manifest_out = list(
+ "Command",
+ "Security",
+ "Engineering",
+ "Medical",
+ "Science",
+ "Supply",
+ "Service",
+ "Silicon"
+ )
+ var/list/departments = list(
+ "Command" = GLOB.command_positions + GLOB.command_alttitles,
+ "Security" = GLOB.security_positions + GLOB.security_sub_positions + GLOB.security_alttitles,
+ "Engineering" = GLOB.engineering_positions + GLOB.engineering_alttitles,
+ "Medical" = GLOB.medical_positions + GLOB.medical_alttitles,
+ "Science" = GLOB.science_positions + GLOB.science_alttitles,
+ "Supply" = GLOB.supply_positions + GLOB.supply_alttitles,
+ "Service" = GLOB.service_positions + GLOB.service_alttitles,
+ "Silicon" = GLOB.nonhuman_positions + GLOB.nonhuman_alttitles
+ )
+ var/list/heads = GLOB.command_positions + list("Quartermaster")
+
+ for(var/datum/data/record/t in GLOB.data_core.general)
+ var/name = t.fields["name"]
+ var/rank = t.fields["rank"]
+ var/has_department = FALSE
+ for(var/department in departments)
+ var/list/jobs = departments[department]
+ if(rank in jobs)
+ if(!manifest_out[department])
+ manifest_out[department] = list()
+ // Append to beginning of list if captain or department head
+ if (rank == "Captain" || (department != "Command" && (rank in heads)))
+ manifest_out[department] = list(list(
+ "name" = name,
+ "rank" = rank
+ )) + manifest_out[department]
+ else
+ manifest_out[department] += list(list(
+ "name" = name,
+ "rank" = rank
+ ))
+ has_department = TRUE
+ if(!has_department)
+ if(!manifest_out["Misc"])
+ manifest_out["Misc"] = list()
+ manifest_out["Misc"] += list(list(
+ "name" = name,
+ "rank" = rank
+ ))
+ for (var/department in departments)
+ if (!manifest_out[department])
+ manifest_out -= department
+ return manifest_out
diff --git a/modular_skyrat/modules/altjobtitles/code/game.dm b/modular_skyrat/modules/altjobtitles/code/game.dm
new file mode 100644
index 00000000000..04af22d6de7
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/code/game.dm
@@ -0,0 +1,17 @@
+/proc/AnnounceArrival(mob/living/carbon/human/character, rank)
+ if(!SSticker.IsRoundInProgress() || QDELETED(character))
+ return
+ var/area/A = get_area(character)
+ deadchat_broadcast(" has arrived at the station at [A.name].", "[character.real_name] ([rank])", follow_target = character, message_type=DEADCHAT_ARRIVALRATTLE)
+ if(!character.mind)
+ return
+ if(!GLOB.announcement_systems.len)
+ return
+ if((character.mind.assigned_role == "Cyborg") || (character.mind.assigned_role == character.mind.special_role))
+ return
+
+ var/displayed_rank = rank
+ if(character.client && character.client.prefs && character.client.prefs.alt_titles_preferences[rank])
+ displayed_rank = character.client.prefs.alt_titles_preferences[rank]
+ var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
+ announcer.announce("ARRIVAL", character.real_name, displayed_rank, list()) //make the list empty to make it announce it in common
diff --git a/modular_skyrat/modules/altjobtitles/code/jobs.dm b/modular_skyrat/modules/altjobtitles/code/jobs.dm
new file mode 100644
index 00000000000..b1377d3cc03
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/code/jobs.dm
@@ -0,0 +1,66 @@
+GLOBAL_LIST_INIT(command_alttitles, list(
+ "Station Commander", "Commanding Officer", "Site Manager", //Captain
+ "Executive Officer", "Employment Officer", "Crew Supervisor", //HoP
+ "Security Commander", //HoS
+ "Engineering Foreman", //CE
+ "Silicon Administrator", "Lead Researcher", "Biorobotics Director", "Research Supervisor", //RD
+ "Deck Chief", "Cargo Foreman", //QM
+ "Medical Director")) //CMO
+
+
+GLOBAL_LIST_INIT(engineering_alttitles, list(
+ "Engineering Foreman", //CE
+ "Emergency Damage Control Technician", "Electrician", "Engine Technician", "EVA Technician", //Engie
+ "Life Support Technician", "Emergency Fire Technician")) //Atmos
+
+
+GLOBAL_LIST_INIT(medical_alttitles, list(
+ "Medical Director", //CMO
+ "Surgeon", "Nurse", //Doctor
+ "Emergency Medical Technician", "Search and Rescue Technician", //Paramed
+ "Pathologist", //Viro
+ "Pharmacist", "Pharmacologist")) //Chem
+
+
+GLOBAL_LIST_INIT(science_alttitles, list(
+ "Silicon Administrator", "Lead Researcher", "Biorobotics Director", "Research Supervisor", //RD
+ "Circuitry Designer", "Xenobiologist", "Cytologist", "Nanomachine Programmer", "Plasma Researcher", "Anomalist", "Lab Technician", //Sci
+ "Mutation Researcher", //Genetics
+ "Biomechanical Engineer", "Mechatronic Engineer")) //Robo
+
+
+GLOBAL_LIST_INIT(supply_alttitles, list(
+ "Deck Chief", //QM
+ "Deck Worker", "Mailman", //Cargo
+ "Excavator")) //Miner
+
+
+GLOBAL_LIST_INIT(service_alttitles, list(
+ "Executive Officer", "Employment Officer", "Crew Supervisor", //HoP
+ "Mixologist", //Bartender
+ "Hydroponicist", "Gardener", "Botanical Researcher", "Herbalist", //Botanist
+ "Chef", "Butcher", "Culinary Artist", "Sous-Chef", //Cook
+ "Custodian", "Custodial Technicial", "Sanitation Technician", //Janitor
+ "Librarian", "Journalist", "Archivist", //Curator
+ "Psychiatrist", "Therapist", "Counsellor", //Psych
+ "Internal Affairs Agent", "Human Resources Agent", //Lawyer
+ "Priest", "Preacher", //Chap
+ "Pantomimist", //Mime
+ "Jester", //Honkmaster Supreme
+ "Minimum Security Prisoner", "Maximum Security Prisoner", "SuperMax Security Prisoner", "Protective Custody Prisoner", //Prisoner
+ "Civilian", "Tourist", "Businessman", "Trader", "Entertainer", "Off-Duty Staff")) //Asistant
+
+GLOBAL_LIST_INIT(security_alttitles, list(
+ "Security Commander", //HoS
+ "Brig Sergeant", "Dispatch Officer", //Warden
+ "Forensic Technician", "Private Investigator", "Forensic Scientist", //Det
+ "Security Operative", "Peacekeeper", //Sec
+ "Field Medic", "Security Corpsman", "Brig Physician", //Secmed
+ "Security Squad Leader", "Security Task Force Leader", "Security Fireteam Leader", //Sarge
+ "Station Police", "Civil Protection Officer", //CDO
+ "Brig Officer", "Prison Guard", //Brigoff
+ "Command Bodyguard")) //Bluey
+
+GLOBAL_LIST_INIT(nonhuman_alttitles, list(
+ "Station Intelligence", "Automated Overseer", //AI
+ "Robot", "Android")) //Borg
diff --git a/modular_skyrat/modules/altjobtitles/readme.md b/modular_skyrat/modules/altjobtitles/readme.md
new file mode 100644
index 00000000000..c3c88b1e9db
--- /dev/null
+++ b/modular_skyrat/modules/altjobtitles/readme.md
@@ -0,0 +1,41 @@
+https://github.com/Skyrat-SS13/Skyrat-tg/pull/5150
+
+## Title: Alternative Job Titles
+
+MODULE ID: ALTJOBTITLES
+
+### Description:
+
+Ports alternative job titles from oldbase, making the necessary changes to make it actually work.
+
+### TG Proc Changes:
+
+- /proc/AnnounceArrival() - (code/_HELPERS/game.dm) - Moved to modular
+- /datum/controller/subsystem/job/proc/EquipRank() - (code/controllers/subsystem/job.dm)
+- /datum/datacore/proc/get_manifest() - (code/datums/datacore.dm) - Moved to modular
+- /datum/datacore/proc/manifest_inject() - (code/datums/datacore.dm)
+- /datum/crewmonitor/proc/update_data() - (code/game/machinery/computer/crew.dm)
+- /datum/job/proc/equip() - (code/modules/jobs/job_types/_job.dm)
+- /datum/outfit/job/post_equip() - (code/modules/jobs/job_types/_job.dm)
+- /datum/job/proc/announce_head() - (code/modules/jobs/job_types/_job.dm) - Moved to modular
+- /datum/job/security_officer/after_spawn() - (code/modules/jobs/job_types/security_officer.dm)
+
+### Defines:
+(i don't know if these count but)
+- Global lists for each department's alt title (command_altttles, security_alttitles etc.)
+
+### Master file additions
+
+- N/A
+
+### Edited files that are not contained in this module:
+
+- modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm - Updated latejoin job selection
+- modular_skyrat/modules/customization/modules/client/preferences.dm - Title selection
+- modular_skyrat/modules/customization/modules/client/preferences_savefile.dm - Saving of title selection
+
+### Credits:
+FlamingLily - Porting and Refactoring
+
+Azarak - OG code - https://github.com/Skyrat-SS13/Skyrat13/pull/1887
+
diff --git a/modular_skyrat/modules/customization/modules/client/preferences.dm b/modular_skyrat/modules/customization/modules/client/preferences.dm
index b33597e9d60..cdc0a49db6e 100644
--- a/modular_skyrat/modules/customization/modules/client/preferences.dm
+++ b/modular_skyrat/modules/customization/modules/client/preferences.dm
@@ -125,6 +125,8 @@ GLOBAL_LIST_INIT(food, list(
//Job preferences 2.0 - indexed by job title , no key or value implies never
var/list/job_preferences = list()
+ // Alternate Job Titles
+ var/list/alt_titles_preferences = list()
// Want randomjob if preferences already filled - Donkie
var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
@@ -1346,6 +1348,12 @@ GLOBAL_LIST_INIT(food, list(
HTML += "