From 50f372e053beaacec50c466bd868bca62236405a Mon Sep 17 00:00:00 2001
From: QuacksQ <79924768+QuacksQ@users.noreply.github.com>
Date: Sun, 6 Oct 2024 19:02:20 +0200
Subject: [PATCH] Job renames + Department security removal + Belryth jobslots
(#610)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## About The Pull Request
Cooler names cus FUCK TG!!!!
Also removes Department security because fuck that bullshit
Also adds proper job slots for Belryth instead of using the ones from
bearcat
------ Name changes below ------
Captain -> Shipmaster
Head of Personnel -> Executive Officer
Head of Security -> Colonel
Chief Engineer -> Lead Technician
Chief Medical Officer - Head Physician
Engineer -> Technician
Medical doctor -> Physician
Security officer -> Enforcer
Quartermaster -> Logistics Manager
Cargo Technician -> Logistics Technician
## How Does This Help ***Gameplay***?
🤷
## How Does This Help ***Roleplay***?
Cooler names are cooler :)
## Proof of Testing
Screenshots/Videos
![image-1](https://github.com/user-attachments/assets/e2ca835e-5373-4bf8-b38c-3c1e78e0d71c)
## Changelog
:cl:
code: Job renames cus why not
code: Belryth now has proper job slots
del: Removed Department security
/:cl:
---
code/__DEFINES/jobs.dm | 23 +-
code/controllers/subsystem/ticker.dm | 30 --
code/datums/id_trim/jobs.dm | 145 ++------
code/game/machinery/computer/crew.dm | 6 +-
.../client/preferences/security_department.dm | 21 --
.../jobs/job_types/security_officer.dm | 333 +-----------------
.../modules/map_content/alv_belryth_define.dm | 2 +-
.../map_specific_code/belryth/belryth_jobs.dm | 87 +++++
code/modules/unit_tests/_unit_tests.dm | 1 -
.../security_officer_distribution.dm | 110 ------
tgstation.dme | 2 +-
.../security_department.tsx | 6 -
12 files changed, 126 insertions(+), 640 deletions(-)
delete mode 100644 code/modules/client/preferences/security_department.dm
create mode 100644 code/modules/mapping/map_specific_code/belryth/belryth_jobs.dm
delete mode 100644 code/modules/unit_tests/security_officer_distribution.dm
delete mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx
diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm
index 549ade7601f..fe05a56a923 100644
--- a/code/__DEFINES/jobs.dm
+++ b/code/__DEFINES/jobs.dm
@@ -38,11 +38,11 @@
#define JOB_ASSISTANT "Assistant"
#define JOB_PRISONER "Prisoner"
//Command
-#define JOB_CAPTAIN "Captain"
-#define JOB_HEAD_OF_PERSONNEL "Head of Personnel"
-#define JOB_HEAD_OF_SECURITY "Head of Security"
-#define JOB_CHIEF_ENGINEER "Chief Engineer"
-#define JOB_CHIEF_MEDICAL_OFFICER "Chief Medical Officer"
+#define JOB_CAPTAIN "Shipmaster"
+#define JOB_HEAD_OF_PERSONNEL "Executive Officer"
+#define JOB_HEAD_OF_SECURITY "Colonel"
+#define JOB_CHIEF_ENGINEER "Lead Technician"
+#define JOB_CHIEF_MEDICAL_OFFICER "Head Physician"
#define JOB_PATHFINDER_LEAD "Lead Pathfinder"
#define JOB_INTERNAL_AFFAIRS_AGENT "Internal Affairs Agent"
//Silicon
@@ -53,23 +53,19 @@
#define JOB_WARDEN "Warden"
#define JOB_DETECTIVE "Detective"
#define JOB_SECURITY_OFFICER "Security Officer"
-#define JOB_SECURITY_OFFICER_MEDICAL "Security Officer (Medical)"
-#define JOB_SECURITY_OFFICER_ENGINEERING "Security Officer (Engineering)"
-#define JOB_SECURITY_OFFICER_SCIENCE "Security Officer (Science)"
-#define JOB_SECURITY_OFFICER_SUPPLY "Security Officer (Cargo)"
//Engineering
-#define JOB_STATION_ENGINEER "Station Engineer"
+#define JOB_STATION_ENGINEER "Technician"
#define JOB_ATMOSPHERIC_TECHNICIAN "Atmospheric Technician"
#define JOB_ROBOTICIST "Roboticist"
//Medical
-#define JOB_MEDICAL_DOCTOR "Medical Doctor"
+#define JOB_MEDICAL_DOCTOR "Physician"
#define JOB_PARAMEDIC "Paramedic"
#define JOB_CHEMIST "Chemist"
//Pathfinders
#define JOB_PATHFINDER "Pathfinder"
//Supply
-#define JOB_QUARTERMASTER "Quartermaster"
-#define JOB_CARGO_TECHNICIAN "Cargo Technician"
+#define JOB_QUARTERMASTER "Logistics Manager"
+#define JOB_CARGO_TECHNICIAN "Logistics Technician"
#define JOB_SHAFT_MINER "Shaft Miner"
//Service
#define JOB_BARTENDER "Bartender"
@@ -185,6 +181,7 @@
#define FACTION_NONE "None"
#define FACTION_STATION "Station"
#define FACTION_BEARCAT "Bearcat"
+#define FACTION_BELRYTH "Belryth"
/// Special define that's PURPOSEFULLY NOT USED ANYWHERE BUT IN JOB DATUMS TO TEMPORARILY DISABLE JOBS.
#define FACTION_DISABLED "do not use"
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 4975c528cd7..0610c26ffad 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -354,10 +354,6 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/equip_characters()
- GLOB.security_officer_distribution = decide_security_officer_departments(
- shuffle(GLOB.new_player_list),
- shuffle(GLOB.available_depts),
- )
var/captainless = TRUE
@@ -422,32 +418,6 @@ 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,
-)
- var/list/officer_mobs = list()
- var/list/officer_preferences = list()
-
- 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) && is_security_officer_job(character.mind?.assigned_role))
- officer_mobs += character
-
- var/datum/client_interface/client = GET_CLIENT(new_player_mob)
- var/preference = client?.prefs?.read_preference(/datum/preference/choiced/security_department)
- officer_preferences += preference
-
- var/distribution = get_officer_departments(officer_preferences, departments)
-
- var/list/output = list()
-
- for (var/index in 1 to officer_mobs.len)
- output[REF(officer_mobs[index])] = distribution[index]
-
- return output
-
/datum/controller/subsystem/ticker/proc/transfer_characters()
var/list/livings = list()
for(var/i in GLOB.new_player_list)
diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm
index f9b7cb734ae..abe0ad752a2 100644
--- a/code/datums/id_trim/jobs.dm
+++ b/code/datums/id_trim/jobs.dm
@@ -77,7 +77,7 @@
return TRUE
/datum/id_trim/job/assistant
- assignment = "Assistant"
+ assignment = JOB_ASSISTANT
orbit_icon = "toolbox"
sechud_icon_state = SECHUD_ASSISTANT
minimal_access = list()
@@ -103,7 +103,7 @@
ACCESS_MAINT_TUNNELS)
/datum/id_trim/job/bartender
- assignment = "Bartender"
+ assignment = JOB_BARTENDER
trim_state = "dept-service"
orbit_icon = "cocktail"
department_color = COLOR_SERVICE_LIME
@@ -128,7 +128,7 @@
job = /datum/job/bartender
/datum/id_trim/job/botanist
- assignment = "Botanist"
+ assignment = JOB_BOTANIST
trim_state = "dept-service"
orbit_icon = "seedling"
department_color = COLOR_SERVICE_LIME
@@ -176,7 +176,7 @@
return ..()
/datum/id_trim/job/cargo_technician
- assignment = "Cargo Technician"
+ assignment = JOB_CARGO_TECHNICIAN
trim_state = "dept-cargo"
orbit_icon = "box"
department_color = COLOR_CARGO_BROWN
@@ -201,7 +201,7 @@
job = /datum/job/cargo_technician
/datum/id_trim/job/chaplain
- assignment = "Chaplain"
+ assignment = JOB_CHAPLAIN
trim_state = "dept-service"
orbit_icon = "cross"
department_color = COLOR_SERVICE_LIME
@@ -223,7 +223,7 @@
job = /datum/job/chaplain
/datum/id_trim/job/chemist
- assignment = "Chemist"
+ assignment = JOB_CHEMIST
trim_state = "dept-medical"
orbit_icon = "prescription-bottle"
department_color = COLOR_MEDICAL_BLUE
@@ -248,7 +248,7 @@
job = /datum/job/chemist
/datum/id_trim/job/chief_engineer
- assignment = "Chief Engineer"
+ assignment = JOB_CHIEF_ENGINEER
intern_alt_name = "Chief Engineer-in-Training"
trim_state = "dept-engineering"
orbit_icon = "user-astronaut"
@@ -292,7 +292,7 @@
job = /datum/job/chief_engineer
/datum/id_trim/job/chief_medical_officer
- assignment = "Chief Medical Officer"
+ assignment = JOB_CHIEF_MEDICAL_OFFICER
intern_alt_name = "Chief Medical Officer-in-Training"
trim_state = "dept-medical"
orbit_icon = "user-md"
@@ -331,7 +331,7 @@
job = /datum/job/chief_medical_officer
/datum/id_trim/job/clown
- assignment = "Clown"
+ assignment = JOB_CLOWN
trim_state = "dept-clown"
orbit_icon = "face-grin-tears"
department_color = COLOR_MOSTLY_PURE_PINK
@@ -350,7 +350,7 @@
job = /datum/job/clown
/datum/id_trim/job/cook
- assignment = "Cook"
+ assignment = JOB_COOK
trim_state = "dept-service"
orbit_icon = "utensils"
department_color = COLOR_SERVICE_LIME
@@ -378,7 +378,7 @@
sechud_icon_state = SECHUD_CHEF
/datum/id_trim/job/curator
- assignment = "Curator"
+ assignment = JOB_CURATOR
trim_state = "dept-service"
orbit_icon = "book"
department_color = COLOR_SERVICE_LIME
@@ -399,7 +399,7 @@
job = /datum/job/curator
/datum/id_trim/job/detective
- assignment = "Detective"
+ assignment = JOB_DETECTIVE
trim_state = "dept-security"
orbit_icon = "user-secret"
department_color = COLOR_SECURITY_RED
@@ -437,7 +437,7 @@
access |= list(ACCESS_MAINT_TUNNELS)
/datum/id_trim/job/head_of_personnel
- assignment = "Head of Personnel"
+ assignment = JOB_HEAD_OF_PERSONNEL
intern_alt_name = "Head of Personnel-in-Training"
trim_state = "dept-hop"
orbit_icon = "dog"
@@ -487,7 +487,7 @@
job = /datum/job/head_of_personnel
/datum/id_trim/job/head_of_security
- assignment = "Head of Security"
+ assignment = JOB_HEAD_OF_SECURITY
intern_alt_name = "Head of Security-in-Training"
trim_state = "dept-security"
orbit_icon = "user-shield"
@@ -545,7 +545,7 @@
access |= list(ACCESS_MAINT_TUNNELS)
/datum/id_trim/job/internal_affairs_agent
- assignment = "Internal Affairs Agent"
+ assignment = JOB_INTERNAL_AFFAIRS_AGENT
trim_state = "dept-internal-affairs"
orbit_icon = "print"
department_color = COLOR_COMMAND_BLUE
@@ -565,7 +565,7 @@
job = /datum/job/internal_affairs_agent
/datum/id_trim/job/janitor
- assignment = "Janitor"
+ assignment = JOB_JANITOR
trim_state = "dept-service"
orbit_icon = "broom"
department_color = COLOR_SERVICE_LIME
@@ -586,7 +586,7 @@
job = /datum/job/janitor
/datum/id_trim/job/medical_doctor
- assignment = "Medical Doctor"
+ assignment = JOB_MEDICAL_DOCTOR
trim_state = "dept-medical"
orbit_icon = "staff-snake"
department_color = COLOR_MEDICAL_BLUE
@@ -612,7 +612,7 @@
job = /datum/job/doctor
/datum/id_trim/job/mime
- assignment = "Mime"
+ assignment = JOB_MIME
trim_state = "dept-service"
orbit_icon = "comment-slash"
department_color = COLOR_SILVER
@@ -631,7 +631,7 @@
job = /datum/job/mime
/datum/id_trim/job/paramedic
- assignment = "Paramedic"
+ assignment = JOB_PARAMEDIC
trim_state = "dept-medical"
orbit_icon = "truck-medical"
department_color = COLOR_MEDICAL_BLUE
@@ -662,7 +662,7 @@
job = /datum/job/paramedic
/datum/id_trim/job/prisoner
- assignment = "Prisoner"
+ assignment = JOB_PRISONER
trim_state = "dept-prisoner"
orbit_icon = "lock"
department_color = COLOR_PRISONER_BLACK
@@ -698,7 +698,7 @@
template_access = null
/datum/id_trim/job/quartermaster
- assignment = "Quartermaster"
+ assignment = JOB_QUARTERMASTER
trim_state = "dept-cargo"
orbit_icon = "sack-dollar"
department_color = COLOR_COMMAND_BLUE
@@ -733,7 +733,7 @@
job = /datum/job/quartermaster
/datum/id_trim/job/roboticist
- assignment = "Roboticist"
+ assignment = JOB_ROBOTICIST
trim_state = "dept-engineering"
orbit_icon = "battery-half"
department_color = COLOR_ENGINEERING_ORANGE
@@ -759,7 +759,7 @@
/// Sec officers have departmental variants. They each have their own trims with bonus departmental accesses.
/datum/id_trim/job/security_officer
- assignment = "Security Officer"
+ assignment = JOB_SECURITY_OFFICER
trim_state = "dept-security"
orbit_icon = "shield-halved"
department_color = COLOR_SECURITY_RED
@@ -785,101 +785,9 @@
ACCESS_HOS,
)
job = /datum/job/security_officer
- /// List of bonus departmental accesses that departmental sec officers get by default.
- var/department_access = list()
- /// List of bonus departmental accesses that departmental security officers can in relation to how many overall security officers there are if the scaling system is set up. These can otherwise be granted via config settings.
- var/elevated_access = list()
-
-/datum/id_trim/job/security_officer/refresh_trim_access()
- . = ..()
-
- if(!.)
- return
-
- access |= department_access
-
- // Config check for if sec has maint access.
- if(CONFIG_GET(flag/security_has_maint_access))
- access |= list(ACCESS_MAINT_TUNNELS)
-
- // Scaling access (POPULATION_SCALED_ACCESS) is a system directly tied into calculations derived via a config entered variable, as well as the amount of players in the shift.
- // Thus, it makes it possible to judge if departmental security officers should have more access to their department on a lower population shift.
- // Server operators can modify config to change it such that security officers can use this system, or alternatively either: A) always give the "elevated" access (ALWAYS_GETS_ACCESS) or B) never give this access (null value).
-
- #define POPULATION_SCALED_ACCESS 1
- #define ALWAYS_GETS_ACCESS 2
-
- // If null, then the departmental security officer will not get any elevated access.
- if(!CONFIG_GET(number/depsec_access_level))
- return
-
- if(CONFIG_GET(number/depsec_access_level) == POPULATION_SCALED_ACCESS)
- var/minimal_security_officers = 3 // We do not spawn in any more lockers if there are 5 or less security officers, so let's keep it lower than that number.
- var/datum/job/J = SSjob.GetJob(JOB_SECURITY_OFFICER)
- if((J.spawn_positions - minimal_security_officers) <= 0)
- access |= elevated_access
-
- if(CONFIG_GET(number/depsec_access_level) == ALWAYS_GETS_ACCESS)
- access |= elevated_access
-
-/datum/id_trim/job/security_officer/supply
- assignment = "Security Officer (Cargo)"
- subdepartment_color = COLOR_CARGO_BROWN
- department_access = list(
- ACCESS_CARGO,
- ACCESS_MINING,
- ACCESS_SHIPPING,
- )
- elevated_access = list(
- ACCESS_AUX_BASE,
- ACCESS_MINING_STATION,
- )
-
-/datum/id_trim/job/security_officer/engineering
- assignment = "Security Officer (Engineering)"
- subdepartment_color = COLOR_ENGINEERING_ORANGE
- department_access = list(
- ACCESS_ATMOSPHERICS,
- ACCESS_ENGINEERING,
- )
- elevated_access = list(
- ACCESS_AUX_BASE,
- ACCESS_CONSTRUCTION,
- ACCESS_ENGINE_EQUIP,
- ACCESS_TCOMMS,
- )
-
-/datum/id_trim/job/security_officer/medical
- assignment = "Security Officer (Medical)"
- subdepartment_color = COLOR_MEDICAL_BLUE
- department_access = list(
- ACCESS_MEDICAL,
- ACCESS_MORGUE,
- )
- elevated_access = list(
- ACCESS_PHARMACY,
- ACCESS_SURGERY,
- ACCESS_VIROLOGY,
- )
-
-/datum/id_trim/job/security_officer/science
- assignment = "Security Officer (Science)"
- subdepartment_color = COLOR_SCIENCE_PINK
- department_access = list(
- ACCESS_RESEARCH,
- ACCESS_SCIENCE,
- )
- elevated_access = list(
- ACCESS_AUX_BASE,
- ACCESS_GENETICS,
- ACCESS_ORDNANCE_STORAGE,
- ACCESS_ORDNANCE,
- ACCESS_ROBOTICS,
- ACCESS_XENOBIOLOGY,
- )
/datum/id_trim/job/station_engineer
- assignment = "Station Engineer"
+ assignment = JOB_STATION_ENGINEER
trim_state = "dept-engineering"
orbit_icon = "gears"
department_color = COLOR_ENGINEERING_ORANGE
@@ -907,7 +815,7 @@
job = /datum/job/station_engineer
/datum/id_trim/job/warden
- assignment = "Warden"
+ assignment = JOB_WARDEN
trim_state = "dept-security"
orbit_icon = "handcuffs"
department_color = COLOR_SECURITY_RED
@@ -944,6 +852,3 @@
// Config check for if sec has maint access.
if(CONFIG_GET(flag/security_has_maint_access))
access |= list(ACCESS_MAINT_TUNNELS)
-
-#undef POPULATION_SCALED_ACCESS
-#undef ALWAYS_GETS_ACCESS
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index 1dcd03c93b1..bcffab3be33 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -101,11 +101,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
JOB_HEAD_OF_SECURITY = 10,
JOB_WARDEN = 11,
JOB_SECURITY_OFFICER = 12,
- JOB_SECURITY_OFFICER_MEDICAL = 13,
- JOB_SECURITY_OFFICER_ENGINEERING = 14,
- JOB_SECURITY_OFFICER_SCIENCE = 15,
- JOB_SECURITY_OFFICER_SUPPLY = 16,
- JOB_DETECTIVE = 17,
+ JOB_DETECTIVE = 13,
// 20-29: Medbay
JOB_CHIEF_MEDICAL_OFFICER = 20,
JOB_CHEMIST = 21,
diff --git a/code/modules/client/preferences/security_department.dm b/code/modules/client/preferences/security_department.dm
deleted file mode 100644
index ea122f0c521..00000000000
--- a/code/modules/client/preferences/security_department.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-/// Which department to put security officers in, when the config is enabled
-/datum/preference/choiced/security_department
- category = PREFERENCE_CATEGORY_MISC_LIST
- can_randomize = FALSE
- savefile_identifier = PREFERENCE_CHARACTER
- savefile_key = "prefered_security_department"
-
-/datum/preference/choiced/security_department/init_possible_values()
- return GLOB.security_depts_prefs
-
-/datum/preference/choiced/security_department/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
- return
-
-/datum/preference/choiced/security_department/create_default_value()
- return SEC_DEPT_NONE
-
-/datum/preference/choiced/security_department/is_accessible(datum/preferences/preferences)
- if (!..(preferences))
- return FALSE
-
- return !CONFIG_GET(flag/sec_start_brig)
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 8967884226c..961df401c43 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -7,7 +7,7 @@
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)"
+ supervisors = "the Colonel"
selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 300
@@ -41,106 +41,6 @@
rpg_title = "Guard"
job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE | JOB_REOPEN_ON_ROUNDSTART_LOSS | JOB_ASSIGN_QUIRKS | JOB_CAN_BE_INTERN
-
-GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
-
-/**
- * The department distribution of the security officers.
- *
- * Keys are refs of the security officer mobs. This is to preserve the list's structure even if the
- * mob gets deleted. This is also safe, as mobs are guaranteed to have a unique ref, as per /mob/GenerateTag().
- */
-GLOBAL_LIST_EMPTY(security_officer_distribution)
-
-
-/datum/job/security_officer/after_roundstart_spawn(mob/living/spawning, client/player_client)
- . = ..()
- if(ishuman(spawning))
- setup_department(spawning, player_client)
-
-
-/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)
-
-
-/// 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?.read_preference(/datum/preference/choiced/security_department)
- if (!isnull(department))
- department = get_my_department(spawning, 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
-
- switch(department)
- if(SEC_DEPT_SUPPLY)
- ears = /obj/item/radio/headset/headset_sec/alt/department/supply
- dep_trim = /datum/id_trim/job/security_officer/supply
- destination = /area/station/security/checkpoint/supply
- accessory = /obj/item/clothing/accessory/armband/cargo
- if(SEC_DEPT_ENGINEERING)
- ears = /obj/item/radio/headset/headset_sec/alt/department/engi
- dep_trim = /datum/id_trim/job/security_officer/engineering
- destination = /area/station/security/checkpoint/engineering
- accessory = /obj/item/clothing/accessory/armband/engine
- if(SEC_DEPT_MEDICAL)
- ears = /obj/item/radio/headset/headset_sec/alt/department/med
- dep_trim = /datum/id_trim/job/security_officer/medical
- destination = /area/station/security/checkpoint/medical
- accessory = /obj/item/clothing/accessory/armband/medblue
- if(SEC_DEPT_SCIENCE)
- ears = /obj/item/radio/headset/headset_sec/alt/department/sci
- dep_trim = /datum/id_trim/job/security_officer/science
- destination = /area/station/security/checkpoint/science
- accessory = /obj/item/clothing/accessory/armband/science
-
- if(accessory)
- var/obj/item/clothing/under/worn_under = spawning.w_uniform
- worn_under.attach_accessory(new accessory)
-
- if(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 = spawning.get_idcard(hand_first = FALSE)
- SSid_access.apply_trim_to_card(worn_id, dep_trim)
- spawning.sec_hud_set_ID()
-
- var/spawn_point = pick(LAZYACCESS(GLOB.department_security_spawns, department))
-
- if(!CONFIG_GET(flag/sec_start_brig) && (destination || spawn_point))
- if(spawn_point)
- spawning.Move(get_turf(spawn_point))
- else
- var/list/possible_turfs = get_area_turfs(destination)
- while (length(possible_turfs))
- var/random_index = rand(1, length(possible_turfs))
- var/turf/target = possible_turfs[random_index]
- if (spawning.Move(target))
- break
- 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,
department,
@@ -181,19 +81,6 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
signal.send_to_receivers()
-/datum/job/security_officer/proc/get_my_department(mob/character, preferred_department)
- var/department = GLOB.security_officer_distribution[REF(character)]
-
- // This passes when they are a round start security officer.
- if (department)
- return department
-
- return get_new_officer_distribution_from_late_join(
- preferred_department,
- shuffle(GLOB.available_depts),
- GLOB.security_officer_distribution,
- )
-
/datum/outfit/job/security
name = "Security Officer"
jobtype = /datum/job/security_officer
@@ -265,221 +152,3 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
/obj/item/radio/headset/headset_sec/alt/department/sci
keyslot = new /obj/item/encryptionkey/headset_sec
keyslot2 = new /obj/item/encryptionkey/headset_sci
-
-/// Returns the distribution of splitting the given security officers into departments.
-/// Return value is an assoc list of candidate => SEC_DEPT_*.
-/proc/get_officer_departments(list/preferences, list/departments)
- if (!preferences.len)
- return list()
-
- /**
- * This is a pretty complicated algorithm, but it's one I'm rather proud of.
- *
- * This is the function that is responsible for taking the list of preferences,
- * and spitting out what to put them in.
- *
- * However, it should, wherever possible, prevent solo departments.
- * That means that if there's one medical officer, and one engineering officer,
- * that they should be put onto the same department (either medical or engineering).
- *
- * The first step is to get the "distribution". This describes how many officers
- * should be in each department, no matter what they are.
- * This is handled in `get_distribution`. Examples of inputs/outputs are:
- * get_distribution(1, 4) => [1]
- * get_distribution(2, 4) => [2]
- * get_distribution(3, 4) => [3] # If this returned [2, 1], then we'd get a loner.
- * get_distribution(4, 4) => [2, 2] # We have enough to put into a separate group
- *
- * Once this distribution is received, the next step is to figure out where to put everyone.
- *
- * If all members have no preference, just make one an unused department (from the departments argument).
- * Then, call ourselves again.
- *
- * Order the groups from most populated to least.
- *
- * If the top group has enough officers who actually *want* that department, then we give it to them.
- * If there are any leftovers (for example, if 3 officers want medical, but we only want 2), then we
- * update those to have no preference instead.
- *
- * If the top group does NOT have enough officers, then we kill the least popular group by setting
- * them all to have no preference.
- *
- * Anyone in the most popular group will be removed from the list, and the final tally will be updated.
- * In the case of not having enough officers, this is a no-op, as there won't be any in the most popular group yet.
- *
- * If there are any candidates left, then we call the algorithm again, but for everyone who hasn't been selected yet.
- * We take the results from that run, and put them in the correct order.
- *
- * As an example, let's assume we have the following preferences:
- * [engineer, medical, medical, medical, medical, cargo]
- *
- * The distribution of this is [2, 2, 2], meaning there will be 3 departments chosen and they will have 2 each.
- * We order from most popular to least popular and get:
- * - medical: 4
- * - engineer: 1
- * - cargo: 1
- *
- * We need 2 to fill the first group. There are enough medical staff to do it. Thus, we take the first 2 medical staff
- * and update the output, making it now: [engineer, medical, medical, ?, ?, cargo].
- *
- * The remaining two want-to-be-medical officers are now updated to act as no preference. We run the algorithm again.
- * This time, are candidates are [engineer, none, none, cargo].
- * The distribution of this is [2, 2]. The frequency is:
- * - engineer: 1
- * - cargo: 1
- * - no preference: 2
- *
- * We need 2 to fill the engineering group, but only have one who wants to do it.
- * We have enough no preferences for it, making our result: [engineer, engineer, none, cargo].
- * We run the algorithm again, but this time with: [none, cargo].
- * Frequency is:
- * - cargo: 1
- * - no preference: 1
- * Enough to fill cargo, etc, and we get [cargo, cargo].
- *
- * These are all then compounded into one list.
- *
- * In the case that all are no preference, it will pop the last department, and use that.
- * For example, if `departments` is [engi, medical, cargo], and we have the preferences:
- * [none, none, none]...
- * Then we will just give them all cargo.
- *
- * One of the most important parts of this algorithm is IT IS DETERMINISTIC.
- * That means that this proc is 100% testable.
- * Instead, to get random results, the preferences and departments are shuffled
- * before the proc is ever called.
- */
-
- preferences = preferences.Copy()
- departments = departments.Copy()
-
- var/distribution = get_distribution(preferences.len, departments.len)
- var/selection[preferences.len]
-
- var/list/grouped = list()
- var/list/biggest_group
- var/biggest_preference
- var/list/indices = list()
-
- for (var/index in 1 to preferences.len)
- indices += index
-
- var/preference = preferences[index]
- if (!(preference in grouped))
- grouped[preference] = list()
- grouped[preference] += index
-
- var/list/preferred_group = grouped[preference]
-
- if (preference != SEC_DEPT_NONE && (isnull(biggest_group) || biggest_group.len < preferred_group.len))
- biggest_group = grouped[preference]
- biggest_preference = preference
-
- if (isnull(biggest_group))
- preferences[1] = pop(departments)
- return get_officer_departments(preferences, departments)
-
- if (biggest_group.len >= distribution[1])
- for (var/index in 1 to distribution[1])
- selection[biggest_group[index]] = biggest_preference
-
- if (biggest_group.len > distribution[1])
- for (var/leftover in (distribution[1] + 1) to biggest_group.len)
- preferences[leftover] = SEC_DEPT_NONE
- else
- var/needed = distribution[1] - biggest_group.len
- if (LAZYLEN(LAZYACCESS(grouped, SEC_DEPT_NONE)) >= needed)
- for (var/candidate_index in biggest_group)
- selection[candidate_index] = biggest_preference
-
- for (var/index in 1 to needed)
- selection[grouped[SEC_DEPT_NONE][index]] = biggest_preference
- else
- var/least_popular_index = grouped[grouped.len]
- if (least_popular_index == SEC_DEPT_NONE)
- least_popular_index = grouped[grouped.len - 1]
- var/least_popular = grouped[least_popular_index]
- for (var/candidate_index in least_popular)
- preferences[candidate_index] = SEC_DEPT_NONE
-
- // Remove all members of the most popular candidate from the list
- for (var/chosen in 1 to selection.len)
- if (selection[chosen] == biggest_preference)
- indices -= chosen
- preferences[chosen] = null
-
- list_clear_nulls(preferences)
-
- departments -= biggest_preference
-
- if (grouped.len != 1)
- var/list/next_step = get_officer_departments(preferences, departments)
- for (var/index in 1 to indices.len)
- var/place = indices[index]
- selection[place] = next_step[index]
-
- return selection
-
-/proc/get_distribution(candidates, departments)
- var/number_of_twos = min(departments, round(candidates / 2))
- var/redistribute = candidates - (2 * number_of_twos)
-
- var/distribution[max(1, number_of_twos)]
-
- for (var/index in 1 to number_of_twos)
- distribution[index] = 2
-
- for (var/index in 0 to redistribute - 1)
- distribution[(index % departments) + 1] += 1
-
- return distribution
-
-/proc/get_new_officer_distribution_from_late_join(
- preference,
- list/departments,
- list/distribution,
-)
- /**
- * For late joiners, we're forced to put them in an alone department at some point.
- *
- * This is because reusing the round-start algorithm would force existing officers into
- * a different department in order to preserve having partners at all times.
- *
- * This would mean retroactively updating their access as well, which is too much
- * of a headache for me to want to bother.
- *
- * So, here's the method. If any department currently has 1 officer, they are forced into
- * that.
- *
- * Otherwise, the department with the least officers in it is chosen.
- * Preference takes priority, meaning that if both medical and engineering have zero officers,
- * and the preference is medical, then medical is what will be chosen.
- *
- * Just like `get_officer_departments`, this function is deterministic.
- * Randomness should instead be handled in the shuffling of the `departments` argument.
- */
- var/list/amount_in_departments = list()
-
- for (var/department in departments)
- amount_in_departments[department] = 0
-
- for (var/officer in distribution)
- var/department = distribution[officer]
- if (!isnull(department))
- amount_in_departments[department] += 1
-
- var/list/lowest_departments = list(departments[1])
- var/lowest_amount = INFINITY
-
- for (var/department in amount_in_departments)
- var/amount = amount_in_departments[department]
-
- if (amount == 1)
- return department
- else if (lowest_amount > amount)
- lowest_departments = list(department)
- lowest_amount = amount
- else if (lowest_amount == amount)
- lowest_departments += department
-
- return (preference in lowest_departments) ? preference : lowest_departments[1]
diff --git a/code/modules/map_content/alv_belryth_define.dm b/code/modules/map_content/alv_belryth_define.dm
index 772e36affc7..d030f07f94e 100644
--- a/code/modules/map_content/alv_belryth_define.dm
+++ b/code/modules/map_content/alv_belryth_define.dm
@@ -20,7 +20,7 @@
)
//central_trading_hub_type = /datum/trade_hub/randomname/large
overmap_object_type = /datum/overmap_object/shuttle/ship/alv_belryth
- job_faction = FACTION_BEARCAT
+ job_faction = FACTION_BELRYTH
job_changes = list()
overflow_job = /datum/job/assistant/bearcat
shuttles = list(
diff --git a/code/modules/mapping/map_specific_code/belryth/belryth_jobs.dm b/code/modules/mapping/map_specific_code/belryth/belryth_jobs.dm
new file mode 100644
index 00000000000..745c4329549
--- /dev/null
+++ b/code/modules/mapping/map_specific_code/belryth/belryth_jobs.dm
@@ -0,0 +1,87 @@
+/datum/job/captain/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/head_of_personnel/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/chief_engineer/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/lead_pathfinder/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/pathfinder/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 2
+ spawn_positions = 2
+
+/datum/job/quartermaster/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/head_of_security/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/internal_affairs_agent/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 2
+ spawn_positions = 2
+
+/datum/job/chief_medical_officer/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/station_engineer/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 3
+ spawn_positions = 3
+
+/datum/job/cargo_technician/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 2
+ spawn_positions = 2
+
+/datum/job/security_officer/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 4
+ spawn_positions = 4
+
+/datum/job/doctor/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 3
+ spawn_positions = 3
+
+/datum/job/cook/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/botanist/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/janitor/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/bartender/belryth
+ faction = FACTION_BELRYTH
+ total_positions = 1
+ spawn_positions = 1
+
+/datum/job/assistant/belryth
+ faction = FACTION_BELRYTH
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 9bf1dc2b23e..74e9777e599 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -154,7 +154,6 @@
#include "screenshot_humanoids.dm"
#include "screenshot_saturnx.dm"
#include "security_levels.dm"
-#include "security_officer_distribution.dm"
#include "serving_tray.dm"
#include "siunit.dm"
#include "slips.dm"
diff --git a/code/modules/unit_tests/security_officer_distribution.dm b/code/modules/unit_tests/security_officer_distribution.dm
deleted file mode 100644
index 67f02282b03..00000000000
--- a/code/modules/unit_tests/security_officer_distribution.dm
+++ /dev/null
@@ -1,110 +0,0 @@
-#define SECURITY_OFFICER_DEPARTMENTS list("a", "b", "c", "d")
-#define SECURITY_OFFICER_DEPARTMENTS_TO_NAMES (list( \
- "a" = SEC_DEPT_ENGINEERING, \
- "b" = SEC_DEPT_MEDICAL, \
- "c" = SEC_DEPT_SCIENCE, \
- "d" = SEC_DEPT_SUPPLY, \
-))
-
-/// Test that security officers with specific distributions get their departments.
-/datum/unit_test/security_officer_roundstart_distribution
-
-/datum/unit_test/security_officer_roundstart_distribution/proc/test(
- list/preferences,
- list/expected,
-)
- var/list/outcome = get_officer_departments(preferences, SECURITY_OFFICER_DEPARTMENTS)
- var/failure_message = "Tested with [json_encode(preferences)] and expected [json_encode(expected)], got [json_encode(outcome)]"
-
- if (outcome.len == expected.len)
- for (var/index in 1 to outcome.len)
- TEST_ASSERT_EQUAL(outcome[index], expected[index], failure_message)
- else
- TEST_FAIL(failure_message)
-
-/datum/unit_test/security_officer_roundstart_distribution/Run()
- test_distributions()
- test_with_mock_players()
-
-/datum/unit_test/security_officer_roundstart_distribution/proc/test_distributions()
- test(list("a"), list("a"))
- test(list("a", "b"), list("a", "a"))
- test(list("a", "b", "c"), list("a", "a", "a"))
- test(list("a", "a", "b"), list("a", "a", "a"))
- test(list("a", "a", "b", "b"), list("a", "a", "b", "b"))
- test(list("a", "a", "a", "b"), list("a", "a", "b", "b"))
- test(list("a", "b", "c", "d"), list("a", "b", "b", "a"))
- test(list(SEC_DEPT_NONE), list("d"))
- test(list("a", SEC_DEPT_NONE), list("a", "a"))
- test(list(SEC_DEPT_NONE, SEC_DEPT_NONE, SEC_DEPT_NONE, SEC_DEPT_NONE), list("d", "d", "c", "c"))
-
-/datum/unit_test/security_officer_roundstart_distribution/proc/test_with_mock_players()
- var/mob/dead/new_player/officer_a = create_officer("a")
- var/mob/dead/new_player/officer_b = create_officer("b")
- var/mob/dead/new_player/officer_c = create_officer("c")
- var/mob/dead/new_player/officer_d = create_officer("d")
-
- var/list/outcome = SSticker.decide_security_officer_departments(
- list(officer_a, officer_b, officer_c, officer_d),
- SECURITY_OFFICER_DEPARTMENTS,
- )
-
- TEST_ASSERT_EQUAL(outcome[REF(officer_a.new_character)], SECURITY_OFFICER_DEPARTMENTS_TO_NAMES["a"], "Officer A's department outcome was incorrect.")
- TEST_ASSERT_EQUAL(outcome[REF(officer_b.new_character)], SECURITY_OFFICER_DEPARTMENTS_TO_NAMES["b"], "Officer B's department outcome was incorrect.")
- TEST_ASSERT_EQUAL(outcome[REF(officer_c.new_character)], SECURITY_OFFICER_DEPARTMENTS_TO_NAMES["b"], "Officer C's department outcome was incorrect.")
- TEST_ASSERT_EQUAL(outcome[REF(officer_d.new_character)], SECURITY_OFFICER_DEPARTMENTS_TO_NAMES["a"], "Officer D's department outcome was incorrect.")
-
-/datum/unit_test/security_officer_roundstart_distribution/proc/create_officer(preference)
- var/mob/dead/new_player/new_player = allocate(/mob/dead/new_player)
- var/datum/client_interface/mock_client = new
-
- mock_client.prefs = new(mock_client)
- var/write_success = mock_client.prefs.write_preference(
- GLOB.preference_entries[/datum/preference/choiced/security_department],
- SECURITY_OFFICER_DEPARTMENTS_TO_NAMES[preference],
- )
-
- TEST_ASSERT(write_success, "Couldn't write department [SECURITY_OFFICER_DEPARTMENTS_TO_NAMES[preference]]")
-
- var/mob/living/carbon/human/new_character = allocate(/mob/living/carbon/human/consistent)
- new_character.mind_initialize()
- new_character.mind.set_assigned_role(SSjob.GetJobType(/datum/job/security_officer))
-
- new_player.new_character = new_character
- new_player.mock_client = mock_client
- return new_player
-
-/// Test that latejoin security officers are put into the correct department
-/datum/unit_test/security_officer_latejoin_distribution
-
-/datum/unit_test/security_officer_latejoin_distribution/proc/test(
- preference,
- list/preferences_of_others,
- expected,
-)
- var/list/distribution = list()
-
- for (var/officer_preference in preferences_of_others)
- var/mob/officer = allocate(/mob/living/carbon/human/consistent)
- distribution[officer] = officer_preference
-
- var/result = get_new_officer_distribution_from_late_join(
- preference,
- SECURITY_OFFICER_DEPARTMENTS,
- distribution,
- )
-
- var/failure_message = "Latejoin distribution was incorrect (preference = [preference], preferences_of_others = [json_encode(preferences_of_others)])."
-
- TEST_ASSERT_EQUAL(result, expected, failure_message)
-
-/datum/unit_test/security_officer_latejoin_distribution/Run()
- test("a", list(), "a")
- test("b", list(), "b")
- test("a", list("b"), "b")
- test("a", list("a", "a"), "b")
- test("a", list("a", "a", "b"), "b")
- test("a", list("a", "a", "b", "b"), "c")
- test("a", list("a", "a", "b", "b", "c", "c", "d", "d"), "a")
-
-#undef SECURITY_OFFICER_DEPARTMENTS
diff --git a/tgstation.dme b/tgstation.dme
index 06f48bda845..2c9fb9d6cd0 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2792,7 +2792,6 @@
#include "code\modules\client\preferences\runechat.dm"
#include "code\modules\client\preferences\scaling_method.dm"
#include "code\modules\client\preferences\screentips.dm"
-#include "code\modules\client\preferences\security_department.dm"
#include "code\modules\client\preferences\skin_tone.dm"
#include "code\modules\client\preferences\species.dm"
#include "code\modules\client\preferences\statpanel.dm"
@@ -3474,6 +3473,7 @@
#include "code\modules\mapping\verify.dm"
#include "code\modules\mapping\map_specific_code\Tramstation.dm"
#include "code\modules\mapping\map_specific_code\bearcat\bearcat_jobs.dm"
+#include "code\modules\mapping\map_specific_code\belryth\belryth_jobs.dm"
#include "code\modules\mapping\modular_map_loader\modular_map_loader.dm"
#include "code\modules\mapping\space_management\multiz_helpers.dm"
#include "code\modules\mapping\space_management\space_level.dm"
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx
deleted file mode 100644
index e9f380bd675..00000000000
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import { FeatureChoiced, FeatureDropdownInput } from '../base';
-
-export const prefered_security_department: FeatureChoiced = {
- name: 'Security department',
- component: FeatureDropdownInput,
-};