diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 4ed099d9e2..4372c4ca24 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -98,6 +98,13 @@
#define DRINKSBLOOD 15
#define NOEYES 16
#define MARKINGS 17
+#define MUTCOLORS2 18
+#define MUTCOLORS3 19
+#define NOAROUSAL 20 //Stops all arousal effects
+#define NOGENITALS 21 //Cannot create, use, or otherwise have genitals
+#define MATRIXED 22 //if icon is color matrix'd
+#define SKINTONE 23 //uses skin tones
+#define HORNCOLOR 24
#define ORGAN_SLOT_BRAIN "brain"
#define ORGAN_SLOT_APPENDIX "appendix"
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 07b53848cf..3301def4a1 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -89,17 +89,6 @@
//Damage stuffs
#define AROUSAL "arousal"
-//DNA stuffs. Remember to change this if upstream adds more snowflake options
-
-
-//Species stuffs. Remember to change this if upstream updates species flags
-#define MUTCOLORS2 35
-#define MUTCOLORS3 36
-#define NOAROUSAL 37 //Stops all arousal effects
-#define NOGENITALS 38 //Cannot create, use, or otherwise have genitals
-#define MATRIXED 39 //if icon is color matrix'd
-#define SKINTONE 40 //uses skin tones
-
//Citadel istypes
#define isgenital(A) (istype(A, /obj/item/organ/genital))
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index ba6ffe12bd..a4d41b02b6 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -56,7 +56,7 @@
#define isslimeperson(A) (is_species(A, /datum/species/jelly/slime))
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
#define iszombie(A) (is_species(A, /datum/species/zombie))
-#define ismoth(A) (is_species(A, /datum/species/moth))
+#define ismoth(A) (is_species(A, /datum/species/insect))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm
index dc4080a789..e6eb9f313e 100644
--- a/code/__DEFINES/jobs.dm
+++ b/code/__DEFINES/jobs.dm
@@ -48,3 +48,41 @@
#define JOB_UNAVAILABLE_PLAYTIME 3
#define JOB_UNAVAILABLE_ACCOUNTAGE 4
#define JOB_UNAVAILABLE_SLOTFULL 5
+
+#define DEFAULT_RELIGION "Christianity"
+#define DEFAULT_DEITY "Space Jesus"
+
+#define JOB_DISPLAY_ORDER_DEFAULT 0
+
+#define JOB_DISPLAY_ORDER_ASSISTANT 1
+#define JOB_DISPLAY_ORDER_CAPTAIN 2
+#define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3
+#define JOB_DISPLAY_ORDER_BARTENDER 4
+#define JOB_DISPLAY_ORDER_COOK 5
+#define JOB_DISPLAY_ORDER_BOTANIST 6
+#define JOB_DISPLAY_ORDER_JANITOR 7
+#define JOB_DISPLAY_ORDER_CLOWN 8
+#define JOB_DISPLAY_ORDER_MIME 9
+#define JOB_DISPLAY_ORDER_CURATOR 10
+#define JOB_DISPLAY_ORDER_LAWYER 11
+#define JOB_DISPLAY_ORDER_CHAPLAIN 12
+#define JOB_DISPLAY_ORDER_QUARTERMASTER 13
+#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 14
+#define JOB_DISPLAY_ORDER_SHAFT_MINER 15
+#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16
+#define JOB_DISPLAY_ORDER_STATION_ENGINEER 17
+#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18
+#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 19
+#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 20
+#define JOB_DISPLAY_ORDER_CHEMIST 21
+#define JOB_DISPLAY_ORDER_GENETICIST 22
+#define JOB_DISPLAY_ORDER_VIROLOGIST 23
+#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 24
+#define JOB_DISPLAY_ORDER_SCIENTIST 25
+#define JOB_DISPLAY_ORDER_ROBOTICIST 26
+#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 27
+#define JOB_DISPLAY_ORDER_WARDEN 28
+#define JOB_DISPLAY_ORDER_DETECTIVE 29
+#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 30
+#define JOB_DISPLAY_ORDER_AI 31
+#define JOB_DISPLAY_ORDER_CYBORG 32
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 02f151dcd9..0992b2e586 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -69,4 +69,9 @@
//Flags in the players table in the db
#define DB_FLAG_EXEMPT 1
-#define DEFAULT_CYBORG_NAME "Default Cyborg Name"
\ No newline at end of file
+#define DEFAULT_CYBORG_NAME "Default Cyborg Name"
+
+//Job preferences levels
+#define JP_LOW 1
+#define JP_MEDIUM 2
+#define JP_HIGH 3
diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm
index 8683f75b08..86d0a34e3e 100644
--- a/code/__HELPERS/_cit_helpers.dm
+++ b/code/__HELPERS/_cit_helpers.dm
@@ -94,6 +94,12 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
"Purple" = "#e300ff"//purple
))
+GLOBAL_LIST_INIT(meat_types, list(
+ "Mammalian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal,
+ "Aquatic" = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic,
+ "Avian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/avian,
+ "Inesct" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect))
+
//Crew objective and miscreants stuff
GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index e09ebcb10c..37f36a7e0d 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -81,3 +81,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
+
+/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
+ return A.display_order - B.display_order
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index ad2bedaa4e..b20122e653 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -30,7 +30,8 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list)
//CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE
//mammal bodyparts (fucking furries)
@@ -44,6 +45,9 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
+ //ipcs
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/screen, GLOB.ipc_screens_list, roundstart = TRUE)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/antenna, GLOB.ipc_antennas_list, roundstart = TRUE)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
@@ -53,7 +57,11 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list ("a", "b", "c", "d", "e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
- GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger")
+ GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ",
+ "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret",
+ "baloney pony", "schlanger", "Mutton dagger", "old blind bob","Hanging Johnny", "fishing rod", "Tally whacker", "polly rocket",
+ "One eyed trouser trout", "Ding dong", "ankle spanker", "Pork sword", "engine cranker", "Harry hot dog", "Davy Crockett",
+ "Kidney cracker", "Heat seeking moisture missile", "Giggle stick", "love whistle", "Tube steak", "Uncle Dick", "Purple helmet warrior")
for(var/K in GLOB.breasts_shapes_list)
var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K]
GLOB.breasts_shapes_icons[K] = value.icon_state
@@ -62,6 +70,7 @@
for(var/K in GLOB.balls_shapes_list)
var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K]
GLOB.balls_shapes_icons[K] = value.icon_state
+
//END OF CIT CHANGES
//Species
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 7ec99fa885..8f3cd4f60d 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -59,7 +59,7 @@
if(!GLOB.horns_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns, GLOB.horns_list)
if(!GLOB.ears_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.horns_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
if(!GLOB.frills_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
if(!GLOB.spines_list.len)
@@ -70,8 +70,10 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
if(!GLOB.wings_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
- if(!GLOB.moth_wings_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
+ if(!GLOB.insect_wings_list.len)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list)
+ if(!GLOB.insect_fluffs_list.len)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list)
//CIT CHANGES - genitals and such
if(!GLOB.cock_shapes_list.len)
@@ -130,22 +132,23 @@
//CIT CHANGE - changes this entire return to support cit's snowflake parts
return(list(
- "mcolor" = color1,
- "mcolor2" = color2,
- "mcolor3" = color3,
- "tail_lizard" = pick(GLOB.tails_list_lizard),
- "tail_human" = "None",
- "wings" = "None",
- "snout" = pick(GLOB.snouts_list),
- "horns" = pick(GLOB.horns_list),
- "ears" = "None",
- "frills" = pick(GLOB.frills_list),
- "spines" = pick(GLOB.spines_list),
- "body_markings" = pick(GLOB.body_markings_list),
- "legs" = pick("Normal Legs","Digitigrade Legs"),
- "caps" = pick(GLOB.caps_list),
- "moth_wings" = pick(GLOB.moth_wings_list),
- "taur" = "None",
+ "mcolor" = color1,
+ "mcolor2" = color2,
+ "mcolor3" = color3,
+ "tail_lizard" = pick(GLOB.tails_list_lizard),
+ "tail_human" = "None",
+ "wings" = "None",
+ "snout" = pick(GLOB.snouts_list),
+ "horns" = pick(GLOB.horns_list),
+ "ears" = "None",
+ "frills" = pick(GLOB.frills_list),
+ "spines" = pick(GLOB.spines_list),
+ "body_markings" = pick(GLOB.body_markings_list),
+ "legs" = pick("Plantigrade","Digitigrade"),
+ "caps" = pick(GLOB.caps_list),
+ "insect_wings" = pick(GLOB.insect_wings_list),
+ "insect_fluff" = "None",
+ "taur" = "None",
"mam_body_markings" = pick(snowflake_markings_list),
"mam_ears" = pick(snowflake_ears_list),
"mam_snouts" = pick(snowflake_mam_snouts_list),
@@ -201,9 +204,11 @@
"womb_cum_mult" = CUM_RATE_MULT,
"womb_efficiency" = CUM_EFFICIENCY,
"womb_fluid" = "femcum",
- "ipc_screen" = "Sunburst",
- "ipc_antenna" = "None",
- "flavor_text" = ""))
+ "ipc_screen" = "Sunburst",
+ "ipc_antenna" = "None",
+ "flavor_text" = "",
+ "meat_type" = "Mammalian"
+ ))
/proc/random_hair_style(gender)
switch(gender)
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index d09368d7b7..c759658bd4 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -34,7 +34,8 @@ GLOBAL_LIST_EMPTY(ears_list)
GLOBAL_LIST_EMPTY(wings_list)
GLOBAL_LIST_EMPTY(wings_open_list)
GLOBAL_LIST_EMPTY(r_wings_list)
-GLOBAL_LIST_EMPTY(moth_wings_list)
+GLOBAL_LIST_EMPTY(insect_wings_list)
+GLOBAL_LIST_EMPTY(insect_fluffs_list)
GLOBAL_LIST_EMPTY(caps_list)
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 4001c666ee..5983fa3ae5 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -116,7 +116,7 @@ SUBSYSTEM_DEF(job)
if(player.mind && job.title in player.mind.restricted_roles)
JobDebug("FOC incompatible with antagonist role, Player: [player]")
continue
- if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
+ if(player.client.prefs.job_preferences[job.title] == level)
JobDebug("FOC pass, Player: [player], Level:[level]")
candidates += player
return candidates
@@ -228,7 +228,7 @@ SUBSYSTEM_DEF(job)
* fills var "assigned_role" for all ready players.
* This proc must not have any side effect besides of modifying "assigned_role".
**/
-/datum/controller/subsystem/job/proc/DivideOccupations()
+/datum/controller/subsystem/job/proc/DivideOccupations(list/required_jobs)
//Setup new player list and get the jobs list
JobDebug("Running DO")
@@ -241,14 +241,14 @@ SUBSYSTEM_DEF(job)
//Get the players who are ready
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)
+ if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role)
unassigned += player
initial_players_to_assign = unassigned.len
JobDebug("DO, Len: [unassigned.len]")
if(unassigned.len == 0)
- return 0
+ return validate_required_jobs(required_jobs)
//Scale number of open security officer slots to population
setup_officer_positions()
@@ -269,7 +269,7 @@ 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, 3)
+ var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW)
JobDebug("AC1, Candidates: [overflow_candidates.len]")
for(var/mob/dead/new_player/player in overflow_candidates)
JobDebug("AC1 pass, Player: [player]")
@@ -297,7 +297,8 @@ SUBSYSTEM_DEF(job)
// Loop through all levels from high to low
var/list/shuffledoccupations = shuffle(occupations)
- for(var/level = 1 to 3)
+ var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW)
+ for(var/level in levels)
//Check the head jobs first each level
CheckHeadPositions(level)
@@ -332,7 +333,7 @@ SUBSYSTEM_DEF(job)
continue
// If the player wants that job on this level, then try give it to him.
- if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
+ if(player.client.prefs.job_preferences[job.title] == level)
// 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]")
@@ -351,9 +352,28 @@ 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))
- AssignRole(player, SSjob.overflow_role) //If everything is already filled, make them an assistant
+ if(!AssignRole(player, SSjob.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 1
+ return validate_required_jobs(required_jobs)
+
+/datum/controller/subsystem/job/proc/validate_required_jobs(list/required_jobs)
+ if(!required_jobs.len)
+ return TRUE
+ for(var/required_group in required_jobs)
+ var/group_ok = TRUE
+ for(var/rank in required_group)
+ var/datum/job/J = GetJob(rank)
+ if(!J)
+ SSticker.mode.setup_error = "Invalid job [rank] in gamemode required jobs."
+ return FALSE
+ if(J.current_positions < required_group[rank])
+ group_ok = FALSE
+ break
+ if(group_ok)
+ return TRUE
+ SSticker.mode.setup_error = "Required jobs not present."
+ return FALSE
//We couldn't find a job from prefs for this guy.
/datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player)
@@ -406,7 +426,7 @@ SUBSYSTEM_DEF(job)
if(length(GLOB.jobspawn_overrides[rank]))
S = pick(GLOB.jobspawn_overrides[rank])
if(S)
- SendToAtom(H, S, buckle = FALSE)
+ S.JoinPlayerHere(H, FALSE)
if(!S) //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]")
SendToLateJoin(H)
@@ -418,7 +438,7 @@ SUBSYSTEM_DEF(job)
if(job)
if(!job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
- var/new_mob = job.equip(H, null, null, joined_late)
+ var/new_mob = job.equip(H, null, null, joined_late , null, M.client)
if(ismob(new_mob))
H = new_mob
if(!joined_late)
@@ -428,12 +448,18 @@ SUBSYSTEM_DEF(job)
SSpersistence.antag_rep_change[M.client.ckey] += job.GetAntagRep()
+/* 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, "You are the [rank]. ")
if(job)
to_chat(M, "As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this. ")
- to_chat(M, "To speak on your departments radio, use the :h button. To see others, look closely at your headset. ")
+ 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. ")
+ to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect immediately, please notify the admins via adminhelp. Otherwise put your locker gear back into the locker and cryo out. ")
if(job.custom_spawn_text)
to_chat(M, "[job.custom_spawn_text] ")
if(CONFIG_GET(number/minimal_access_threshold))
@@ -446,12 +472,24 @@ SUBSYSTEM_DEF(job)
equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works
return H
-
+/*
+/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank)
+ if(!C?.holder)
+ return TRUE
+ var/datum/job/job = GetJob(rank)
+ if(!job)
+ return
+ if((job.auto_deadmin_role_flags & DEADMIN_POSITION_HEAD) && (CONFIG_GET(flag/auto_deadmin_heads) || (C.prefs?.toggles & DEADMIN_POSITION_HEAD)))
+ return C.holder.auto_deadmin()
+ else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SECURITY) && (CONFIG_GET(flag/auto_deadmin_security) || (C.prefs?.toggles & DEADMIN_POSITION_SECURITY)))
+ return C.holder.auto_deadmin()
+ else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SILICON) && (CONFIG_GET(flag/auto_deadmin_silicons) || (C.prefs?.toggles & DEADMIN_POSITION_SILICON))) //in the event there's ever psuedo-silicon roles added, ie synths.
+ return C.holder.auto_deadmin()*/
/datum/controller/subsystem/job/proc/setup_officer_positions()
var/datum/job/J = SSjob.GetJob("Security Officer")
if(!J)
- throw EXCEPTION("setup_officer_positions(): Security officer job is missing")
+ CRASH("setup_officer_positions(): Security officer job is missing")
var/ssc = CONFIG_GET(number/security_scaling_coeff)
if(ssc > 0)
@@ -502,13 +540,15 @@ SUBSYSTEM_DEF(job)
if(job.required_playtime_remaining(player.client))
young++
continue
- if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
- high++
- else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
- medium++
- else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag)
- low++
- else never++ //not selected
+ switch(player.client.prefs.job_preferences[job.title])
+ if(JP_HIGH)
+ high++
+ if(JP_MEDIUM)
+ medium++
+ if(JP_LOW)
+ low++
+ else
+ never++
SSblackbox.record_feedback("nested tally", "job_preferences", high, list("[job.title]", "high"))
SSblackbox.record_feedback("nested tally", "job_preferences", medium, list("[job.title]", "medium"))
SSblackbox.record_feedback("nested tally", "job_preferences", low, list("[job.title]", "low"))
@@ -551,51 +591,61 @@ SUBSYSTEM_DEF(job)
newjob.spawn_positions = J.spawn_positions
newjob.current_positions = J.current_positions
-/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle)
- if(buckle && isliving(M) && istype(A, /obj/structure/chair))
- var/obj/structure/chair/C = A
- if(C.buckle_mob(M, FALSE, FALSE))
- return
- M.forceMove(get_turf(A))
+/atom/proc/JoinPlayerHere(mob/M, buckle)
+ // By default, just place the mob on the same turf as the marker or whatever.
+ M.forceMove(get_turf(src))
+
+/obj/structure/chair/JoinPlayerHere(mob/M, buckle)
+ // Placing a mob in a chair will attempt to buckle it, or else fall back to default.
+ if (buckle && isliving(M) && buckle_mob(M, FALSE, FALSE))
+ return
+ ..()
/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.
- SendToAtom(M,pick(GLOB.jobspawn_overrides[M.mind.assigned_role]),FALSE)
+ destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role])
+ destination.JoinPlayerHere(M, FALSE)
return
if(latejoin_trackers.len)
- SendToAtom(M, pick(latejoin_trackers), buckle)
- else
- //bad mojo
- var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival]
- if(A)
- //first check if we can find a chair
- var/obj/structure/chair/C = locate() in A
- if(C)
- SendToAtom(M, C, buckle)
- return
- else //last hurrah
- var/list/avail = list()
- for(var/turf/T in A)
- if(!is_blocked_turf(T, TRUE))
- avail += T
- if(avail.len)
- SendToAtom(M, pick(avail), FALSE)
- return
+ destination = pick(latejoin_trackers)
+ destination.JoinPlayerHere(M, buckle)
+ return
- //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(!is_blocked_turf(T, TRUE))
- SendToAtom(M, T, FALSE)
- return
- //last chance, pick ANY spot on arrivals and dump em
- SendToAtom(M, arrivals_turfs[1], FALSE)
- else
- var/msg = "Unable to send mob [M] to late join!"
- message_admins(msg)
- CRASH(msg)
+ //bad mojo
+ var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival]
+ if(A)
+ //first check if we can find a chair
+ var/obj/structure/chair/C = locate() in A
+ if(C)
+ C.JoinPlayerHere(M, buckle)
+ return
+
+ //last hurrah
+ var/list/avail = list()
+ for(var/turf/T in A)
+ if(!is_blocked_turf(T, TRUE))
+ avail += T
+ if(avail.len)
+ destination = pick(avail)
+ destination.JoinPlayerHere(M, FALSE)
+ return
+
+ //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(!is_blocked_turf(T, TRUE))
+ T.JoinPlayerHere(M, FALSE)
+ return
+ //last chance, pick ANY spot on arrivals and dump em
+ destination = arrivals_turfs[1]
+ destination.JoinPlayerHere(M, FALSE)
+ else
+ var/msg = "Unable to send mob [M] to late join!"
+ message_admins(msg)
+ CRASH(msg)
///////////////////////////////////
@@ -637,4 +687,4 @@ SUBSYSTEM_DEF(job)
. |= player.mind
/datum/controller/subsystem/job/proc/JobDebug(message)
- log_job_debug(message)
\ No newline at end of file
+ log_job_debug(message)
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index f2469e8f7d..14e1e86f7d 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -255,7 +255,7 @@ SUBSYSTEM_DEF(ticker)
var/can_continue = 0
can_continue = src.mode.pre_setup() //Choose antagonists
CHECK_TICK
- SSjob.DivideOccupations() //Distribute jobs
+ can_continue = can_continue && SSjob.DivideOccupations(mode.required_jobs) //Distribute jobs
CHECK_TICK
if(!GLOB.Debug2)
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 1f5c28d3c2..68165af956 100755
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -21,6 +21,7 @@
var/l_hand = null
var/internals_slot = null //ID of slot containing a gas tank
var/list/backpack_contents = null // In the list(path=count,otherpath=count) format
+ var/box // Internals box. Will be inserted at the start of backpack_contents
var/list/implants = null
var/accessory = null
@@ -83,6 +84,13 @@
H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE)
if(r_pocket)
H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE)
+
+ if(box)
+ if(!backpack_contents)
+ backpack_contents = list()
+ backpack_contents.Insert(1, box)
+ backpack_contents[box] = 1
+
if(backpack_contents)
for(var/path in backpack_contents)
var/number = backpack_contents[path]
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index cc992fefbc..f790053863 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -24,6 +24,7 @@
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
var/list/protected_jobs = list() // Jobs that can't be traitors because
+ var/list/required_jobs = list() // alternative required job groups eg list(list(cap=1),list(hos=1,sec=2)) translates to one captain OR one hos and two secmans
var/required_players = 0
var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations
var/required_enemies = 0
@@ -355,7 +356,7 @@
// Ultimate randomizing code right here
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.client && player.ready == PLAYER_READY_TO_PLAY)
+ if(player.client && player.ready == PLAYER_READY_TO_PLAY && player.check_preferences())
players += player
// Shuffling, the players list is now ping-independent!!!
diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm
index 5e30e599df..88ab4ec6f8 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -27,12 +27,10 @@
"human",
"lizard",
"fly",
- "moth",
+ "insect",
"plasmaman",
"mammal",
- "aquatic",
- "insect",
- "xenoperson",
+ "xeno",
"other"
)
diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm
index f66cda42dc..8b6f471e7d 100644
--- a/code/modules/admin/create_mob.dm
+++ b/code/modules/admin/create_mob.dm
@@ -34,7 +34,8 @@
H.dna.features["frills"] = pick(GLOB.frills_list)
H.dna.features["spines"] = pick(GLOB.spines_list)
H.dna.features["body_markings"] = pick(GLOB.body_markings_list)
- H.dna.features["moth_wings"] = pick(GLOB.moth_wings_list)
+ H.dna.features["insect_wings"] = pick(GLOB.insect_wings_list)
+ H.dna.features["insect_fluff"] = pick(GLOB.insect_fluffs_list)
H.update_body()
H.update_hair()
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index 8a3ff2186a..72edb18020 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -167,7 +167,7 @@
/obj/item/organ/heart/gland/pop/activate()
to_chat(owner, "You feel unlike yourself. ")
randomize_human(owner)
- var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/moth, /datum/species/fly))
+ var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/insect, /datum/species/fly))
owner.set_species(species)
/obj/item/organ/heart/gland/ventcrawling
diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm
index bdbd38b92d..081b1181dc 100644
--- a/code/modules/antagonists/changeling/powers/strained_muscles.dm
+++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm
@@ -34,6 +34,7 @@
return TRUE
/obj/effect/proc_holder/changeling/strained_muscles/proc/muscle_loop(mob/living/carbon/user)
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
while(active)
ADD_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles")
if(user.stat != CONSCIOUS || user.staminaloss >= 90)
@@ -41,6 +42,7 @@
to_chat(user, "Our muscles relax without the energy to strengthen them. ")
user.Knockdown(40)
REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles")
+ changeling.chem_recharge_slowdown -= 0.5
break
stacks++
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 88fd142c1e..686d5d3572 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -85,6 +85,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/facial_hair_color = "000" //Facial hair color
var/skin_tone = "caucasian1" //Skin color
var/eye_color = "000" //Eye color
+ var/horn_color = "85615a" //Horn color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
var/list/features = list("mcolor" = "FFF",
"tail_lizard" = "Smooth",
@@ -96,8 +97,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"frills" = "None",
"spines" = "None",
"body_markings" = "None",
- "legs" = "Normal Legs",
- "moth_wings" = "Plain",
+ "legs" = "Plantigrade",
+ "insect_wings" = "Plain",
+ "insect_fluff" = "None",
"mcolor2" = "FFF",
"mcolor3" = "FFF",
"mam_body_markings" = "Plain",
@@ -157,7 +159,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"womb_fluid" = "femcum",
"ipc_screen" = "Sunburst",
"ipc_antenna" = "None",
- "flavor_text" = ""
+ "flavor_text" = "",
+ "meat_type" = "Mammalian"
)
var/list/custom_names = list()
@@ -172,18 +175,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/all_quirks = list()
var/list/character_quirks = list()
- //Jobs, uses bitflags
- var/job_civilian_high = 0
- var/job_civilian_med = 0
- var/job_civilian_low = 0
-
- var/job_medsci_high = 0
- var/job_medsci_med = 0
- var/job_medsci_low = 0
-
- var/job_engsec_high = 0
- var/job_engsec_med = 0
- var/job_engsec_low = 0
+ //Job preferences 2.0 - indexed by job title , no key or value implies never
+ var/list/job_preferences = list()
// Want randomjob if preferences already filled - Donkie
var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
@@ -241,7 +234,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return
#define APPEARANCE_CATEGORY_COLUMN "
"
-#define MAX_MUTANT_ROWS 4
+#define MAX_MUTANT_ROWS 5
/datum/preferences/proc/ShowChoices(mob/user)
if(!user || !user.client)
@@ -351,9 +344,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "[TextPreview(features["flavor_text"])]... "
dat += "Body "
dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))] "
- dat += "Species: [pref_species.id] "
+ dat += "Species: [pref_species.name] "
dat += "Custom Species Name: [custom_species ? custom_species : "None"] "
- dat += "Random Body "
+ dat += "Random Body: Randomize! "
dat += "Always Random Body: [be_random_body ? "Yes" : "No"] "
dat += "Cycle background: [bgstate] "
@@ -448,6 +441,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "[features["tail_human"]] "
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += " "
+ mutant_category = 0
+
+ if("meat_type" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Meat Type "
+
+ dat += "[features["meat_type"]] "
+
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
@@ -471,6 +477,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Horns "
dat += "[features["horns"]] "
+ dat += " Change "
+
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
@@ -537,6 +545,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
mutant_category = 0
+
if("ears" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
@@ -549,6 +558,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
mutant_category = 0
+
if("mam_snouts" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
@@ -573,14 +583,24 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
mutant_category = 0
- if("moth_wings" in pref_species.default_features)
+ if("insect_wings" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
- dat += "Moth wings "
+ dat += "Insect wings "
- dat += "[features["moth_wings"]] "
+ dat += "[features["insect_wings"]] "
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("insect_fluff" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+ dat += "Insect Fluff "
+
+ dat += "[features["insect_fluff"]] "
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
@@ -992,9 +1012,7 @@ 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 = SSjob.GetJob(SSjob.overflow_role)
-
- for(var/datum/job/job in SSjob.occupations)
+ for(var/datum/job/job in sortList(SSjob.occupations, /proc/cmp_job_display_asc))
index += 1
if((index >= limit) || (job.title in splitJobs))
@@ -1011,7 +1029,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/rank = job.title
lastJob = job
if(jobban_isbanned(user, rank))
- HTML += "[rank] BANNED "
+ HTML += "[rank] BANNED "
continue
var/required_playtime_remaining = job.required_playtime_remaining(user.client)
if(required_playtime_remaining)
@@ -1021,7 +1039,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/available_in_days = job.available_in_days(user.client)
HTML += "[rank] \[IN [(available_in_days)] DAYS\] "
continue
- if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
+ if((job_preferences[SSjob.overflow_role] == JP_LOW) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
HTML += "[rank] "
continue
if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
@@ -1036,32 +1054,32 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/prefUpperLevel = -1 // level to assign on left click
var/prefLowerLevel = -1 // level to assign on right click
- if(GetJobDepartment(job, 1) & job.flag)
- prefLevelLabel = "High"
- prefLevelColor = "slateblue"
- prefUpperLevel = 4
- prefLowerLevel = 2
- else if(GetJobDepartment(job, 2) & job.flag)
- prefLevelLabel = "Medium"
- prefLevelColor = "green"
- prefUpperLevel = 1
- prefLowerLevel = 3
- else if(GetJobDepartment(job, 3) & job.flag)
- prefLevelLabel = "Low"
- prefLevelColor = "orange"
- prefUpperLevel = 2
- prefLowerLevel = 4
- else
- prefLevelLabel = "NEVER"
- prefLevelColor = "red"
- prefUpperLevel = 3
- prefLowerLevel = 1
-
+ switch(job_preferences[job.title])
+ if(JP_HIGH)
+ prefLevelLabel = "High"
+ prefLevelColor = "slateblue"
+ prefUpperLevel = 4
+ prefLowerLevel = 2
+ if(JP_MEDIUM)
+ prefLevelLabel = "Medium"
+ prefLevelColor = "green"
+ prefUpperLevel = 1
+ prefLowerLevel = 3
+ if(JP_LOW)
+ prefLevelLabel = "Low"
+ prefLevelColor = "orange"
+ prefUpperLevel = 2
+ prefLowerLevel = 4
+ else
+ prefLevelLabel = "NEVER"
+ prefLevelColor = "red"
+ prefUpperLevel = 3
+ prefLowerLevel = 1
HTML += ""
if(rank == SSjob.overflow_role)//Overflow is special
- if(job_civilian_low & overflow.flag)
+ if(job_preferences[SSjob.overflow_role] == JP_LOW)
HTML += "Yes "
else
HTML += "No "
@@ -1092,61 +1110,17 @@ GLOBAL_LIST_EMPTY(preferences_datums)
/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level)
if (!job)
- return 0
+ return FALSE
- if (level == 1) // to high
- // remove any other job(s) set to high
- job_civilian_med |= job_civilian_high
- job_engsec_med |= job_engsec_high
- job_medsci_med |= job_medsci_high
- job_civilian_high = 0
- job_engsec_high = 0
- job_medsci_high = 0
+ if (level == JP_HIGH) // to high
+ //Set all other high to medium
+ for(var/j in job_preferences)
+ if(job_preferences[j] == JP_HIGH)
+ job_preferences[j] = JP_MEDIUM
+ //technically break here
- if (job.department_flag == CIVILIAN)
- job_civilian_low &= ~job.flag
- job_civilian_med &= ~job.flag
- job_civilian_high &= ~job.flag
-
- switch(level)
- if (1)
- job_civilian_high |= job.flag
- if (2)
- job_civilian_med |= job.flag
- if (3)
- job_civilian_low |= job.flag
-
- return 1
- else if (job.department_flag == ENGSEC)
- job_engsec_low &= ~job.flag
- job_engsec_med &= ~job.flag
- job_engsec_high &= ~job.flag
-
- switch(level)
- if (1)
- job_engsec_high |= job.flag
- if (2)
- job_engsec_med |= job.flag
- if (3)
- job_engsec_low |= job.flag
-
- return 1
- else if (job.department_flag == MEDSCI)
- job_medsci_low &= ~job.flag
- job_medsci_med &= ~job.flag
- job_medsci_high &= ~job.flag
-
- switch(level)
- if (1)
- job_medsci_high |= job.flag
- if (2)
- job_medsci_med |= job.flag
- if (3)
- job_medsci_low |= job.flag
-
- return 1
-
- return 0
+ job_preferences[job.title] = level
+ return TRUE
/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl)
if(!SSjob || SSjob.occupations.len <= 0)
@@ -1163,64 +1137,29 @@ GLOBAL_LIST_EMPTY(preferences_datums)
ShowChoices(user)
return
- if(role == SSjob.overflow_role)
- if(job_civilian_low & job.flag)
- job_civilian_low &= ~job.flag
- else
- job_civilian_low |= job.flag
- SetChoices(user)
- return 1
+ var/jpval = null
+ switch(desiredLvl)
+ if(3)
+ jpval = JP_LOW
+ if(2)
+ jpval = JP_MEDIUM
+ if(1)
+ jpval = JP_HIGH
- SetJobPreferenceLevel(job, desiredLvl)
+ if(role == SSjob.overflow_role)
+ if(job_preferences[job.title] == JP_LOW)
+ jpval = null
+ else
+ jpval = JP_LOW
+
+ SetJobPreferenceLevel(job, jpval)
SetChoices(user)
return 1
/datum/preferences/proc/ResetJobs()
-
- job_civilian_high = 0
- job_civilian_med = 0
- job_civilian_low = 0
-
- job_medsci_high = 0
- job_medsci_med = 0
- job_medsci_low = 0
-
- job_engsec_high = 0
- job_engsec_med = 0
- job_engsec_low = 0
-
-
-/datum/preferences/proc/GetJobDepartment(datum/job/job, level)
- if(!job || !level)
- return 0
- switch(job.department_flag)
- if(CIVILIAN)
- switch(level)
- if(1)
- return job_civilian_high
- if(2)
- return job_civilian_med
- if(3)
- return job_civilian_low
- if(MEDSCI)
- switch(level)
- if(1)
- return job_medsci_high
- if(2)
- return job_medsci_med
- if(3)
- return job_medsci_low
- if(ENGSEC)
- switch(level)
- if(1)
- return job_engsec_high
- if(2)
- return job_engsec_med
- if(3)
- return job_engsec_low
- return 0
+ job_preferences = list()
/datum/preferences/proc/SetQuirks(mob/user)
if(!SSquirks)
@@ -1562,9 +1501,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
eye_color = sanitize_hexcolor(new_eyes)
if("species")
- var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races
+ var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_race_names
if(result)
- var/newtype = GLOB.species_list[result]
+ var/newtype = GLOB.species_list[GLOB.roundstart_race_names[result]]
pref_species = new newtype()
//let's ensure that no weird shit happens on species swapping.
custom_species = null
@@ -1692,6 +1631,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["tail_human"] = "None"
features["tail_lizard"] = "None"
+ if("meats")
+ var/new_meat
+ new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types
+ if(new_meat)
+ features["meat_type"] = new_meat
+
if("snout")
var/list/snowflake_snouts_list = list()
for(var/path in GLOB.snouts_list)
@@ -1727,6 +1672,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_horns)
features["horns"] = new_horns
+ if("horns_color")
+ var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+horn_color) as color|null
+ if(new_horn_color)
+ horn_color = sanitize_hexcolor(new_horn_color)
+
if("wings")
var/new_wings
new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list
@@ -1761,11 +1711,17 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["legs"] = new_legs
update_preview_icon()
- if("moth_wings")
- var/new_moth_wings
- new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list
- if(new_moth_wings)
- features["moth_wings"] = new_moth_wings
+ if("insect_wings")
+ var/new_insect_wings
+ new_insect_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_wings_list
+ if(new_insect_wings)
+ features["insect_wings"] = new_insect_wings
+
+ if("insect_fluffs")
+ var/new_insect_fluff
+ new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list
+ if(new_insect_fluff)
+ features["insect_fluff"] = new_insect_fluff
if("s_tone")
var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
@@ -2285,6 +2241,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
organ_eyes.old_eye_color = eye_color
character.hair_color = hair_color
character.facial_hair_color = facial_hair_color
+ character.horn_color = horn_color
character.skin_tone = skin_tone
character.hair_style = hair_style
@@ -2325,7 +2282,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("xenotail" in pref_species.default_features)
character.dna.species.mutant_bodyparts |= "xenotail"
- if(("legs" in character.dna.species.mutant_bodyparts) && character.dna.features["legs"] == "Digitigrade Legs")
+ if("meat_type" in pref_species.default_features)
+ character.type_of_meat = GLOB.meat_types[features["meat_type"]]
+
+ if(("legs" in character.dna.species.mutant_bodyparts) && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian"))
pref_species.species_traits |= DIGITIGRADE
else
pref_species.species_traits -= DIGITIGRADE
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index a3f45f53ca..c900349843 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 20
+#define SAVEFILE_VERSION_MAX 22
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -49,6 +49,61 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
pda_style = "mono"
if(current_version < 20)
pda_color = "#808000"
+ if(current_version < 21)
+ job_preferences = list() //It loaded null from nonexistant savefile field.
+ var/job_civilian_high = 0
+ var/job_civilian_med = 0
+ var/job_civilian_low = 0
+
+ var/job_medsci_high = 0
+ var/job_medsci_med = 0
+ var/job_medsci_low = 0
+
+ var/job_engsec_high = 0
+ var/job_engsec_med = 0
+ var/job_engsec_low = 0
+
+ S["job_civilian_high"] >> job_civilian_high
+ S["job_civilian_med"] >> job_civilian_med
+ S["job_civilian_low"] >> job_civilian_low
+ S["job_medsci_high"] >> job_medsci_high
+ S["job_medsci_med"] >> job_medsci_med
+ S["job_medsci_low"] >> job_medsci_low
+ S["job_engsec_high"] >> job_engsec_high
+ S["job_engsec_med"] >> job_engsec_med
+ S["job_engsec_low"] >> job_engsec_low
+
+ //Can't use SSjob here since this happens right away on login
+ for(var/job in subtypesof(/datum/job))
+ var/datum/job/J = job
+ var/new_value
+ var/fval = initial(J.flag)
+ switch(initial(J.department_flag))
+ if(CIVILIAN)
+ if(job_civilian_high & fval)
+ new_value = JP_HIGH
+ else if(job_civilian_med & fval)
+ new_value = JP_MEDIUM
+ else if(job_civilian_low & fval)
+ new_value = JP_LOW
+ if(MEDSCI)
+ if(job_medsci_high & fval)
+ new_value = JP_HIGH
+ else if(job_medsci_med & fval)
+ new_value = JP_MEDIUM
+ else if(job_medsci_low & fval)
+ new_value = JP_LOW
+ if(ENGSEC)
+ if(job_engsec_high & fval)
+ new_value = JP_HIGH
+ else if(job_engsec_med & fval)
+ new_value = JP_MEDIUM
+ else if(job_engsec_low & fval)
+ new_value = JP_LOW
+ if(new_value)
+ job_preferences[initial(J.title)] = new_value
+ if((current_version < 22) && features["meat_type"] && (features["meat_type"] == null))
+ features["meat_type"] = "Mammalian"
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
@@ -246,6 +301,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
var/species_id
S["species"] >> species_id
if(species_id)
+ if(species_id == "avian" || species_id == "aquatic")
+ species_id = "mammal"
+ else if(species_id == "moth")
+ species_id = "insect"
+
var/newtype = GLOB.species_list[species_id]
if(newtype)
pref_species = new newtype
@@ -254,28 +314,29 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["features["mcolor"]"] , "#FFF")
//Character
- S["real_name"] >> real_name
- S["nameless"] >> nameless
- S["custom_species"] >> custom_species
- S["name_is_always_random"] >> be_random_name
- S["body_is_always_random"] >> be_random_body
- S["gender"] >> gender
- S["age"] >> age
- S["hair_color"] >> hair_color
- S["facial_hair_color"] >> facial_hair_color
- S["eye_color"] >> eye_color
- S["skin_tone"] >> skin_tone
- S["hair_style_name"] >> hair_style
- S["facial_style_name"] >> facial_hair_style
- S["underwear"] >> underwear
- S["undie_color"] >> undie_color
- S["undershirt"] >> undershirt
- S["shirt_color"] >> shirt_color
- S["socks"] >> socks
- S["socks_color"] >> socks_color
- S["backbag"] >> backbag
- S["jumpsuit_style"] >> jumpsuit_style
- S["uplink_loc"] >> uplink_spawn_loc
+ S["real_name"] >> real_name
+ S["nameless"] >> nameless
+ S["custom_species"] >> custom_species
+ S["name_is_always_random"] >> be_random_name
+ S["body_is_always_random"] >> be_random_body
+ S["gender"] >> gender
+ S["age"] >> age
+ S["hair_color"] >> hair_color
+ S["facial_hair_color"] >> facial_hair_color
+ S["eye_color"] >> eye_color
+ S["skin_tone"] >> skin_tone
+ S["hair_style_name"] >> hair_style
+ S["facial_style_name"] >> facial_hair_style
+ S["underwear"] >> underwear
+ S["undie_color"] >> undie_color
+ S["undershirt"] >> undershirt
+ S["shirt_color"] >> shirt_color
+ S["socks"] >> socks
+ S["socks_color"] >> socks_color
+ S["horn_color"] >> horn_color
+ S["backbag"] >> backbag
+ S["jumpsuit_style"] >> jumpsuit_style
+ S["uplink_loc"] >> uplink_spawn_loc
S["feature_mcolor"] >> features["mcolor"]
S["feature_lizard_tail"] >> features["tail_lizard"]
S["feature_lizard_snout"] >> features["snout"]
@@ -284,29 +345,23 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_lizard_spines"] >> features["spines"]
S["feature_lizard_body_markings"] >> features["body_markings"]
S["feature_lizard_legs"] >> features["legs"]
- S["feature_moth_wings"] >> features["moth_wings"]
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
+ S["feature_insect_wings"] >> features["insect_wings"]
+ S["feature_insect_fluff"] >> features["insect_fluff"]
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
var/savefile_slot_name = custom_name_id + "_name" //TODO remove this
S[savefile_slot_name] >> custom_names[custom_name_id]
- S["preferred_ai_core_display"] >> preferred_ai_core_display
- S["prefered_security_department"] >> prefered_security_department
+ S["preferred_ai_core_display"] >> preferred_ai_core_display
+ S["prefered_security_department"] >> prefered_security_department
//Jobs
S["joblessrole"] >> joblessrole
- S["job_civilian_high"] >> job_civilian_high
- S["job_civilian_med"] >> job_civilian_med
- S["job_civilian_low"] >> job_civilian_low
- S["job_medsci_high"] >> job_medsci_high
- S["job_medsci_med"] >> job_medsci_med
- S["job_medsci_low"] >> job_medsci_low
- S["job_engsec_high"] >> job_engsec_high
- S["job_engsec_med"] >> job_engsec_med
- S["job_engsec_low"] >> job_engsec_low
+ //Load prefs
+ S["job_preferences"] >> job_preferences
//Quirks
S["all_quirks"] >> all_quirks
@@ -325,6 +380,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_mam_tail_animated"] >> features["mam_tail_animated"]
S["feature_taur"] >> features["taur"]
S["feature_mam_snouts"] >> features["mam_snouts"]
+ S["feature_meat"] >> features["meat_type"]
//Xeno features
S["feature_xeno_tail"] >> features["xenotail"]
S["feature_xeno_dors"] >> features["xenodorsal"]
@@ -374,11 +430,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Sanitize
- real_name = reject_bad_name(real_name)
- gender = sanitize_gender(gender, TRUE, TRUE)
+ real_name = reject_bad_name(real_name)
+ gender = sanitize_gender(gender, TRUE, TRUE)
if(!real_name)
- real_name = random_unique_name(gender)
- custom_species = reject_bad_name(custom_species)
+ real_name = random_unique_name(gender)
+ custom_species = reject_bad_name(custom_species)
for(var/custom_name_id in GLOB.preferences_custom_names)
var/namedata = GLOB.preferences_custom_names[custom_name_id]
custom_names[custom_name_id] = reject_bad_name(custom_names[custom_name_id],namedata["allow_numbers"])
@@ -388,57 +444,55 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!features["mcolor"] || features["mcolor"] == "#000")
features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
+ nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
if(gender == MALE)
- hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_male_list)
+ hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_male_list)
facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_male_list)
else
- hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_female_list)
+ hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_female_list)
facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_female_list)
- underwear = sanitize_inlist(underwear, GLOB.underwear_list)
- undie_color = sanitize_hexcolor(undie_color, 3, FALSE, initial(undie_color))
- undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list)
- shirt_color = sanitize_hexcolor(shirt_color, 3, FALSE, initial(shirt_color))
- socks = sanitize_inlist(socks, GLOB.socks_list)
- socks_color = sanitize_hexcolor(socks_color, 3, FALSE, initial(socks_color))
- age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
- hair_color = sanitize_hexcolor(hair_color, 3, 0)
- facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0)
- eye_color = sanitize_hexcolor(eye_color, 3, 0)
- skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones)
- backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
- jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
- uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
- features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0)
- features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
- features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human)
- features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list)
- features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list)
- features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list)
- features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list)
- features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list)
- features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list)
+ underwear = sanitize_inlist(underwear, GLOB.underwear_list)
+ undie_color = sanitize_hexcolor(undie_color, 3, FALSE, initial(undie_color))
+ undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list)
+ shirt_color = sanitize_hexcolor(shirt_color, 6, FALSE, initial(shirt_color))
+ socks = sanitize_inlist(socks, GLOB.socks_list)
+ socks_color = sanitize_hexcolor(socks_color, 6, FALSE, initial(socks_color))
+ age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
+ hair_color = sanitize_hexcolor(hair_color, 3, 0)
+ facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0)
+ eye_color = sanitize_hexcolor(eye_color, 3, 0)
+ skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones)
+ horn_color = sanitize_hexcolor(horn_color, 3, FALSE)
+ backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
+ jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
+ uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
+ features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0)
+ features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
+ features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human)
+ features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list)
+ features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list)
+ features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list)
+ features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list)
+ features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list)
+ features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list)
features["feature_lizard_legs"] = sanitize_inlist(features["legs"], GLOB.legs_list)
- features["moth_wings"] = sanitize_inlist(features["moth_wings"], GLOB.moth_wings_list)
+ features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
+ features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
- job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high))
- job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med))
- job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_low))
- job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high))
- job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med))
- job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low))
- job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high))
- job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med))
- job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low))
+ //Validate job prefs
+ for(var/j in job_preferences)
+ if(job_preferences[j] != JP_LOW && job_preferences[j] != JP_MEDIUM && job_preferences[j] != JP_HIGH)
+ job_preferences -= j
all_quirks = SANITIZE_LIST(all_quirks)
+
positive_quirks = SANITIZE_LIST(positive_quirks)
negative_quirks = SANITIZE_LIST(negative_quirks)
- neutral_quirks = SANITIZE_LIST(neutral_quirks)
+ neutral_quirks = SANITIZE_LIST(neutral_quirks)
cit_character_pref_load(S)
@@ -460,31 +514,32 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //load_character will sanitize any bad data, so assume up-to-date.)
//Character
- WRITE_FILE(S["real_name"] , real_name)
- WRITE_FILE(S["nameless"] , nameless)
- WRITE_FILE(S["custom_species"] , custom_species)
- WRITE_FILE(S["name_is_always_random"] , be_random_name)
- WRITE_FILE(S["body_is_always_random"] , be_random_body)
- WRITE_FILE(S["gender"] , gender)
- WRITE_FILE(S["age"] , age)
- WRITE_FILE(S["hair_color"] , hair_color)
- WRITE_FILE(S["facial_hair_color"] , facial_hair_color)
- WRITE_FILE(S["eye_color"] , eye_color)
- WRITE_FILE(S["skin_tone"] , skin_tone)
- WRITE_FILE(S["hair_style_name"] , hair_style)
- WRITE_FILE(S["facial_style_name"] , facial_hair_style)
- WRITE_FILE(S["underwear"] , underwear)
- WRITE_FILE(S["undie_color"] , undie_color)
- WRITE_FILE(S["undershirt"] , undershirt)
- WRITE_FILE(S["shirt_color"] , shirt_color)
- WRITE_FILE(S["socks"] , socks)
- WRITE_FILE(S["socks_color"] , socks_color)
- WRITE_FILE(S["backbag"] , backbag)
- WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
- WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
- WRITE_FILE(S["species"] , pref_species.id)
+ WRITE_FILE(S["real_name"] , real_name)
+ WRITE_FILE(S["nameless"] , nameless)
+ WRITE_FILE(S["custom_species"] , custom_species)
+ WRITE_FILE(S["name_is_always_random"] , be_random_name)
+ WRITE_FILE(S["body_is_always_random"] , be_random_body)
+ WRITE_FILE(S["gender"] , gender)
+ WRITE_FILE(S["age"] , age)
+ WRITE_FILE(S["hair_color"] , hair_color)
+ WRITE_FILE(S["facial_hair_color"] , facial_hair_color)
+ WRITE_FILE(S["eye_color"] , eye_color)
+ WRITE_FILE(S["skin_tone"] , skin_tone)
+ WRITE_FILE(S["hair_style_name"] , hair_style)
+ WRITE_FILE(S["facial_style_name"] , facial_hair_style)
+ WRITE_FILE(S["underwear"] , underwear)
+ WRITE_FILE(S["undie_color"] , undie_color)
+ WRITE_FILE(S["undershirt"] , undershirt)
+ WRITE_FILE(S["shirt_color"] , shirt_color)
+ WRITE_FILE(S["socks"] , socks)
+ WRITE_FILE(S["socks_color"] , socks_color)
+ WRITE_FILE(S["horn_color"] , horn_color)
+ WRITE_FILE(S["backbag"] , backbag)
+ WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
+ WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
+ WRITE_FILE(S["species"] , pref_species.id)
WRITE_FILE(S["feature_mcolor"] , features["mcolor"])
- WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"])
+ WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"])
WRITE_FILE(S["feature_human_tail"] , features["tail_human"])
WRITE_FILE(S["feature_lizard_snout"] , features["snout"])
WRITE_FILE(S["feature_lizard_horns"] , features["horns"])
@@ -492,28 +547,23 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_lizard_frills"] , features["frills"])
WRITE_FILE(S["feature_lizard_spines"] , features["spines"])
WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"])
- WRITE_FILE(S["feature_lizard_legs"] , features["legs"])
- WRITE_FILE(S["feature_moth_wings"] , features["moth_wings"])
+ WRITE_FILE(S["feature_lizard_legs"] , features["legs"])
+ WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"])
+ WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"])
+ WRITE_FILE(S["feature_meat"] , features["meat_type"])
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
var/savefile_slot_name = custom_name_id + "_name" //TODO remove this
WRITE_FILE(S[savefile_slot_name],custom_names[custom_name_id])
- WRITE_FILE(S["preferred_ai_core_display"] , preferred_ai_core_display)
- WRITE_FILE(S["prefered_security_department"] , prefered_security_department)
+ WRITE_FILE(S["preferred_ai_core_display"] , preferred_ai_core_display)
+ WRITE_FILE(S["prefered_security_department"] , prefered_security_department)
//Jobs
WRITE_FILE(S["joblessrole"] , joblessrole)
- WRITE_FILE(S["job_civilian_high"] , job_civilian_high)
- WRITE_FILE(S["job_civilian_med"] , job_civilian_med)
- WRITE_FILE(S["job_civilian_low"] , job_civilian_low)
- WRITE_FILE(S["job_medsci_high"] , job_medsci_high)
- WRITE_FILE(S["job_medsci_med"] , job_medsci_med)
- WRITE_FILE(S["job_medsci_low"] , job_medsci_low)
- WRITE_FILE(S["job_engsec_high"] , job_engsec_high)
- WRITE_FILE(S["job_engsec_med"] , job_engsec_med)
- WRITE_FILE(S["job_engsec_low"] , job_engsec_low)
+ //Write prefs
+ WRITE_FILE(S["job_preferences"] , job_preferences)
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm
index 1a82d1b406..ee169e9861 100644
--- a/code/modules/food_and_drinks/food/snacks/meat.dm
+++ b/code/modules/food_and_drinks/food/snacks/meat.dm
@@ -108,7 +108,7 @@
tastes = list("maggots" = 1, "the inside of a reactor" = 1)
foodtype = MEAT | RAW | GROSS
-/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth
+/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect
icon_state = "mothmeat"
desc = "Unpleasantly powdery and dry. Kind of pretty, though."
filling_color = "#BF896B"
diff --git a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm
index 4b7b175240..f99bf65071 100644
--- a/code/modules/jobs/job_exp.dm
+++ b/code/modules/jobs/job_exp.dm
@@ -8,6 +8,8 @@ GLOBAL_PROTECT(exp_to_update)
return 0
if(!CONFIG_GET(flag/use_exp_tracking))
return 0
+ if(!SSdbcore.Connect())
+ return 0
if(!exp_requirements || !exp_type)
return 0
if(!job_is_xp_locked(src.title))
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/_job.dm
similarity index 88%
rename from code/modules/jobs/job_types/job.dm
rename to code/modules/jobs/job_types/_job.dm
index 9549b6100c..2eeffa8b7a 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -1,240 +1,245 @@
-/datum/job
- //The name of the job
- var/title = "NOPE"
-
- //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access
- var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population)
- var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!)
-
- //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.
- var/list/head_announce = null
-
- //Bitflags for the job
- var/flag = 0
- var/department_flag = 0
-
- //Players will be allowed to spawn in as jobs that are set to "Station"
- var/faction = "None"
-
- //How many players can be this job
- var/total_positions = 0
-
- //How many players can spawn in as this job
- var/spawn_positions = 0
-
- //How many players have this job
- var/current_positions = 0
-
- //Supervisors, who this person answers to directly
- var/supervisors = ""
-
- //Sellection screen color
- var/selection_color = "#ffffff"
-
-
- //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
-
- var/custom_spawn_text
-
- //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
-
- var/exp_requirements = 0
-
- var/exp_type = ""
- var/exp_type_department = ""
-
- //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round
- //can be overridden by antag_rep.txt config
- var/antag_rep = 10
-
- var/list/mind_traits // Traits added to the mind of the mob assigned this job
-
- var/list/blacklisted_quirks //list of quirk typepaths blacklisted.
-
-//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
- if(mind_traits)
- for(var/t in mind_traits)
- ADD_TRAIT(H.mind, t, JOB_TRAIT)
-
-/datum/job/proc/announce(mob/living/carbon/human/H)
- 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
-
-//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
-
-/datum/job/proc/GetAntagRep()
- . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)]
- if(. == null)
- return antag_rep
-
-//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)
- if(!H)
- return FALSE
-
- if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions))
- if(H.dna.species.id != "human")
- H.set_species(/datum/species/human)
- H.apply_pref_name("human", H.client)
-
- //Equip the rest of the gear
- H.dna.species.before_equip_job(src, H, visualsOnly)
-
- if(outfit_override || outfit)
- H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly)
-
- H.dna.species.after_equip_job(src, H, visualsOnly)
-
- if(!visualsOnly && announce)
- announce(H)
-
-/datum/job/proc/get_access()
- if(!config) //Needed for robots.
- return src.minimal_access.Copy()
-
- . = list()
-
- if(CONFIG_GET(flag/jobs_have_minimal_access))
- . = src.minimal_access.Copy()
- else
- . = src.access.Copy()
-
- if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set
- . |= list(ACCESS_MAINT_TUNNELS)
-
-/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/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)
- return TRUE //Available in 0 days = available right now = player is old enough to play.
- return FALSE
-
-
-/datum/job/proc/available_in_days(client/C)
- if(!C)
- return 0
- if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
- return 0
- if(C.prefs.db_flags & DB_FLAG_EXEMPT)
- return 0
- if(!isnum(C.player_age))
- return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
- if(!isnum(minimal_player_age))
- return 0
-
- return max(0, minimal_player_age - C.player_age)
-
-/datum/job/proc/config_check()
- return TRUE
-
-/datum/job/proc/map_check()
- return TRUE
-
-
-/datum/outfit/job
- name = "Standard Gear"
-
- var/jobtype = null
-
- uniform = /obj/item/clothing/under/color/grey
- id = /obj/item/card/id
- ears = /obj/item/radio/headset
- belt = /obj/item/pda
- back = /obj/item/storage/backpack
- shoes = /obj/item/clothing/shoes/sneakers/black
-
- var/backpack = /obj/item/storage/backpack
- var/satchel = /obj/item/storage/backpack/satchel
- var/duffelbag = /obj/item/storage/backpack/duffelbag
- var/box = /obj/item/storage/box/survival
-
- var/pda_slot = SLOT_BELT
-
-/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- switch(H.backbag)
- if(GBACKPACK)
- back = /obj/item/storage/backpack //Grey backpack
- if(GSATCHEL)
- back = /obj/item/storage/backpack/satchel //Grey satchel
- if(GDUFFELBAG)
- back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag
- if(LSATCHEL)
- back = /obj/item/storage/backpack/satchel/leather //Leather Satchel
- if(DSATCHEL)
- back = satchel //Department satchel
- if(DDUFFELBAG)
- back = duffelbag //Department duffel bag
- else
- back = backpack //Department backpack
-
- if(box)
- if(!backpack_contents)
- backpack_contents = list()
- backpack_contents.Insert(1, box) // Box always takes a first slot in backpack
- backpack_contents[box] = 1
-
- //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant
- var/holder
- if(H.jumpsuit_style == PREF_SKIRT)
- holder = "[uniform]/skirt"
- if(!text2path(holder))
- holder = "[uniform]"
- else
- holder = "[uniform]"
- uniform = text2path(holder)
-
-/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- if(visualsOnly)
- return
-
- var/datum/job/J = SSjob.GetJobType(jobtype)
- if(!J)
- J = SSjob.GetJob(H.job)
-
- if(H.nameless && J.dresscodecompliant)
- if(J.title in GLOB.command_positions)
- H.real_name = J.title
- else
- H.real_name = "[J.title] #[rand(10000, 99999)]"
-
- var/obj/item/card/id/C = H.wear_id
- if(istype(C))
- C.access = J.get_access()
- shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable
- C.registered_name = H.real_name
- C.assignment = J.title
- C.update_label()
- H.sec_hud_set_ID()
-
- var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot)
- if(istype(PDA))
- PDA.owner = H.real_name
- PDA.ownjob = J.title
- PDA.update_label()
-
-/datum/outfit/job/get_chameleon_disguise_info()
- var/list/types = ..()
- types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks
- types += backpack
- types += satchel
- types += duffelbag
- return types
+/datum/job
+ //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"
+
+ //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access
+ var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population)
+ var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!)
+
+ //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.
+ var/list/head_announce = null
+
+ //Bitflags for the job
+ var/flag = NONE //Deprecated
+ var/department_flag = NONE //Deprecated
+// var/auto_deadmin_role_flags = NONE
+
+ //Players will be allowed to spawn in as jobs that are set to "Station"
+ var/faction = "None"
+
+ //How many players can be this job
+ var/total_positions = 0
+
+ //How many players can spawn in as this job
+ var/spawn_positions = 0
+
+ //How many players have this job
+ var/current_positions = 0
+
+ //Supervisors, who this person answers to directly
+ var/supervisors = ""
+
+ //Sellection screen color
+ var/selection_color = "#ffffff"
+
+
+ //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
+
+ // This is for Citadel specific tweaks to job notices.
+ var/custom_spawn_text
+
+ //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
+
+ var/exp_requirements = 0
+
+ var/exp_type = ""
+ var/exp_type_department = ""
+
+ //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round
+ //can be overridden by antag_rep.txt config
+ var/antag_rep = 10
+
+ var/list/mind_traits // Traits added to the mind of the mob assigned this job
+ var/list/blacklisted_quirks //list of quirk typepaths blacklisted.
+
+ var/display_order = JOB_DISPLAY_ORDER_DEFAULT
+
+//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
+ if(mind_traits)
+ for(var/t in mind_traits)
+ ADD_TRAIT(H.mind, t, JOB_TRAIT)
+
+/datum/job/proc/announce(mob/living/carbon/human/H)
+ 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
+
+//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
+
+/datum/job/proc/GetAntagRep()
+ . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)]
+ if(. == null)
+ return antag_rep
+
+//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)
+ if(!H)
+ return FALSE
+
+ if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions))
+ if(H.dna.species.id != "human")
+ H.set_species(/datum/species/human)
+ H.apply_pref_name("human", preference_source)
+
+ //Equip the rest of the gear
+ H.dna.species.before_equip_job(src, H, visualsOnly)
+
+ if(outfit_override || outfit)
+ H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly)
+
+ H.dna.species.after_equip_job(src, H, visualsOnly)
+
+ if(!visualsOnly && announce)
+ announce(H)
+
+/datum/job/proc/get_access()
+ if(!config) //Needed for robots.
+ return src.minimal_access.Copy()
+
+ . = list()
+
+ if(CONFIG_GET(flag/jobs_have_minimal_access))
+ . = src.minimal_access.Copy()
+ else
+ . = src.access.Copy()
+
+ if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set
+ . |= list(ACCESS_MAINT_TUNNELS)
+
+/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/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)
+ return TRUE //Available in 0 days = available right now = player is old enough to play.
+ return FALSE
+
+
+/datum/job/proc/available_in_days(client/C)
+ if(!C)
+ return 0
+ if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
+ return 0
+ if(!SSdbcore.Connect())
+ return 0 //Without a database connection we can't get a player's age so we'll assume they're old enough for all jobs
+ if(C.prefs.db_flags & DB_FLAG_EXEMPT)
+ return 0
+ if(!isnum(minimal_player_age))
+ return 0
+
+ return max(0, minimal_player_age - C.player_age)
+
+/datum/job/proc/config_check()
+ return TRUE
+
+/datum/job/proc/map_check()
+ return TRUE
+
+/datum/job/proc/radio_help_message(mob/M)
+ to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset. ")
+
+/datum/outfit/job
+ name = "Standard Gear"
+
+ var/jobtype = null
+
+ uniform = /obj/item/clothing/under/color/grey
+ id = /obj/item/card/id
+ ears = /obj/item/radio/headset
+ belt = /obj/item/pda
+ back = /obj/item/storage/backpack
+ shoes = /obj/item/clothing/shoes/sneakers/black
+ box = /obj/item/storage/box/survival
+
+ var/backpack = /obj/item/storage/backpack
+ var/satchel = /obj/item/storage/backpack/satchel
+ var/duffelbag = /obj/item/storage/backpack/duffelbag
+
+ var/pda_slot = SLOT_BELT
+
+/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ switch(H.backbag)
+ if(GBACKPACK)
+ back = /obj/item/storage/backpack //Grey backpack
+ if(GSATCHEL)
+ back = /obj/item/storage/backpack/satchel //Grey satchel
+ if(GDUFFELBAG)
+ back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag
+ if(LSATCHEL)
+ back = /obj/item/storage/backpack/satchel/leather //Leather Satchel
+ if(DSATCHEL)
+ back = satchel //Department satchel
+ if(DDUFFELBAG)
+ back = duffelbag //Department duffel bag
+ else
+ back = backpack //Department backpack
+
+ //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant
+ var/holder
+ if(H.jumpsuit_style == PREF_SKIRT)
+ holder = "[uniform]/skirt"
+ if(!text2path(holder))
+ holder = "[uniform]"
+ else
+ holder = "[uniform]"
+ uniform = text2path(holder)
+
+/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ if(visualsOnly)
+ return
+
+ var/datum/job/J = SSjob.GetJobType(jobtype)
+ if(!J)
+ J = SSjob.GetJob(H.job)
+
+ if(H.nameless && J.dresscodecompliant)
+ if(J.title in GLOB.command_positions)
+ H.real_name = J.title
+ else
+ H.real_name = "[J.title] #[rand(10000, 99999)]"
+
+ var/obj/item/card/id/C = H.wear_id
+ if(istype(C))
+ C.access = J.get_access()
+ shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable
+ C.registered_name = H.real_name
+ C.assignment = J.title
+ C.update_label()
+ H.sec_hud_set_ID()
+
+ var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot)
+ if(istype(PDA))
+ PDA.owner = H.real_name
+ PDA.ownjob = J.title
+ PDA.update_label()
+
+/datum/outfit/job/get_chameleon_disguise_info()
+ var/list/types = ..()
+ types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks
+ types += backpack
+ types += satchel
+ types += duffelbag
+ return types
+
+//Warden and regular officers add this result to their get_access()
+/datum/job/proc/check_config_for_sec_maint()
+ if(CONFIG_GET(flag/security_has_maint_access))
+ return list(ACCESS_MAINT_TUNNELS)
+ return list()
diff --git a/code/modules/jobs/job_types/silicon.dm b/code/modules/jobs/job_types/ai.dm
similarity index 71%
rename from code/modules/jobs/job_types/silicon.dm
rename to code/modules/jobs/job_types/ai.dm
index ab963eb8f3..4bcfab5836 100644
--- a/code/modules/jobs/job_types/silicon.dm
+++ b/code/modules/jobs/job_types/ai.dm
@@ -1,90 +1,69 @@
-/*
-AI
-*/
-/datum/job/ai
- title = "AI"
- flag = AI_JF
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- selection_color = "#ccffcc"
- supervisors = "your laws"
- req_admin_notify = TRUE
- minimal_player_age = 30
- exp_requirements = 180
- exp_type = EXP_TYPE_CREW
- exp_type_department = EXP_TYPE_SILICON
- var/do_special_check = TRUE
-
-/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, outfit_override)
- . = H.AIize(latejoin)
-
-/datum/job/ai/after_spawn(mob/H, mob/M, latejoin)
- . = ..()
- if(latejoin)
- var/obj/structure/AIcore/latejoin_inactive/lateJoinCore
- for(var/obj/structure/AIcore/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
- AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked.
- 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/special_check_latejoin(client/C)
- if(!do_special_check)
- return TRUE
- for(var/i in GLOB.latejoin_ai_cores)
- var/obj/structure/AIcore/latejoin_inactive/LAI = i
- if(istype(LAI))
- if(LAI.is_available())
- return TRUE
- return FALSE
-
-/datum/job/ai/announce(mob/living/silicon/ai/AI)
- . = ..()
- SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)]."))
-
-/datum/job/ai/config_check()
- return CONFIG_GET(flag/allow_ai)
-
-/*
-Cyborg
-*/
-/datum/job/cyborg
- title = "Cyborg"
- flag = CYBORG
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 0
- spawn_positions = 1
- supervisors = "your laws and the AI" //Nodrak
- selection_color = "#ddffdd"
- minimal_player_age = 21
- exp_requirements = 120
- exp_type = EXP_TYPE_CREW
-
-/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, outfit_override = null)
- 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/ai
+ title = "AI"
+ flag = AI_JF
+// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ selection_color = "#ccffcc"
+ supervisors = "your laws"
+ req_admin_notify = TRUE
+ minimal_player_age = 30
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_SILICON
+ display_order = JOB_DISPLAY_ORDER_AI
+ 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)
+ . = ..()
+ if(latejoin)
+ var/obj/structure/AIcore/latejoin_inactive/lateJoinCore
+ for(var/obj/structure/AIcore/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
+ AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked.
+ 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/special_check_latejoin(client/C)
+ if(!do_special_check)
+ return TRUE
+ for(var/i in GLOB.latejoin_ai_cores)
+ var/obj/structure/AIcore/latejoin_inactive/LAI = i
+ if(istype(LAI))
+ if(LAI.is_available())
+ return TRUE
+ return FALSE
+
+/datum/job/ai/announce(mob/living/silicon/ai/AI)
+ . = ..()
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)]."))
+
+/datum/job/ai/config_check()
+ return CONFIG_GET(flag/allow_ai)
+
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index ce6eea97b0..c04560f849 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -14,7 +14,7 @@ Assistant
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
antag_rep = 7
-
+ display_order = JOB_DISPLAY_ORDER_ASSISTANT
/datum/job/assistant/get_access()
if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
new file mode 100644
index 0000000000..93775beca9
--- /dev/null
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -0,0 +1,44 @@
+/datum/job/atmos
+ title = "Atmospheric Technician"
+ flag = ATMOSTECH
+ department_head = list("Chief Engineer")
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 3
+ spawn_positions = 2
+ supervisors = "the chief engineer"
+ selection_color = "#ff9b3d"
+ exp_requirements = 60
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/atmos
+
+ access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
+ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM)
+ display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN
+
+/datum/outfit/job/atmos
+ name = "Atmospheric Technician"
+ jobtype = /datum/job/atmos
+
+ belt = /obj/item/storage/belt/utility/atmostech
+ l_pocket = /obj/item/pda/atmos
+ ears = /obj/item/radio/headset/headset_eng
+ uniform = /obj/item/clothing/under/rank/atmospheric_technician
+ r_pocket = /obj/item/analyzer
+
+ backpack = /obj/item/storage/backpack/industrial
+ satchel = /obj/item/storage/backpack/satchel/eng
+ duffelbag = /obj/item/storage/backpack/duffelbag/engineering
+ box = /obj/item/storage/box/engineer
+ pda_slot = SLOT_L_STORE
+ backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
+
+/datum/outfit/job/atmos/rig
+ name = "Atmospheric Technician (Hardsuit)"
+
+ mask = /obj/item/clothing/mask/gas
+ suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos
+ suit_store = /obj/item/tank/internals/oxygen
+ internals_slot = SLOT_S_STORE
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
new file mode 100644
index 0000000000..0ace449757
--- /dev/null
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -0,0 +1,30 @@
+/datum/job/bartender
+ title = "Bartender"
+ flag = BARTENDER
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#bbe291"
+ exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly
+
+ outfit = /datum/outfit/job/bartender
+
+ access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM)
+ display_order = JOB_DISPLAY_ORDER_BARTENDER
+
+/datum/outfit/job/bartender
+ name = "Bartender"
+ jobtype = /datum/job/bartender
+
+ glasses = /obj/item/clothing/glasses/sunglasses/reagent
+ belt = /obj/item/pda/bar
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/bartender
+ suit = /obj/item/clothing/suit/armor/vest
+ backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1)
+ shoes = /obj/item/clothing/shoes/laceup
+
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
new file mode 100644
index 0000000000..e6338d9b0a
--- /dev/null
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -0,0 +1,32 @@
+/datum/job/hydro
+ title = "Botanist"
+ flag = BOTANIST
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 3
+ spawn_positions = 2
+ supervisors = "the head of personnel"
+ selection_color = "#bbe291"
+
+ outfit = /datum/outfit/job/botanist
+
+ access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+ display_order = JOB_DISPLAY_ORDER_BOTANIST
+
+/datum/outfit/job/botanist
+ name = "Botanist"
+ jobtype = /datum/job/hydro
+
+ belt = /obj/item/pda/botanist
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/hydroponics
+ suit = /obj/item/clothing/suit/apron
+ gloves =/obj/item/clothing/gloves/botanic_leather
+ suit_store = /obj/item/plant_analyzer
+
+ backpack = /obj/item/storage/backpack/botany
+ satchel = /obj/item/storage/backpack/satchel/hyd
+
+
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
old mode 100755
new mode 100644
index 58943df4e4..7e832d6975
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -1,20 +1,19 @@
-/*
-Captain
-*/
/datum/job/captain
title = "Captain"
flag = CAPTAIN
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY //:eyes:
department_head = list("CentCom")
department_flag = ENGSEC
faction = "Station"
total_positions = 1
spawn_positions = 1
supervisors = "Nanotrasen officials and Space law"
- selection_color = "#ccccff"
+ selection_color = "#aac1ee"
req_admin_notify = 1
minimal_player_age = 14
exp_requirements = 180
exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_COMMAND
outfit = /datum/outfit/job/captain
@@ -22,6 +21,9 @@ Captain
minimal_access = list() //See get_access()
mind_traits = list(TRAIT_CAPTAIN_METABOLISM)
+// mind_traits = list(TRAIT_DISK_VERIFIER)
+
+ display_order = JOB_DISPLAY_ORDER_CAPTAIN
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
@@ -62,55 +64,3 @@ Captain
mask = /obj/item/clothing/mask/gas/sechailer
suit = /obj/item/clothing/suit/space/hardsuit/captain
suit_store = /obj/item/tank/internals/oxygen
-
-/*
-Head of Personnel
-*/
-/datum/job/hop
- title = "Head of Personnel"
- flag = HOP
- department_head = list("Captain")
- department_flag = CIVILIAN
- head_announce = list(RADIO_CHANNEL_SERVICE)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the captain"
- selection_color = "#ddddff"
- req_admin_notify = 1
- minimal_player_age = 10
- exp_requirements = 180
- exp_type = EXP_TYPE_CREW
- exp_type_department = EXP_TYPE_SUPPLY
-
- outfit = /datum/outfit/job/hop
-
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
- ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
- ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
- ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
- ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
- ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
- ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
- ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
- ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
-
-/datum/outfit/job/hop
- name = "Head of Personnel"
- jobtype = /datum/job/hop
-
- id = /obj/item/card/id/silver
- belt = /obj/item/pda/heads/hop
- ears = /obj/item/radio/headset/heads/hop
- uniform = /obj/item/clothing/under/rank/head_of_personnel
- shoes = /obj/item/clothing/shoes/sneakers/brown
- head = /obj/item/clothing/head/hopcap
- backpack_contents = list(/obj/item/storage/box/ids=1,\
- /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
-
- chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
diff --git a/code/modules/jobs/job_types/cargo_service.dm b/code/modules/jobs/job_types/cargo_service.dm
deleted file mode 100644
index 8e24ece655..0000000000
--- a/code/modules/jobs/job_types/cargo_service.dm
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
-Quartermaster
-*/
-/datum/job/qm
- title = "Quartermaster"
- flag = QUARTERMASTER
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- head_announce = list(RADIO_CHANNEL_SUPPLY)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#d7b088"
-
- outfit = /datum/outfit/job/quartermaster
-
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
- minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
-
-/datum/outfit/job/quartermaster
- name = "Quartermaster"
- jobtype = /datum/job/qm
-
- belt = /obj/item/pda/quartermaster
- ears = /obj/item/radio/headset/headset_cargo
- uniform = /obj/item/clothing/under/rank/cargo
- shoes = /obj/item/clothing/shoes/sneakers/brown
- glasses = /obj/item/clothing/glasses/sunglasses
- l_hand = /obj/item/clipboard
-
- chameleon_extras = /obj/item/stamp/qm
-
-/*
-Cargo Technician
-*/
-/datum/job/cargo_tech
- title = "Cargo Technician"
- flag = CARGOTECH
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 3
- spawn_positions = 2
- supervisors = "the quartermaster and the head of personnel"
- selection_color = "#dcba97"
-
- outfit = /datum/outfit/job/cargo_tech
-
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/cargo_tech
- name = "Cargo Technician"
- jobtype = /datum/job/cargo_tech
-
- belt = /obj/item/pda/cargo
- ears = /obj/item/radio/headset/headset_cargo
- uniform = /obj/item/clothing/under/rank/cargotech
- l_hand = /obj/item/export_scanner
-
-/*
-Shaft Miner
-*/
-/datum/job/mining
- title = "Shaft Miner"
- flag = MINER
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 3
- spawn_positions = 3
- supervisors = "the quartermaster and the head of personnel"
- selection_color = "#dcba97"
- custom_spawn_text = "Remember, you are a miner, not a hunter. Hunting monsters is not a requirement of your job, the only requirement of your job is to provide materials for the station. Don't be afraid to run away if you're inexperienced with fighting the mining area's locals."
-
- outfit = /datum/outfit/job/miner
-
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/miner
- name = "Shaft Miner (Lavaland)"
- jobtype = /datum/job/mining
-
- belt = /obj/item/pda/shaftminer
- ears = /obj/item/radio/headset/headset_cargo/mining
- shoes = /obj/item/clothing/shoes/workboots/mining
- gloves = /obj/item/clothing/gloves/color/black
- uniform = /obj/item/clothing/under/rank/miner/lavaland
- l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival
- r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack
- backpack_contents = list(
- /obj/item/flashlight/seclite=1,\
- /obj/item/kitchen/knife/combat/survival=1,\
- /obj/item/mining_voucher=1,\
- /obj/item/suit_voucher=1,\
- /obj/item/stack/marker_beacon/ten=1)
-
- backpack = /obj/item/storage/backpack/explorer
- satchel = /obj/item/storage/backpack/satchel/explorer
- duffelbag = /obj/item/storage/backpack/duffelbag
- box = /obj/item/storage/box/survival_mining
-
- chameleon_extras = /obj/item/gun/energy/kinetic_accelerator
-
-/datum/outfit/job/miner/asteroid
- name = "Shaft Miner (Asteroid)"
- uniform = /obj/item/clothing/under/rank/miner
- shoes = /obj/item/clothing/shoes/workboots
-
-/datum/outfit/job/miner/equipped
- name = "Shaft Miner (Lavaland + Equipment)"
- suit = /obj/item/clothing/suit/hooded/explorer/standard
- mask = /obj/item/clothing/mask/gas/explorer
- glasses = /obj/item/clothing/glasses/meson
- suit_store = /obj/item/tank/internals/oxygen
- internals_slot = SLOT_S_STORE
- backpack_contents = list(
- /obj/item/flashlight/seclite=1,\
- /obj/item/kitchen/knife/combat/survival=1,
- /obj/item/mining_voucher=1,
- /obj/item/t_scanner/adv_mining_scanner/lesser=1,
- /obj/item/gun/energy/kinetic_accelerator=1,\
- /obj/item/stack/marker_beacon/ten=1)
-
-/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
- if(istype(H.wear_suit, /obj/item/clothing/suit/hooded))
- var/obj/item/clothing/suit/hooded/S = H.wear_suit
- S.ToggleHood()
-
-/datum/outfit/job/miner/equipped/hardsuit
- name = "Shaft Miner (Equipment + Hardsuit)"
- suit = /obj/item/clothing/suit/space/hardsuit/mining
- mask = /obj/item/clothing/mask/breath
-
-
-/*
-Bartender
-*/
-/datum/job/bartender
- title = "Bartender"
- flag = BARTENDER
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#bbe291"
-
- outfit = /datum/outfit/job/bartender
-
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM)
-
-
-/datum/outfit/job/bartender
- name = "Bartender"
- jobtype = /datum/job/bartender
-
- glasses = /obj/item/clothing/glasses/sunglasses/reagent
- belt = /obj/item/pda/bar
- ears = /obj/item/radio/headset/headset_srv
- uniform = /obj/item/clothing/under/rank/bartender
- suit = /obj/item/clothing/suit/armor/vest
- backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1)
- shoes = /obj/item/clothing/shoes/laceup
-
-/*
-Cook
-*/
-/datum/job/cook
- title = "Cook"
- flag = COOK
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 2
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#bbe291"
- var/cooks = 0 //Counts cooks amount
-
- outfit = /datum/outfit/job/cook
-
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/cook
- name = "Cook"
- jobtype = /datum/job/cook
-
- belt = /obj/item/pda/cook
- ears = /obj/item/radio/headset/headset_srv
- uniform = /obj/item/clothing/under/rank/chef
- suit = /obj/item/clothing/suit/toggle/chef
- head = /obj/item/clothing/head/chefhat
- mask = /obj/item/clothing/mask/fakemoustache/italian
- backpack_contents = list(/obj/item/sharpener = 1)
-
-/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- var/datum/job/cook/J = SSjob.GetJobType(jobtype)
- if(J) // Fix for runtime caused by invalid job being passed
- if(J.cooks>0)//Cooks
- suit = /obj/item/clothing/suit/apron/chef
- head = /obj/item/clothing/head/soft/mime
- if(!visualsOnly)
- J.cooks++
-
-/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
- var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients)
- var/chosen_box = pick(possible_boxes)
- var/obj/item/storage/box/I = new chosen_box(src)
- H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK)
- var/datum/martial_art/cqc/under_siege/justacook = new
- justacook.teach(H)
-
-/*
-Botanist
-*/
-/datum/job/hydro
- title = "Botanist"
- flag = BOTANIST
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 3
- spawn_positions = 2
- supervisors = "the head of personnel"
- selection_color = "#bbe291"
-
- outfit = /datum/outfit/job/botanist
-
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
- // Removed tox and chem access because STOP PISSING OFF THE CHEMIST GUYS
- // Removed medical access because WHAT THE FUCK YOU AREN'T A DOCTOR YOU GROW WHEAT
- // Given Morgue access because they have a viable means of cloning.
-
-
-/datum/outfit/job/botanist
- name = "Botanist"
- jobtype = /datum/job/hydro
-
- belt = /obj/item/pda/botanist
- ears = /obj/item/radio/headset/headset_srv
- uniform = /obj/item/clothing/under/rank/hydroponics
- suit = /obj/item/clothing/suit/apron
- gloves =/obj/item/clothing/gloves/botanic_leather
- suit_store = /obj/item/plant_analyzer
-
- backpack = /obj/item/storage/backpack/botany
- satchel = /obj/item/storage/backpack/satchel/hyd
-
-
-/*
-Janitor
-*/
-/datum/job/janitor
- title = "Janitor"
- flag = JANITOR
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 2
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#bbe291"
- var/global/janitors = 0
-
- outfit = /datum/outfit/job/janitor
-
- access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/janitor
- name = "Janitor"
- jobtype = /datum/job/janitor
-
- belt = /obj/item/pda/janitor
- ears = /obj/item/radio/headset/headset_srv
- uniform = /obj/item/clothing/under/rank/janitor
- backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
new file mode 100644
index 0000000000..3ceb29bae2
--- /dev/null
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -0,0 +1,27 @@
+/datum/job/cargo_tech
+ title = "Cargo Technician"
+ flag = CARGOTECH
+ department_head = list("Quartermaster")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 3
+ spawn_positions = 2
+ supervisors = "the quartermaster"
+ selection_color = "#ca8f55"
+
+ outfit = /datum/outfit/job/cargo_tech
+
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN
+
+/datum/outfit/job/cargo_tech
+ name = "Cargo Technician"
+ jobtype = /datum/job/cargo_tech
+
+ belt = /obj/item/pda/cargo
+ ears = /obj/item/radio/headset/headset_cargo
+ uniform = /obj/item/clothing/under/rank/cargotech
+ l_hand = /obj/item/export_scanner
+
diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
similarity index 66%
rename from code/modules/jobs/job_types/civilian_chaplain.dm
rename to code/modules/jobs/job_types/chaplain.dm
index 2d190cfe60..f6648fdf86 100644
--- a/code/modules/jobs/job_types/civilian_chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -1,95 +1,121 @@
-//Due to how large this one is it gets its own file
-/*
-Chaplain
-*/
-/datum/job/chaplain
- title = "Chaplain"
- flag = CHAPLAIN
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#dddddd"
-
- outfit = /datum/outfit/job/chaplain
-
- access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
- minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
-
-/datum/job/chaplain/after_spawn(mob/living/H, mob/M)
- . = ..()
- if(H.mind)
- H.mind.isholy = TRUE
-
- var/obj/item/storage/book/bible/booze/B = new
-
- if(GLOB.religion)
- B.deity_name = GLOB.deity
- B.name = GLOB.bible_name
- B.icon_state = GLOB.bible_icon_state
- B.item_state = GLOB.bible_item_state
- to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.")
- H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
- var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod
- var/obj/item/nullrod/N = new nrt(H)
- H.put_in_hands(N)
- return
-
- var/new_religion = "Christianity"
- if(M.client && M.client.prefs.custom_names["religion"])
- new_religion = M.client.prefs.custom_names["religion"]
-
- var/new_deity = "Space Jesus"
- if(M.client && M.client.prefs.custom_names["deity"])
- new_deity = M.client.prefs.custom_names["deity"]
-
- B.deity_name = new_deity
-
-
- switch(lowertext(new_religion))
- if("christianity")
- B.name = pick("The Holy Bible","The Dead Sea Scrolls")
- if("satanism")
- B.name = "The Unholy Bible"
- if("cthulhu")
- B.name = "The Necronomicon"
- if("islam")
- B.name = "Quran"
- if("scientology")
- B.name = pick("The Biography of L. Ron Hubbard","Dianetics")
- if("chaos")
- B.name = "The Book of Lorgar"
- if("imperium")
- B.name = "Uplifting Primer"
- if("toolboxia")
- B.name = "Toolbox Manifesto"
- if("homosexuality")
- B.name = "Guys Gone Wild"
- if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes")
- B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition")
- H.adjustBrainLoss(100) // starts off retarded as fuck
- if("science")
- B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition")
- else
- B.name = "The Holy Book of [new_religion]"
-
- GLOB.religion = new_religion
- GLOB.bible_name = B.name
- GLOB.deity = B.deity_name
-
- H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
-
- SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1)
- SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1)
-
-/datum/outfit/job/chaplain
- name = "Chaplain"
- jobtype = /datum/job/chaplain
-
- belt = /obj/item/pda/chaplain
- uniform = /obj/item/clothing/under/rank/chaplain
- backpack_contents = list(/obj/item/camera/spooky = 1)
- backpack = /obj/item/storage/backpack/cultpack
- satchel = /obj/item/storage/backpack/cultpack
+/datum/job/chaplain
+ title = "Chaplain"
+ flag = CHAPLAIN
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+
+ outfit = /datum/outfit/job/chaplain
+
+ access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
+ minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
+
+ display_order = JOB_DISPLAY_ORDER_CHAPLAIN
+
+
+/datum/job/chaplain/after_spawn(mob/living/H, mob/M)
+ . = ..()
+ if(H.mind)
+ H.mind.isholy = TRUE
+
+ var/obj/item/storage/book/bible/booze/B = new
+
+ if(GLOB.religion)
+ B.deity_name = GLOB.deity
+ B.name = GLOB.bible_name
+ B.icon_state = GLOB.bible_icon_state
+ B.item_state = GLOB.bible_item_state
+ to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain.")
+ H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
+ var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod
+ var/obj/item/nullrod/N = new nrt(H)
+ H.put_in_hands(N)
+ return
+
+ var/new_religion = DEFAULT_RELIGION
+ if(M.client && M.client.prefs.custom_names["religion"])
+ new_religion = M.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"]
+
+ B.deity_name = new_deity
+
+
+ switch(lowertext(new_religion))
+ if("christianity") // DEFAULT_RELIGION
+ B.name = pick("The Holy Bible","The Dead Sea Scrolls")
+ if("buddhism")
+ B.name = "The Sutras"
+ if("clownism","honkmother","honk","honkism","comedy")
+ B.name = pick("The Holy Joke Book", "Just a Prank", "Hymns to the Honkmother")
+ if("chaos")
+ B.name = "The Book of Lorgar"
+ if("cthulhu")
+ B.name = "The Necronomicon"
+ if("hinduism")
+ B.name = "The Vedas"
+ if("homosexuality")
+ B.name = pick("Guys Gone Wild","Coming Out of The Closet")
+ if("imperium")
+ B.name = "Uplifting Primer"
+ if("islam")
+ B.name = "Quran"
+ if("judaism")
+ B.name = "The Torah"
+ if("lampism")
+ B.name = "Fluorescent Incandescence"
+ if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes")
+ B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition","F.A.T.A.L. Rulebook")
+ H.adjustBrainLoss(100) // starts off retarded as fuck
+ if("monkeyism","apism","gorillism","primatism")
+ B.name = pick("Going Bananas", "Bananas Out For Harambe")
+ if("mormonism")
+ B.name = "The Book of Mormon"
+ if("pastafarianism")
+ B.name = "The Gospel of the Flying Spaghetti Monster"
+ if("rastafarianism","rasta")
+ B.name = "The Holy Piby"
+ if("satanism")
+ B.name = "The Unholy Bible"
+ if("science")
+ B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition")
+ if("scientology")
+ B.name = pick("The Biography of L. Ron Hubbard","Dianetics")
+ if("servicianism", "partying")
+ B.name = "The Tenets of Servicia"
+ B.deity_name = pick("Servicia", "Space Bacchus", "Space Dionysus")
+ B.desc = "Happy, Full, Clean. Live it and give it."
+ if("subgenius")
+ B.name = "Book of the SubGenius"
+ if("toolboxia","greytide")
+ B.name = pick("Toolbox Manifesto","iGlove Assistants")
+ if("weeaboo","kawaii")
+ B.name = pick("Fanfiction Compendium","Japanese for Dummies","The Manganomicon","Establishing Your O.T.P")
+ else
+ B.name = "The Holy Book of [new_religion]"
+
+ GLOB.religion = new_religion
+ GLOB.bible_name = B.name
+ GLOB.deity = B.deity_name
+
+ H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK)
+
+ SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1)
+ SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1)
+
+/datum/outfit/job/chaplain
+ name = "Chaplain"
+ jobtype = /datum/job/chaplain
+
+ belt = /obj/item/pda/chaplain
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/chaplain
+ backpack_contents = list(/obj/item/camera/spooky = 1)
+ backpack = /obj/item/storage/backpack/cultpack
+ satchel = /obj/item/storage/backpack/cultpack
\ No newline at end of file
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
new file mode 100644
index 0000000000..a915d261ed
--- /dev/null
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -0,0 +1,36 @@
+/datum/job/chemist
+ title = "Chemist"
+ flag = CHEMIST
+ department_head = list("Chief Medical Officer")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the chief medical officer"
+ selection_color = "#74b5e0"
+ exp_type = EXP_TYPE_CREW
+ exp_requirements = 60
+
+ outfit = /datum/outfit/job/chemist
+
+ access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_CHEMIST
+
+/datum/outfit/job/chemist
+ name = "Chemist"
+ jobtype = /datum/job/chemist
+
+ glasses = /obj/item/clothing/glasses/science
+ belt = /obj/item/pda/chemist
+ ears = /obj/item/radio/headset/headset_med
+ uniform = /obj/item/clothing/under/rank/chemist
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ suit = /obj/item/clothing/suit/toggle/labcoat/chemist
+ backpack = /obj/item/storage/backpack/chemistry
+ satchel = /obj/item/storage/backpack/satchel/chem
+ duffelbag = /obj/item/storage/backpack/duffelbag/med
+
+ chameleon_extras = /obj/item/gun/syringe
+
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
new file mode 100644
index 0000000000..da3f281267
--- /dev/null
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -0,0 +1,64 @@
+/datum/job/chief_engineer
+ title = "Chief Engineer"
+ flag = CHIEF
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
+ department_head = list("Captain")
+ department_flag = ENGSEC
+ head_announce = list(RADIO_CHANNEL_ENGINEERING)
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#ee7400"
+ req_admin_notify = 1
+ minimal_player_age = 7
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_ENGINEERING
+
+ outfit = /datum/outfit/job/ce
+
+ access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
+ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA,
+ ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
+ ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
+ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA,
+ ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
+ ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
+
+/datum/outfit/job/ce
+ name = "Chief Engineer"
+ jobtype = /datum/job/chief_engineer
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/storage/belt/utility/chief/full
+ l_pocket = /obj/item/pda/heads/ce
+ ears = /obj/item/radio/headset/heads/ce
+ uniform = /obj/item/clothing/under/rank/chief_engineer
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ head = /obj/item/clothing/head/hardhat/white
+ gloves = /obj/item/clothing/gloves/color/black/ce
+ backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1)
+
+ backpack = /obj/item/storage/backpack/industrial
+ satchel = /obj/item/storage/backpack/satchel/eng
+ duffelbag = /obj/item/storage/backpack/duffelbag/engineering
+ box = /obj/item/storage/box/engineer
+ pda_slot = SLOT_L_STORE
+ chameleon_extras = /obj/item/stamp/ce
+
+/datum/outfit/job/ce/rig
+ name = "Chief Engineer (Hardsuit)"
+
+ mask = /obj/item/clothing/mask/breath
+ suit = /obj/item/clothing/suit/space/hardsuit/engine/elite
+ shoes = /obj/item/clothing/shoes/magboots/advance
+ suit_store = /obj/item/tank/internals/oxygen
+ glasses = /obj/item/clothing/glasses/meson/engine
+ gloves = /obj/item/clothing/gloves/color/yellow
+ head = null
+ internals_slot = SLOT_S_STORE
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
new file mode 100644
index 0000000000..4c7249f048
--- /dev/null
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -0,0 +1,59 @@
+/datum/job/cmo
+ title = "Chief Medical Officer"
+ flag = CMO_JF
+ department_head = list("Captain")
+ department_flag = MEDSCI
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
+ head_announce = list(RADIO_CHANNEL_MEDICAL)
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#509ed1"
+ req_admin_notify = 1
+ minimal_player_age = 7
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_MEDICAL
+
+ outfit = /datum/outfit/job/cmo
+
+ access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
+ ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
+ ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
+ minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
+ ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
+ ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
+
+ display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
+/datum/outfit/job/cmo
+ name = "Chief Medical Officer"
+ jobtype = /datum/job/cmo
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/pda/heads/cmo
+ l_pocket = /obj/item/pinpointer/crew
+ ears = /obj/item/radio/headset/heads/cmo
+ uniform = /obj/item/clothing/under/rank/chief_medical_officer
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ suit = /obj/item/clothing/suit/toggle/labcoat/cmo
+ l_hand = /obj/item/storage/firstaid/regular
+ suit_store = /obj/item/flashlight/pen
+ backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1)
+
+ backpack = /obj/item/storage/backpack/medic
+ satchel = /obj/item/storage/backpack/satchel/med
+ duffelbag = /obj/item/storage/backpack/duffelbag/med
+
+ chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo)
+
+/datum/outfit/job/cmo/hardsuit
+ name = "Chief Medical Officer (Hardsuit)"
+
+ mask = /obj/item/clothing/mask/breath
+ suit = /obj/item/clothing/suit/space/hardsuit/medical
+ suit_store = /obj/item/tank/internals/oxygen
+ r_pocket = /obj/item/flashlight/pen
+
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
deleted file mode 100644
index f21ff69e8e..0000000000
--- a/code/modules/jobs/job_types/civilian.dm
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
-Clown
-*/
-/datum/job/clown
- title = "Clown"
- flag = CLOWN
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#dddddd"
-
- outfit = /datum/outfit/job/clown
-
- access = list(ACCESS_THEATRE)
- minimal_access = list(ACCESS_THEATRE)
-
-/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
- . = ..()
- H.apply_pref_name("clown", M.client)
-
-/datum/outfit/job/clown
- name = "Clown"
- jobtype = /datum/job/clown
-
- belt = /obj/item/pda/clown
- uniform = /obj/item/clothing/under/rank/clown
- shoes = /obj/item/clothing/shoes/clown_shoes
- mask = /obj/item/clothing/mask/gas/clown_hat
- l_pocket = /obj/item/bikehorn
- backpack_contents = list(
- /obj/item/stamp/clown = 1,
- /obj/item/reagent_containers/spray/waterflower = 1,
- /obj/item/reagent_containers/food/snacks/grown/banana = 1,
- /obj/item/instrument/bikehorn = 1,
- )
-
- implants = list(/obj/item/implant/sad_trombone)
-
- backpack = /obj/item/storage/backpack/clown
- satchel = /obj/item/storage/backpack/clown
- duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel
-
- box = /obj/item/storage/box/hug/survival
-
- chameleon_extras = /obj/item/stamp/clown
-
-
-/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
-
- H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names))
-
-/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
-
- H.dna.add_mutation(CLOWNMUT)
- H.dna.add_mutation(SMILE)
-
-/*
-Mime
-*/
-/datum/job/mime
- title = "Mime"
- flag = MIME
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#dddddd"
-
- outfit = /datum/outfit/job/mime
-
- access = list(ACCESS_THEATRE)
- minimal_access = list(ACCESS_THEATRE)
-
-/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
- H.apply_pref_name("mime", M.client)
-
-/datum/outfit/job/mime
- name = "Mime"
- jobtype = /datum/job/mime
-
- belt = /obj/item/pda/mime
- uniform = /obj/item/clothing/under/rank/mime
- mask = /obj/item/clothing/mask/gas/mime
- gloves = /obj/item/clothing/gloves/color/white
- head = /obj/item/clothing/head/frenchberet
- suit = /obj/item/clothing/suit/suspenders
- backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1)
-
- accessory = /obj/item/clothing/accessory/pocketprotector/cosmetology
- backpack = /obj/item/storage/backpack/mime
- satchel = /obj/item/storage/backpack/mime
-
-
-/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
-
- if(visualsOnly)
- return
-
- if(H.mind)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
- H.mind.miming = 1
-
-/*
-Curator
-*/
-/datum/job/curator
- title = "Curator"
- flag = CURATOR
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of personnel"
- selection_color = "#dddddd"
-
- outfit = /datum/outfit/job/curator
-
- access = list(ACCESS_LIBRARY)
- minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION,ACCESS_MINING_STATION)
-
-/datum/outfit/job/curator
- name = "Curator"
- jobtype = /datum/job/curator
-
- belt = /obj/item/pda/curator
- uniform = /obj/item/clothing/under/rank/curator
- l_hand = /obj/item/storage/bag/books
- r_pocket = /obj/item/key/displaycase
- l_pocket = /obj/item/laser_pointer
- accessory = /obj/item/clothing/accessory/pocketprotector/full
- backpack_contents = list(
- /obj/item/melee/curator_whip = 1,
- /obj/item/soapstone = 1,
- /obj/item/barcodescanner = 1
- )
-
-
-/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
-
- if(visualsOnly)
- return
-
- H.grant_all_languages(omnitongue=TRUE)
-/*
-Lawyer
-*/
-/datum/job/lawyer
- title = "Lawyer"
- flag = LAWYER
- department_head = list("Head of Personnel")
- department_flag = CIVILIAN
- faction = "Station"
- total_positions = 2
- spawn_positions = 2
- supervisors = "the head of personnel"
- selection_color = "#dddddd"
- var/lawyers = 0 //Counts lawyer amount
-
- outfit = /datum/outfit/job/lawyer
-
- access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
- minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
-
- mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
-
-/datum/outfit/job/lawyer
- name = "Lawyer"
- jobtype = /datum/job/lawyer
-
- belt = /obj/item/pda/lawyer
- ears = /obj/item/radio/headset/headset_sec
- uniform = /obj/item/clothing/under/lawyer/bluesuit
- suit = /obj/item/clothing/suit/toggle/lawyer
- shoes = /obj/item/clothing/shoes/laceup
- l_hand = /obj/item/storage/briefcase/lawyer
- l_pocket = /obj/item/laser_pointer
- r_pocket = /obj/item/clothing/accessory/lawyers_badge
-
- chameleon_extras = /obj/item/stamp/law
-
-
-/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
-
- var/datum/job/lawyer/J = SSjob.GetJobType(jobtype)
- J.lawyers++
- if(J.lawyers>1)
- uniform = /obj/item/clothing/under/lawyer/purpsuit
- suit = /obj/item/clothing/suit/toggle/lawyer/purple
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
new file mode 100644
index 0000000000..d8b88ae871
--- /dev/null
+++ b/code/modules/jobs/job_types/clown.dm
@@ -0,0 +1,58 @@
+/datum/job/clown
+ title = "Clown"
+ flag = CLOWN
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+
+ outfit = /datum/outfit/job/clown
+
+ access = list(ACCESS_THEATRE)
+ minimal_access = list(ACCESS_THEATRE)
+
+ display_order = JOB_DISPLAY_ORDER_CLOWN
+
+
+/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
+ . = ..()
+ H.apply_pref_name("clown", M.client)
+
+/datum/outfit/job/clown
+ name = "Clown"
+ jobtype = /datum/job/clown
+
+ belt = /obj/item/pda/clown
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/clown
+ shoes = /obj/item/clothing/shoes/clown_shoes
+ mask = /obj/item/clothing/mask/gas/clown_hat
+ l_pocket = /obj/item/bikehorn
+ backpack_contents = list(
+ /obj/item/stamp/clown = 1,
+ /obj/item/reagent_containers/spray/waterflower = 1,
+ /obj/item/reagent_containers/food/snacks/grown/banana = 1,
+ /obj/item/instrument/bikehorn = 1,
+ )
+
+ implants = list(/obj/item/implant/sad_trombone)
+
+ backpack = /obj/item/storage/backpack/clown
+ satchel = /obj/item/storage/backpack/clown
+ duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel
+
+ box = /obj/item/storage/box/hug/survival
+
+ chameleon_extras = /obj/item/stamp/clown
+
+/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ if(visualsOnly)
+ return
+
+ H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) //rename the mob AFTER they're equipped so their ID gets updated properly.
+ H.dna.add_mutation(CLOWNMUT)
+ H.dna.add_mutation(SMILE)
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
new file mode 100644
index 0000000000..c213d4dffc
--- /dev/null
+++ b/code/modules/jobs/job_types/cook.dm
@@ -0,0 +1,52 @@
+/datum/job/cook
+ title = "Cook"
+ flag = COOK
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#bbe291"
+ var/cooks = 0 //Counts cooks amount
+
+ outfit = /datum/outfit/job/cook
+
+ access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_COOK
+
+/datum/outfit/job/cook
+ name = "Cook"
+ jobtype = /datum/job/cook
+
+ belt = /obj/item/pda/cook
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/chef
+ suit = /obj/item/clothing/suit/toggle/chef
+ head = /obj/item/clothing/head/chefhat
+ mask = /obj/item/clothing/mask/fakemoustache/italian
+ backpack_contents = list(/obj/item/sharpener = 1)
+
+/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ var/datum/job/cook/J = SSjob.GetJobType(jobtype)
+ if(J) // Fix for runtime caused by invalid job being passed
+ if(J.cooks>0)//Cooks
+ suit = /obj/item/clothing/suit/apron/chef
+ head = /obj/item/clothing/head/soft/mime
+ if(!visualsOnly)
+ J.cooks++
+
+/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ if(visualsOnly)
+ return
+ var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients)
+ var/chosen_box = pick(possible_boxes)
+ var/obj/item/storage/box/I = new chosen_box(src)
+ H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK)
+ var/datum/martial_art/cqc/under_siege/justacook = new
+ justacook.teach(H)
+
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
new file mode 100644
index 0000000000..35fa8483d5
--- /dev/null
+++ b/code/modules/jobs/job_types/curator.dm
@@ -0,0 +1,43 @@
+/datum/job/curator
+ title = "Curator"
+ flag = CURATOR
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+
+ outfit = /datum/outfit/job/curator
+
+ access = list(ACCESS_LIBRARY)
+ minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION)
+
+ display_order = JOB_DISPLAY_ORDER_CURATOR
+
+/datum/outfit/job/curator
+ name = "Curator"
+ jobtype = /datum/job/curator
+
+ shoes = /obj/item/clothing/shoes/laceup
+ belt = /obj/item/pda/curator
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/curator
+ l_hand = /obj/item/storage/bag/books
+ r_pocket = /obj/item/key/displaycase
+ l_pocket = /obj/item/laser_pointer
+ accessory = /obj/item/clothing/accessory/pocketprotector/full
+ backpack_contents = list(
+ /obj/item/melee/curator_whip = 1,
+ /obj/item/soapstone = 1,
+ /obj/item/barcodescanner = 1
+ )
+
+/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+
+ if(visualsOnly)
+ return
+
+ H.grant_all_languages(omnitongue=TRUE)
diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm
new file mode 100644
index 0000000000..29c4c3d833
--- /dev/null
+++ b/code/modules/jobs/job_types/cyborg.dm
@@ -0,0 +1,27 @@
+/datum/job/cyborg
+ title = "Cyborg"
+ flag = CYBORG
+// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 0
+ spawn_positions = 1
+ supervisors = "your laws and the AI" //Nodrak
+ selection_color = "#ddffdd"
+ minimal_player_age = 21
+ exp_requirements = 120
+ exp_type = EXP_TYPE_CREW
+
+ display_order = JOB_DISPLAY_ORDER_CYBORG
+
+/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/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
new file mode 100644
index 0000000000..27a54fbd1f
--- /dev/null
+++ b/code/modules/jobs/job_types/detective.dm
@@ -0,0 +1,57 @@
+/datum/job/detective
+ title = "Detective"
+ flag = DETECTIVE
+// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY
+ department_head = list("Head of Security")
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of security"
+ selection_color = "#c02f2f"
+ minimal_player_age = 7
+ exp_requirements = 300
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/detective
+
+ access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
+
+ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ display_order = JOB_DISPLAY_ORDER_DETECTIVE
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
+
+/datum/outfit/job/detective
+ name = "Detective"
+ jobtype = /datum/job/detective
+
+ belt = /obj/item/pda/detective
+ ears = /obj/item/radio/headset/headset_sec/alt
+ uniform = /obj/item/clothing/under/rank/det
+ neck = /obj/item/clothing/neck/tie/black
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ suit = /obj/item/clothing/suit/det_suit
+ gloves = /obj/item/clothing/gloves/color/black
+ head = /obj/item/clothing/head/fedora/det_hat
+ l_pocket = /obj/item/toy/crayon/white
+ r_pocket = /obj/item/lighter
+ backpack_contents = list(/obj/item/storage/box/evidence=1,\
+ /obj/item/detective_scanner=1,\
+ /obj/item/melee/classic_baton=1)
+ mask = /obj/item/clothing/mask/cigarette
+
+ implants = list(/obj/item/implant/mindshield)
+
+ chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses)
+
+/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
+ if(istype(cig)) //Some species specfic changes can mess this up (plasmamen)
+ cig.light("")
+
+ if(visualsOnly)
+ return
+
diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm
deleted file mode 100644
index e65cbab1bd..0000000000
--- a/code/modules/jobs/job_types/engineering.dm
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-Chief Engineer
-*/
-/datum/job/chief_engineer
- title = "Chief Engineer"
- flag = CHIEF
- department_head = list("Captain")
- department_flag = ENGSEC
- head_announce = list(RADIO_CHANNEL_ENGINEERING)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the captain"
- selection_color = "#ffeeaa"
- req_admin_notify = 1
- minimal_player_age = 7
- exp_requirements = 180
- exp_type = EXP_TYPE_CREW
- exp_type_department = EXP_TYPE_ENGINEERING
-
- outfit = /datum/outfit/job/ce
-
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA,
- ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
- ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA,
- ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
- ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
-
-/datum/outfit/job/ce
- name = "Chief Engineer"
- jobtype = /datum/job/chief_engineer
-
- id = /obj/item/card/id/silver
- belt = /obj/item/storage/belt/utility/chief/full
- l_pocket = /obj/item/pda/heads/ce
- ears = /obj/item/radio/headset/heads/ce
- uniform = /obj/item/clothing/under/rank/chief_engineer
- shoes = /obj/item/clothing/shoes/sneakers/brown
- head = /obj/item/clothing/head/hardhat/white
- gloves = /obj/item/clothing/gloves/color/black/ce
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1)
-
- backpack = /obj/item/storage/backpack/industrial
- satchel = /obj/item/storage/backpack/satchel/eng
- duffelbag = /obj/item/storage/backpack/duffelbag/engineering
- box = /obj/item/storage/box/engineer
- pda_slot = SLOT_L_STORE
- chameleon_extras = /obj/item/stamp/ce
-
-/datum/outfit/job/ce/rig
- name = "Chief Engineer (Hardsuit)"
-
- mask = /obj/item/clothing/mask/breath
- suit = /obj/item/clothing/suit/space/hardsuit/engine/elite
- shoes = /obj/item/clothing/shoes/magboots/advance
- suit_store = /obj/item/tank/internals/oxygen
- glasses = /obj/item/clothing/glasses/meson/engine
- gloves = /obj/item/clothing/gloves/color/yellow
- head = null
- internals_slot = SLOT_S_STORE
-
-
-/*
-Station Engineer
-*/
-/datum/job/engineer
- title = "Station Engineer"
- flag = ENGINEER
- department_head = list("Chief Engineer")
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 5
- spawn_positions = 5
- supervisors = "the chief engineer"
- selection_color = "#fff5cc"
- exp_requirements = 60
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/engineer
-
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/engineer
- name = "Station Engineer"
- jobtype = /datum/job/engineer
-
- belt = /obj/item/storage/belt/utility/full/engi
- l_pocket = /obj/item/pda/engineering
- ears = /obj/item/radio/headset/headset_eng
- uniform = /obj/item/clothing/under/rank/engineer
- shoes = /obj/item/clothing/shoes/workboots
- head = /obj/item/clothing/head/hardhat
- r_pocket = /obj/item/t_scanner
-
- backpack = /obj/item/storage/backpack/industrial
- satchel = /obj/item/storage/backpack/satchel/eng
- duffelbag = /obj/item/storage/backpack/duffelbag/engineering
- box = /obj/item/storage/box/engineer
- pda_slot = SLOT_L_STORE
- backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
-
-/datum/outfit/job/engineer/gloved
- name = "Station Engineer (Gloves)"
- gloves = /obj/item/clothing/gloves/color/yellow
-
-/datum/outfit/job/engineer/gloved/rig
- name = "Station Engineer (Hardsuit)"
-
- mask = /obj/item/clothing/mask/breath
- suit = /obj/item/clothing/suit/space/hardsuit/engine
- suit_store = /obj/item/tank/internals/oxygen
- head = null
- internals_slot = SLOT_S_STORE
-
-
-/*
-Atmospheric Technician
-*/
-/datum/job/atmos
- title = "Atmospheric Technician"
- flag = ATMOSTECH
- department_head = list("Chief Engineer")
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 3
- spawn_positions = 2
- supervisors = "the chief engineer"
- selection_color = "#fff5cc"
- exp_requirements = 60
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/atmos
-
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/atmos
- name = "Atmospheric Technician"
- jobtype = /datum/job/atmos
-
- belt = /obj/item/storage/belt/utility/atmostech
- l_pocket = /obj/item/pda/atmos
- ears = /obj/item/radio/headset/headset_eng
- uniform = /obj/item/clothing/under/rank/atmospheric_technician
- r_pocket = /obj/item/analyzer
-
- backpack = /obj/item/storage/backpack/industrial
- satchel = /obj/item/storage/backpack/satchel/eng
- duffelbag = /obj/item/storage/backpack/duffelbag/engineering
- box = /obj/item/storage/box/engineer
- pda_slot = SLOT_L_STORE
- backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
-
-/datum/outfit/job/atmos/rig
- name = "Atmospheric Technician (Hardsuit)"
-
- mask = /obj/item/clothing/mask/gas
- suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos
- suit_store = /obj/item/tank/internals/oxygen
- internals_slot = SLOT_S_STORE
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
new file mode 100644
index 0000000000..d7f59ff883
--- /dev/null
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -0,0 +1,35 @@
+/datum/job/geneticist
+ title = "Geneticist"
+ flag = GENETICIST
+ department_head = list("Chief Medical Officer", "Research Director")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the chief medical officer and research director"
+ selection_color = "#74b5e0"
+ exp_type = EXP_TYPE_CREW
+ exp_requirements = 60
+
+ outfit = /datum/outfit/job/geneticist
+
+ access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE)
+ minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_GENETICIST
+
+/datum/outfit/job/geneticist
+ name = "Geneticist"
+ jobtype = /datum/job/geneticist
+
+ belt = /obj/item/pda/geneticist
+ ears = /obj/item/radio/headset/headset_medsci
+ uniform = /obj/item/clothing/under/rank/geneticist
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ suit = /obj/item/clothing/suit/toggle/labcoat/genetics
+ suit_store = /obj/item/flashlight/pen
+
+ backpack = /obj/item/storage/backpack/genetics
+ satchel = /obj/item/storage/backpack/satchel/gen
+ duffelbag = /obj/item/storage/backpack/duffelbag/med
+
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
new file mode 100644
index 0000000000..e320ce20b4
--- /dev/null
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -0,0 +1,51 @@
+/datum/job/hop
+ title = "Head of Personnel"
+ flag = HOP
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
+ department_head = list("Captain")
+ department_flag = CIVILIAN
+ head_announce = list(RADIO_CHANNEL_SERVICE)
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#3a8529"
+ req_admin_notify = 1
+ minimal_player_age = 10
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_SERVICE
+
+ outfit = /datum/outfit/job/hop
+
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
+ ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
+ ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
+ ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
+ ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
+ ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
+ ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
+ ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
+ ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
+ ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
+ ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL
+
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
+
+/datum/outfit/job/hop
+ name = "Head of Personnel"
+ jobtype = /datum/job/hop
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/pda/heads/hop
+ ears = /obj/item/radio/headset/heads/hop
+ uniform = /obj/item/clothing/under/rank/head_of_personnel
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ head = /obj/item/clothing/head/hopcap
+ backpack_contents = list(/obj/item/storage/box/ids=1,\
+ /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
+
+ chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
new file mode 100644
index 0000000000..f6b5dbd3ef
--- /dev/null
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -0,0 +1,68 @@
+/datum/job/hos
+ title = "Head of Security"
+ flag = HOS
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY
+ department_head = list("Captain")
+ department_flag = ENGSEC
+ head_announce = list(RADIO_CHANNEL_SECURITY)
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#b90000"
+ req_admin_notify = 1
+ minimal_player_age = 14
+ exp_requirements = 300
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_SECURITY
+
+ outfit = /datum/outfit/job/hos
+ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
+ ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
+ ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
+ ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
+ ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
+ ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
+ ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity)
+
+/datum/outfit/job/hos
+ name = "Head of Security"
+ jobtype = /datum/job/hos
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/pda/heads/hos
+ ears = /obj/item/radio/headset/heads/hos/alt
+ uniform = /obj/item/clothing/under/rank/head_of_security
+ shoes = /obj/item/clothing/shoes/jackboots
+ suit = /obj/item/clothing/suit/armor/hos/trenchcoat
+ gloves = /obj/item/clothing/gloves/color/black/hos
+ head = /obj/item/clothing/head/HoS/beret
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ suit_store = /obj/item/gun/energy/e_gun
+ r_pocket = /obj/item/assembly/flash/handheld
+ l_pocket = /obj/item/restraints/handcuffs
+ backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1)
+
+ backpack = /obj/item/storage/backpack/security
+ satchel = /obj/item/storage/backpack/satchel/sec
+ duffelbag = /obj/item/storage/backpack/duffelbag/sec
+ box = /obj/item/storage/box/security
+
+ implants = list(/obj/item/implant/mindshield)
+
+ chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos)
+
+/datum/outfit/job/hos/hardsuit
+ name = "Head of Security (Hardsuit)"
+
+ mask = /obj/item/clothing/mask/gas/sechailer
+ suit = /obj/item/clothing/suit/space/hardsuit/security/hos
+ suit_store = /obj/item/tank/internals/oxygen
+ backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1)
+
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
new file mode 100644
index 0000000000..d0a06ca0e0
--- /dev/null
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -0,0 +1,27 @@
+/datum/job/janitor
+ title = "Janitor"
+ flag = JANITOR
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#bbe291"
+ var/global/janitors = 0
+
+ outfit = /datum/outfit/job/janitor
+
+ access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_JANITOR
+
+/datum/outfit/job/janitor
+ name = "Janitor"
+ jobtype = /datum/job/janitor
+
+ belt = /obj/item/pda/janitor
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/janitor
+ backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm
new file mode 100644
index 0000000000..0b8be52116
--- /dev/null
+++ b/code/modules/jobs/job_types/lawyer.dm
@@ -0,0 +1,47 @@
+/datum/job/lawyer
+ title = "Lawyer"
+ flag = LAWYER
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+ var/lawyers = 0 //Counts lawyer amount
+
+ outfit = /datum/outfit/job/lawyer
+
+ access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
+ minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
+
+ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ display_order = JOB_DISPLAY_ORDER_LAWYER
+
+/datum/outfit/job/lawyer
+ name = "Lawyer"
+ jobtype = /datum/job/lawyer
+
+ belt = /obj/item/pda/lawyer
+ ears = /obj/item/radio/headset/headset_sec
+ uniform = /obj/item/clothing/under/lawyer/bluesuit
+ suit = /obj/item/clothing/suit/toggle/lawyer
+ shoes = /obj/item/clothing/shoes/laceup
+ l_hand = /obj/item/storage/briefcase/lawyer
+ l_pocket = /obj/item/laser_pointer
+ r_pocket = /obj/item/clothing/accessory/lawyers_badge
+
+ chameleon_extras = /obj/item/stamp/law
+
+
+/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ if(visualsOnly)
+ return
+
+ var/datum/job/lawyer/J = SSjob.GetJobType(jobtype)
+ J.lawyers++
+ if(J.lawyers>1)
+ uniform = /obj/item/clothing/under/lawyer/purpsuit
+ suit = /obj/item/clothing/suit/toggle/lawyer/purple
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
deleted file mode 100644
index 9eeb4ab06e..0000000000
--- a/code/modules/jobs/job_types/medical.dm
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
-Chief Medical Officer
-*/
-/datum/job/cmo
- title = "Chief Medical Officer"
- flag = CMO_JF
- department_head = list("Captain")
- department_flag = MEDSCI
- head_announce = list(RADIO_CHANNEL_MEDICAL)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the captain"
- selection_color = "#ffddf0"
- req_admin_notify = 1
- minimal_player_age = 7
- exp_requirements = 180
- exp_type = EXP_TYPE_CREW
- exp_type_department = EXP_TYPE_MEDICAL
-
- outfit = /datum/outfit/job/cmo
-
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
- ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
- ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
- ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
- ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
-
-/datum/outfit/job/cmo
- name = "Chief Medical Officer"
- jobtype = /datum/job/cmo
-
- id = /obj/item/card/id/silver
- belt = /obj/item/pda/heads/cmo
- l_pocket = /obj/item/pinpointer/crew
- ears = /obj/item/radio/headset/heads/cmo
- uniform = /obj/item/clothing/under/rank/chief_medical_officer
- shoes = /obj/item/clothing/shoes/sneakers/brown
- suit = /obj/item/clothing/suit/toggle/labcoat/cmo
- l_hand = /obj/item/storage/firstaid/regular
- suit_store = /obj/item/flashlight/pen
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1)
-
- backpack = /obj/item/storage/backpack/medic
- satchel = /obj/item/storage/backpack/satchel/med
- duffelbag = /obj/item/storage/backpack/duffelbag/med
-
- chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo)
-
-/datum/outfit/job/cmo/hardsuit
- name = "Chief Medical Officer (Hardsuit)"
-
- mask = /obj/item/clothing/mask/breath
- suit = /obj/item/clothing/suit/space/hardsuit/medical
- suit_store = /obj/item/tank/internals/oxygen
- r_pocket = /obj/item/flashlight/pen
-
-/*
-Medical Doctor
-*/
-/datum/job/doctor
- title = "Medical Doctor"
- flag = DOCTOR
- department_head = list("Chief Medical Officer")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 5
- spawn_positions = 3
- supervisors = "the chief medical officer"
- selection_color = "#ffeef0"
-
- outfit = /datum/outfit/job/doctor
-
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/doctor
- name = "Medical Doctor"
- jobtype = /datum/job/doctor
-
- belt = /obj/item/pda/medical
- ears = /obj/item/radio/headset/headset_med
- uniform = /obj/item/clothing/under/rank/medical
- shoes = /obj/item/clothing/shoes/sneakers/white
- suit = /obj/item/clothing/suit/toggle/labcoat
- l_hand = /obj/item/storage/firstaid/regular
- suit_store = /obj/item/flashlight/pen
-
- backpack = /obj/item/storage/backpack/medic
- satchel = /obj/item/storage/backpack/satchel/med
- duffelbag = /obj/item/storage/backpack/duffelbag/med
-
- chameleon_extras = /obj/item/gun/syringe
-
-/*
-Chemist
-*/
-/datum/job/chemist
- title = "Chemist"
- flag = CHEMIST
- department_head = list("Chief Medical Officer")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 2
- spawn_positions = 2
- supervisors = "the chief medical officer"
- selection_color = "#ffeef0"
- exp_type = EXP_TYPE_CREW
- exp_requirements = 60
-
- outfit = /datum/outfit/job/chemist
-
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/chemist
- name = "Chemist"
- jobtype = /datum/job/chemist
-
- glasses = /obj/item/clothing/glasses/science
- belt = /obj/item/pda/chemist
- ears = /obj/item/radio/headset/headset_med
- uniform = /obj/item/clothing/under/rank/chemist
- shoes = /obj/item/clothing/shoes/sneakers/white
- suit = /obj/item/clothing/suit/toggle/labcoat/chemist
- backpack = /obj/item/storage/backpack/chemistry
- satchel = /obj/item/storage/backpack/satchel/chem
- duffelbag = /obj/item/storage/backpack/duffelbag/med
- l_hand = /obj/item/fermichem/pHbooklet
-
- chameleon_extras = /obj/item/gun/syringe
-
-/*
-Geneticist
-*/
-/datum/job/geneticist
- title = "Geneticist"
- flag = GENETICIST
- department_head = list("Chief Medical Officer", "Research Director")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 2
- spawn_positions = 2
- supervisors = "the chief medical officer and research director"
- selection_color = "#ffeef0"
- exp_type = EXP_TYPE_CREW
- exp_requirements = 60
-
- outfit = /datum/outfit/job/geneticist
-
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/geneticist
- name = "Geneticist"
- jobtype = /datum/job/geneticist
-
- belt = /obj/item/pda/geneticist
- ears = /obj/item/radio/headset/headset_medsci
- uniform = /obj/item/clothing/under/rank/geneticist
- shoes = /obj/item/clothing/shoes/sneakers/white
- suit = /obj/item/clothing/suit/toggle/labcoat/genetics
- suit_store = /obj/item/flashlight/pen
-
- backpack = /obj/item/storage/backpack/genetics
- satchel = /obj/item/storage/backpack/satchel/gen
- duffelbag = /obj/item/storage/backpack/duffelbag/med
-
-/*
-Virologist
-*/
-/datum/job/virologist
- title = "Virologist"
- flag = VIROLOGIST
- department_head = list("Chief Medical Officer")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the chief medical officer"
- selection_color = "#ffeef0"
- exp_type = EXP_TYPE_CREW
- exp_requirements = 60
-
- outfit = /datum/outfit/job/virologist
-
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/virologist
- name = "Virologist"
- jobtype = /datum/job/virologist
-
- belt = /obj/item/pda/viro
- ears = /obj/item/radio/headset/headset_med
- uniform = /obj/item/clothing/under/rank/virologist
- mask = /obj/item/clothing/mask/surgical
- shoes = /obj/item/clothing/shoes/sneakers/white
- suit = /obj/item/clothing/suit/toggle/labcoat/virologist
- suit_store = /obj/item/flashlight/pen
-
- backpack = /obj/item/storage/backpack/virology
- satchel = /obj/item/storage/backpack/satchel/vir
- duffelbag = /obj/item/storage/backpack/duffelbag/med
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
new file mode 100644
index 0000000000..19fa1c7158
--- /dev/null
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -0,0 +1,35 @@
+/datum/job/doctor
+ title = "Medical Doctor"
+ flag = DOCTOR
+ department_head = list("Chief Medical Officer")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 5
+ spawn_positions = 3
+ supervisors = "the chief medical officer"
+ selection_color = "#74b5e0"
+
+ outfit = /datum/outfit/job/doctor
+
+ access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR
+
+/datum/outfit/job/doctor
+ name = "Medical Doctor"
+ jobtype = /datum/job/doctor
+
+ belt = /obj/item/pda/medical
+ ears = /obj/item/radio/headset/headset_med
+ uniform = /obj/item/clothing/under/rank/medical
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ suit = /obj/item/clothing/suit/toggle/labcoat
+ l_hand = /obj/item/storage/firstaid/regular
+ suit_store = /obj/item/flashlight/pen
+
+ backpack = /obj/item/storage/backpack/medic
+ satchel = /obj/item/storage/backpack/satchel/med
+ duffelbag = /obj/item/storage/backpack/duffelbag/med
+
+ chameleon_extras = /obj/item/gun/syringe
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
new file mode 100644
index 0000000000..1347da7125
--- /dev/null
+++ b/code/modules/jobs/job_types/mime.dm
@@ -0,0 +1,49 @@
+/datum/job/mime
+ title = "Mime"
+ flag = MIME
+ department_head = list("Head of Personnel")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+
+ outfit = /datum/outfit/job/mime
+
+ access = list(ACCESS_THEATRE)
+ minimal_access = list(ACCESS_THEATRE)
+
+ display_order = JOB_DISPLAY_ORDER_MIME
+
+/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
+ H.apply_pref_name("mime", M.client)
+
+/datum/outfit/job/mime
+ name = "Mime"
+ jobtype = /datum/job/mime
+
+ belt = /obj/item/pda/mime
+ ears = /obj/item/radio/headset/headset_srv
+ uniform = /obj/item/clothing/under/rank/mime
+ mask = /obj/item/clothing/mask/gas/mime
+ gloves = /obj/item/clothing/gloves/color/white
+ head = /obj/item/clothing/head/frenchberet
+ suit = /obj/item/clothing/suit/suspenders
+ backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1)
+
+ backpack = /obj/item/storage/backpack/mime
+ satchel = /obj/item/storage/backpack/mime
+
+
+/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+
+ if(visualsOnly)
+ return
+
+ if(H.mind)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
+ H.mind.miming = 1
+
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
new file mode 100644
index 0000000000..49a93026ba
--- /dev/null
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -0,0 +1,41 @@
+/datum/job/qm
+ title = "Quartermaster"
+ flag = QUARTERMASTER
+ department_head = list("Captain")
+ department_flag = CIVILIAN
+ head_announce = list(RADIO_CHANNEL_SUPPLY)
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#a06121"
+ req_admin_notify = 1
+ minimal_player_age = 7
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+ exp_type_department = EXP_TYPE_SUPPLY
+
+ outfit = /datum/outfit/job/quartermaster
+
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION,
+ ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
+ minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING,
+ ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
+
+ display_order = JOB_DISPLAY_ORDER_QUARTERMASTER
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
+/datum/outfit/job/quartermaster
+ name = "Quartermaster"
+ jobtype = /datum/job/qm
+
+ belt = /obj/item/pda/quartermaster
+ ears = /obj/item/radio/headset/headset_cargo
+ uniform = /obj/item/clothing/under/rank/cargo
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ glasses = /obj/item/clothing/glasses/sunglasses
+ l_hand = /obj/item/clipboard
+
+ chameleon_extras = /obj/item/stamp/qm
+
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
new file mode 100644
index 0000000000..5368ceee64
--- /dev/null
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -0,0 +1,61 @@
+/datum/job/rd
+ title = "Research Director"
+ flag = RD_JF
+// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
+ department_head = list("Captain")
+ department_flag = MEDSCI
+ head_announce = list(RADIO_CHANNEL_SCIENCE)
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the captain"
+ selection_color = "#7544cc"
+ req_admin_notify = 1
+ minimal_player_age = 7
+ exp_type_department = EXP_TYPE_SCIENCE
+ exp_requirements = 180
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/rd
+
+ access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
+ ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
+ ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
+ ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
+ ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
+ minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
+ ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
+ ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
+ ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
+ ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
+
+ display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
+/datum/outfit/job/rd
+ name = "Research Director"
+ jobtype = /datum/job/rd
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/pda/heads/rd
+ ears = /obj/item/radio/headset/heads/rd
+ uniform = /obj/item/clothing/under/rank/research_director
+ shoes = /obj/item/clothing/shoes/sneakers/brown
+ suit = /obj/item/clothing/suit/toggle/labcoat
+ l_hand = /obj/item/clipboard
+ l_pocket = /obj/item/laser_pointer
+ backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1)
+
+ backpack = /obj/item/storage/backpack/science
+ satchel = /obj/item/storage/backpack/satchel/tox
+
+ chameleon_extras = /obj/item/stamp/rd
+
+/datum/outfit/job/rd/rig
+ name = "Research Director (Hardsuit)"
+
+ l_hand = null
+ mask = /obj/item/clothing/mask/breath
+ suit = /obj/item/clothing/suit/space/hardsuit/rd
+ suit_store = /obj/item/tank/internals/oxygen
+ internals_slot = SLOT_S_STORE
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
new file mode 100644
index 0000000000..782b175ad4
--- /dev/null
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -0,0 +1,34 @@
+/datum/job/roboticist
+ title = "Roboticist"
+ flag = ROBOTICIST
+ department_head = list("Research Director")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the research director"
+ selection_color = "#9574cd"
+ exp_requirements = 60
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/roboticist
+
+ access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS)
+ minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_ROBOTICIST
+
+/datum/outfit/job/roboticist
+ name = "Roboticist"
+ jobtype = /datum/job/roboticist
+
+ belt = /obj/item/storage/belt/utility/full
+ l_pocket = /obj/item/pda/roboticist
+ ears = /obj/item/radio/headset/headset_sci
+ uniform = /obj/item/clothing/under/rank/roboticist
+ suit = /obj/item/clothing/suit/toggle/labcoat
+
+ backpack = /obj/item/storage/backpack/science
+ satchel = /obj/item/storage/backpack/satchel/tox
+
+ pda_slot = SLOT_L_STORE
diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm
deleted file mode 100644
index b58f3faa27..0000000000
--- a/code/modules/jobs/job_types/science.dm
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-Research Director
-*/
-/datum/job/rd
- title = "Research Director"
- flag = RD_JF
- department_head = list("Captain")
- department_flag = MEDSCI
- head_announce = list(RADIO_CHANNEL_SCIENCE)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the captain"
- selection_color = "#ffddff"
- req_admin_notify = 1
- minimal_player_age = 7
- exp_type_department = EXP_TYPE_SCIENCE
- exp_requirements = 180
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/rd
-
- access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
- ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
- ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
- ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
- ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
- minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
- ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
- ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
- ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
- ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
-
-/datum/outfit/job/rd
- name = "Research Director"
- jobtype = /datum/job/rd
-
- id = /obj/item/card/id/silver
- belt = /obj/item/pda/heads/rd
- ears = /obj/item/radio/headset/heads/rd
- uniform = /obj/item/clothing/under/rank/research_director
- shoes = /obj/item/clothing/shoes/sneakers/brown
- suit = /obj/item/clothing/suit/toggle/labcoat
- l_hand = /obj/item/clipboard
- l_pocket = /obj/item/laser_pointer
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1)
-
- backpack = /obj/item/storage/backpack/science
- satchel = /obj/item/storage/backpack/satchel/tox
-
- chameleon_extras = /obj/item/stamp/rd
-
-/datum/outfit/job/rd/rig
- name = "Research Director (Hardsuit)"
-
- l_hand = null
- mask = /obj/item/clothing/mask/breath
- suit = /obj/item/clothing/suit/space/hardsuit/rd
- suit_store = /obj/item/tank/internals/oxygen
- internals_slot = SLOT_S_STORE
-
-/*
-Scientist
-*/
-/datum/job/scientist
- title = "Scientist"
- flag = SCIENTIST
- department_head = list("Research Director")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 5
- spawn_positions = 3
- supervisors = "the research director"
- selection_color = "#ffeeff"
- exp_requirements = 60
- exp_type = EXP_TYPE_CREW
-
-
- outfit = /datum/outfit/job/scientist
-
- access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS)
- minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/scientist
- name = "Scientist"
- jobtype = /datum/job/scientist
-
- belt = /obj/item/pda/toxins
- ears = /obj/item/radio/headset/headset_sci
- uniform = /obj/item/clothing/under/rank/scientist
- shoes = /obj/item/clothing/shoes/sneakers/white
- suit = /obj/item/clothing/suit/toggle/labcoat/science
-
- backpack = /obj/item/storage/backpack/science
- satchel = /obj/item/storage/backpack/satchel/tox
-
-/*
-Roboticist
-*/
-/datum/job/roboticist
- title = "Roboticist"
- flag = ROBOTICIST
- department_head = list("Research Director")
- department_flag = MEDSCI
- faction = "Station"
- total_positions = 2
- spawn_positions = 2
- supervisors = "the research director"
- selection_color = "#ffeeff"
- exp_requirements = 60
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/roboticist
-
- access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS)
- minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
-
-/datum/outfit/job/roboticist
- name = "Roboticist"
- jobtype = /datum/job/roboticist
-
- belt = /obj/item/storage/belt/utility/full
- l_pocket = /obj/item/pda/roboticist
- ears = /obj/item/radio/headset/headset_sci
- uniform = /obj/item/clothing/under/rank/roboticist
- suit = /obj/item/clothing/suit/toggle/labcoat
-
- backpack = /obj/item/storage/backpack/science
- satchel = /obj/item/storage/backpack/satchel/tox
-
- pda_slot = SLOT_L_STORE
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
new file mode 100644
index 0000000000..f40a25d6ba
--- /dev/null
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -0,0 +1,33 @@
+/datum/job/scientist
+ title = "Scientist"
+ flag = SCIENTIST
+ department_head = list("Research Director")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 5
+ spawn_positions = 3
+ supervisors = "the research director"
+ selection_color = "#9574cd"
+ exp_requirements = 60
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/scientist
+
+ access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS)
+ minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_SCIENTIST
+
+/datum/outfit/job/scientist
+ name = "Scientist"
+ jobtype = /datum/job/scientist
+
+ belt = /obj/item/pda/toxins
+ ears = /obj/item/radio/headset/headset_sci
+ uniform = /obj/item/clothing/under/rank/scientist
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ suit = /obj/item/clothing/suit/toggle/labcoat/science
+
+ backpack = /obj/item/storage/backpack/science
+ satchel = /obj/item/storage/backpack/satchel/tox
+
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
deleted file mode 100644
index 96cedd89ef..0000000000
--- a/code/modules/jobs/job_types/security.dm
+++ /dev/null
@@ -1,346 +0,0 @@
-//Warden and regular officers add this result to their get_access()
-/datum/job/proc/check_config_for_sec_maint()
- if(CONFIG_GET(flag/security_has_maint_access))
- return list(ACCESS_MAINT_TUNNELS)
- return list()
-
-/*
-Head of Security
-*/
-/datum/job/hos
- title = "Head of Security"
- flag = HOS
- department_head = list("Captain")
- department_flag = ENGSEC
- head_announce = list(RADIO_CHANNEL_SECURITY)
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the captain"
- selection_color = "#ffdddd"
- req_admin_notify = 1
- minimal_player_age = 14
- exp_requirements = 300
- exp_type = EXP_TYPE_CREW
- exp_type_department = EXP_TYPE_SECURITY
-
- outfit = /datum/outfit/job/hos
-
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
- ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
- ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
- ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
- ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
-
- mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
-
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity)
-
-/datum/outfit/job/hos
- name = "Head of Security"
- jobtype = /datum/job/hos
-
- id = /obj/item/card/id/silver
- belt = /obj/item/pda/heads/hos
- ears = /obj/item/radio/headset/heads/hos/alt
- uniform = /obj/item/clothing/under/rank/head_of_security
- shoes = /obj/item/clothing/shoes/jackboots
- suit = /obj/item/clothing/suit/armor/hos/trenchcoat
- gloves = /obj/item/clothing/gloves/color/black/hos
- head = /obj/item/clothing/head/HoS/beret
- glasses = /obj/item/clothing/glasses/hud/security/sunglasses
- suit_store = /obj/item/gun/energy/e_gun
- r_pocket = /obj/item/assembly/flash/handheld
- l_pocket = /obj/item/restraints/handcuffs
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1)
-
- backpack = /obj/item/storage/backpack/security
- satchel = /obj/item/storage/backpack/satchel/sec
- duffelbag = /obj/item/storage/backpack/duffelbag/sec
- box = /obj/item/storage/box/security
-
- implants = list(/obj/item/implant/mindshield)
-
- chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos)
-
-/datum/outfit/job/hos/hardsuit
- name = "Head of Security (Hardsuit)"
-
- mask = /obj/item/clothing/mask/gas/sechailer
- suit = /obj/item/clothing/suit/space/hardsuit/security/hos
- suit_store = /obj/item/tank/internals/oxygen
- backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1)
-
-/*
-Warden
-*/
-/datum/job/warden
- title = "Warden"
- flag = WARDEN
- department_head = list("Head of Security")
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of security"
- selection_color = "#ffeeee"
- minimal_player_age = 7
- exp_requirements = 300
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/warden
-
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //SEE /DATUM/JOB/WARDEN/GET_ACCESS()
-
- mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
-
-/datum/job/warden/get_access()
- var/list/L = list()
- L = ..() | check_config_for_sec_maint()
- return L
-
-/datum/outfit/job/warden
- name = "Warden"
- jobtype = /datum/job/warden
-
- belt = /obj/item/pda/warden
- ears = /obj/item/radio/headset/headset_sec/alt
- uniform = /obj/item/clothing/under/rank/warden
- shoes = /obj/item/clothing/shoes/jackboots
- suit = /obj/item/clothing/suit/armor/vest/warden/alt
- gloves = /obj/item/clothing/gloves/color/black
- head = /obj/item/clothing/head/warden
- glasses = /obj/item/clothing/glasses/hud/security/sunglasses
- r_pocket = /obj/item/assembly/flash/handheld
- l_pocket = /obj/item/restraints/handcuffs
- suit_store = /obj/item/gun/energy/e_gun/advtaser
- backpack_contents = list(/obj/item/melee/baton/loaded=1)
-
- backpack = /obj/item/storage/backpack/security
- satchel = /obj/item/storage/backpack/satchel/sec
- duffelbag = /obj/item/storage/backpack/duffelbag/sec
- box = /obj/item/storage/box/security
-
- implants = list(/obj/item/implant/mindshield)
-
- chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact
-
-/*
-Detective
-*/
-/datum/job/detective
- title = "Detective"
- flag = DETECTIVE
- department_head = list("Head of Security")
- department_flag = ENGSEC
- faction = "Station"
- total_positions = 1
- spawn_positions = 1
- supervisors = "the head of security"
- selection_color = "#ffeeee"
- minimal_player_age = 7
- exp_requirements = 300
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/detective
-
- access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
-
- mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
-
-/datum/outfit/job/detective
- name = "Detective"
- jobtype = /datum/job/detective
-
- belt = /obj/item/pda/detective
- ears = /obj/item/radio/headset/headset_sec/alt
- uniform = /obj/item/clothing/under/rank/det
- shoes = /obj/item/clothing/shoes/sneakers/brown
- suit = /obj/item/clothing/suit/det_suit
- gloves = /obj/item/clothing/gloves/color/black
- head = /obj/item/clothing/head/fedora/det_hat
- l_pocket = /obj/item/toy/crayon/white
- r_pocket = /obj/item/lighter
- backpack_contents = list(/obj/item/storage/box/evidence=1,\
- /obj/item/detective_scanner=1,\
- /obj/item/melee/classic_baton=1)
- mask = /obj/item/clothing/mask/cigarette
-
- implants = list(/obj/item/implant/mindshield)
-
- chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses)
-
-/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
- if(istype(cig)) //Some species specfic changes can mess this up (plasmamen)
- cig.light("")
-
- if(visualsOnly)
- return
-
-/*
-Security Officer
-*/
-/datum/job/officer
- title = "Security Officer"
- flag = OFFICER
- department_head = list("Head of Security")
- department_flag = ENGSEC
- 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)"
- selection_color = "#ffeeee"
- minimal_player_age = 7
- exp_requirements = 300
- exp_type = EXP_TYPE_CREW
-
- outfit = /datum/outfit/job/security
-
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //BUT SEE /DATUM/JOB/WARDEN/GET_ACCESS()
-
- mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
- blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
-
-/datum/job/officer/get_access()
- var/list/L = list()
- L |= ..() | check_config_for_sec_maint()
- return L
-
-GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
-
-/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M)
- // Assign department security
- var/department
- if(M && M.client && M.client.prefs)
- department = M.client.prefs.prefered_security_department
- if(!LAZYLEN(GLOB.available_depts) || department == "None")
- return
- else if(department in GLOB.available_depts)
- LAZYREMOVE(GLOB.available_depts, department)
- else
- department = pick_n_take(GLOB.available_depts)
- var/ears = null
- var/accessory = null
- var/list/dep_access = null
- var/destination = null
- var/spawn_point = null
- switch(department)
- if(SEC_DEPT_SUPPLY)
- ears = /obj/item/radio/headset/headset_sec/alt/department/supply
- dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION)
- destination = /area/security/checkpoint/supply
- spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns
- accessory = /obj/item/clothing/accessory/armband/cargo
- if(SEC_DEPT_ENGINEERING)
- ears = /obj/item/radio/headset/headset_sec/alt/department/engi
- dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE)
- destination = /area/security/checkpoint/engineering
- spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns
- accessory = /obj/item/clothing/accessory/armband/engine
- if(SEC_DEPT_MEDICAL)
- ears = /obj/item/radio/headset/headset_sec/alt/department/med
- dep_access = list(ACCESS_MEDICAL)
- destination = /area/security/checkpoint/medical
- spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns
- accessory = /obj/item/clothing/accessory/armband/medblue
- if(SEC_DEPT_SCIENCE)
- ears = /obj/item/radio/headset/headset_sec/alt/department/sci
- dep_access = list(ACCESS_RESEARCH)
- destination = /area/security/checkpoint/science
- spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns
- accessory = /obj/item/clothing/accessory/armband/science
-
- if(accessory)
- var/obj/item/clothing/under/U = H.w_uniform
- U.attach_accessory(new accessory)
- if(ears)
- if(H.ears)
- qdel(H.ears)
- H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
-
- var/obj/item/card/id/W = H.wear_id
- W.access |= dep_access
-
- var/teleport = 0
- if(!CONFIG_GET(flag/sec_start_brig))
- if(destination || spawn_point)
- teleport = 1
- if(teleport)
- var/turf/T
- if(spawn_point)
- T = get_turf(spawn_point)
- H.Move(T)
- else
- var/safety = 0
- while(safety < 25)
- T = safepick(get_area_turfs(destination))
- if(T && !H.Move(T))
- safety += 1
- continue
- else
- break
- 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. ")
-
-
-
-/datum/outfit/job/security
- name = "Security Officer"
- jobtype = /datum/job/officer
-
- belt = /obj/item/pda/security
- ears = /obj/item/radio/headset/headset_sec/alt
- uniform = /obj/item/clothing/under/rank/security
- gloves = /obj/item/clothing/gloves/color/black
- head = /obj/item/clothing/head/helmet/sec
- suit = /obj/item/clothing/suit/armor/vest/alt
- shoes = /obj/item/clothing/shoes/jackboots
- l_pocket = /obj/item/restraints/handcuffs
- r_pocket = /obj/item/assembly/flash/handheld
- suit_store = /obj/item/gun/energy/e_gun/advtaser
- backpack_contents = list(/obj/item/melee/baton/loaded=1)
-
- backpack = /obj/item/storage/backpack/security
- satchel = /obj/item/storage/backpack/satchel/sec
- duffelbag = /obj/item/storage/backpack/duffelbag/sec
- box = /obj/item/storage/box/security
-
- implants = list(/obj/item/implant/mindshield)
-
- chameleon_extras = list(/obj/item/gun/energy/e_gun/advtaser, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet)
- //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state
-
-
-/obj/item/radio/headset/headset_sec/alt/department/Initialize()
- . = ..()
- wires = new/datum/wires/radio(src)
- secure_radio_connections = new
- recalculateChannels()
-
-/obj/item/radio/headset/headset_sec/alt/department/engi
- keyslot = new /obj/item/encryptionkey/headset_sec
- keyslot2 = new /obj/item/encryptionkey/headset_eng
-
-/obj/item/radio/headset/headset_sec/alt/department/supply
- keyslot = new /obj/item/encryptionkey/headset_sec
- keyslot2 = new /obj/item/encryptionkey/headset_cargo
-
-/obj/item/radio/headset/headset_sec/alt/department/med
- keyslot = new /obj/item/encryptionkey/headset_sec
- keyslot2 = new /obj/item/encryptionkey/headset_med
-
-/obj/item/radio/headset/headset_sec/alt/department/sci
- keyslot = new /obj/item/encryptionkey/headset_sec
- keyslot2 = new /obj/item/encryptionkey/headset_sci
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
new file mode 100644
index 0000000000..4f12d6a19c
--- /dev/null
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -0,0 +1,159 @@
+/datum/job/officer
+ title = "Security Officer"
+ flag = OFFICER
+// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY
+ department_head = list("Head of Security")
+ department_flag = ENGSEC
+ 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)"
+ selection_color = "#c02f2f"
+ minimal_player_age = 7
+ exp_requirements = 300
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/security
+
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
+
+ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
+
+/datum/job/officer/get_access()
+ var/list/L = list()
+ L |= ..() | check_config_for_sec_maint()
+ return L
+
+GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
+
+/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M)
+ . = ..()
+ // Assign department security
+ var/department
+ if(M && M.client && M.client.prefs)
+ department = M.client.prefs.prefered_security_department
+ if(!LAZYLEN(GLOB.available_depts) || department == "None")
+ return
+ else if(department in GLOB.available_depts)
+ LAZYREMOVE(GLOB.available_depts, department)
+ else
+ department = pick_n_take(GLOB.available_depts)
+ var/ears = null
+ var/accessory = null
+ var/list/dep_access = null
+ var/destination = null
+ var/spawn_point = null
+ switch(department)
+ if(SEC_DEPT_SUPPLY)
+ ears = /obj/item/radio/headset/headset_sec/alt/department/supply
+ dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_CARGO)
+ destination = /area/security/checkpoint/supply
+ spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns
+ accessory = /obj/item/clothing/accessory/armband/cargo
+ if(SEC_DEPT_ENGINEERING)
+ ears = /obj/item/radio/headset/headset_sec/alt/department/engi
+ dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ATMOSPHERICS)
+ destination = /area/security/checkpoint/engineering
+ spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns
+ accessory = /obj/item/clothing/accessory/armband/engine
+ if(SEC_DEPT_MEDICAL)
+ ears = /obj/item/radio/headset/headset_sec/alt/department/med
+ dep_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING)
+ destination = /area/security/checkpoint/medical
+ spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns
+ accessory = /obj/item/clothing/accessory/armband/medblue
+ if(SEC_DEPT_SCIENCE)
+ ears = /obj/item/radio/headset/headset_sec/alt/department/sci
+ dep_access = list(ACCESS_RESEARCH, ACCESS_TOX)
+ destination = /area/security/checkpoint/science
+ spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns
+ accessory = /obj/item/clothing/accessory/armband/science
+
+ if(accessory)
+ var/obj/item/clothing/under/U = H.w_uniform
+ U.attach_accessory(new accessory)
+ if(ears)
+ if(H.ears)
+ qdel(H.ears)
+ H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
+
+ var/obj/item/card/id/W = H.wear_id
+ W.access |= dep_access
+
+ var/teleport = 0
+ if(!CONFIG_GET(flag/sec_start_brig))
+ if(destination || spawn_point)
+ teleport = 1
+ if(teleport)
+ var/turf/T
+ if(spawn_point)
+ T = get_turf(spawn_point)
+ H.Move(T)
+ else
+ var/safety = 0
+ while(safety < 25)
+ T = safepick(get_area_turfs(destination))
+ if(T && !H.Move(T))
+ safety += 1
+ continue
+ else
+ break
+ 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. ")
+
+
+
+/datum/outfit/job/security
+ name = "Security Officer"
+ jobtype = /datum/job/officer
+
+ belt = /obj/item/pda/security
+ ears = /obj/item/radio/headset/headset_sec/alt
+ uniform = /obj/item/clothing/under/rank/security
+ gloves = /obj/item/clothing/gloves/color/black
+ head = /obj/item/clothing/head/helmet/sec
+ suit = /obj/item/clothing/suit/armor/vest/alt
+ shoes = /obj/item/clothing/shoes/jackboots
+ l_pocket = /obj/item/restraints/handcuffs
+ r_pocket = /obj/item/assembly/flash/handheld
+ suit_store = /obj/item/gun/energy/e_gun/advtaser
+ backpack_contents = list(/obj/item/melee/baton/loaded=1)
+
+ backpack = /obj/item/storage/backpack/security
+ satchel = /obj/item/storage/backpack/satchel/sec
+ duffelbag = /obj/item/storage/backpack/duffelbag/sec
+ box = /obj/item/storage/box/security
+
+ implants = list(/obj/item/implant/mindshield)
+
+ chameleon_extras = list(/obj/item/gun/energy/disabler, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet)
+ //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state
+
+
+/obj/item/radio/headset/headset_sec/alt/department/Initialize()
+ . = ..()
+ wires = new/datum/wires/radio(src)
+ secure_radio_connections = new
+ recalculateChannels()
+
+/obj/item/radio/headset/headset_sec/alt/department/engi
+ keyslot = new /obj/item/encryptionkey/headset_sec
+ keyslot2 = new /obj/item/encryptionkey/headset_eng
+
+/obj/item/radio/headset/headset_sec/alt/department/supply
+ keyslot = new /obj/item/encryptionkey/headset_sec
+ keyslot2 = new /obj/item/encryptionkey/headset_cargo
+
+/obj/item/radio/headset/headset_sec/alt/department/med
+ keyslot = new /obj/item/encryptionkey/headset_sec
+ keyslot2 = new /obj/item/encryptionkey/headset_med
+
+/obj/item/radio/headset/headset_sec/alt/department/sci
+ keyslot = new /obj/item/encryptionkey/headset_sec
+ keyslot2 = new /obj/item/encryptionkey/headset_sci
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
new file mode 100644
index 0000000000..ef16d8e53f
--- /dev/null
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -0,0 +1,77 @@
+/datum/job/mining
+ title = "Shaft Miner"
+ flag = MINER
+ department_head = list("Quartermaster")
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = 3
+ spawn_positions = 3
+ supervisors = "the quartermaster"
+ selection_color = "#ca8f55"
+ custom_spawn_text = "Remember, you are a miner, not a hunter. Hunting monsters is not a requirement of your job, the only requirement of your job is to provide materials for the station. Don't be afraid to run away if you're inexperienced with fighting the mining area's locals."
+
+
+ outfit = /datum/outfit/job/miner
+
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_SHAFT_MINER
+
+/datum/outfit/job/miner
+ name = "Shaft Miner (Lavaland)"
+ jobtype = /datum/job/mining
+
+ belt = /obj/item/pda/shaftminer
+ ears = /obj/item/radio/headset/headset_cargo/mining
+ shoes = /obj/item/clothing/shoes/workboots/mining
+ gloves = /obj/item/clothing/gloves/color/black
+ uniform = /obj/item/clothing/under/rank/miner/lavaland
+ l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival
+ r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack
+ backpack_contents = list(
+ /obj/item/flashlight/seclite=1,\
+ /obj/item/kitchen/knife/combat/survival=1,\
+ /obj/item/mining_voucher=1,\
+ /obj/item/suit_voucher=1,\
+ /obj/item/stack/marker_beacon/ten=1)
+
+ backpack = /obj/item/storage/backpack/explorer
+ satchel = /obj/item/storage/backpack/satchel/explorer
+ duffelbag = /obj/item/storage/backpack/duffelbag
+ box = /obj/item/storage/box/survival_mining
+
+ chameleon_extras = /obj/item/gun/energy/kinetic_accelerator
+
+/datum/outfit/job/miner/asteroid
+ name = "Shaft Miner (Asteroid)"
+ uniform = /obj/item/clothing/under/rank/miner
+ shoes = /obj/item/clothing/shoes/workboots
+
+/datum/outfit/job/miner/equipped
+ name = "Shaft Miner (Lavaland + Equipment)"
+ suit = /obj/item/clothing/suit/hooded/explorer/standard
+ mask = /obj/item/clothing/mask/gas/explorer
+ glasses = /obj/item/clothing/glasses/meson
+ suit_store = /obj/item/tank/internals/oxygen
+ internals_slot = SLOT_S_STORE
+ backpack_contents = list(
+ /obj/item/flashlight/seclite=1,\
+ /obj/item/kitchen/knife/combat/survival=1,
+ /obj/item/mining_voucher=1,
+ /obj/item/t_scanner/adv_mining_scanner/lesser=1,
+ /obj/item/gun/energy/kinetic_accelerator=1,\
+ /obj/item/stack/marker_beacon/ten=1)
+
+/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ if(visualsOnly)
+ return
+ if(istype(H.wear_suit, /obj/item/clothing/suit/hooded))
+ var/obj/item/clothing/suit/hooded/S = H.wear_suit
+ S.ToggleHood()
+
+/datum/outfit/job/miner/equipped/hardsuit
+ name = "Shaft Miner (Equipment + Hardsuit)"
+ suit = /obj/item/clothing/suit/space/hardsuit/mining
+ mask = /obj/item/clothing/mask/breath
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
new file mode 100644
index 0000000000..55381549ba
--- /dev/null
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -0,0 +1,54 @@
+/datum/job/engineer
+ title = "Station Engineer"
+ flag = ENGINEER
+ department_head = list("Chief Engineer")
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 5
+ spawn_positions = 5
+ supervisors = "the chief engineer"
+ selection_color = "#ff9b3d"
+ exp_requirements = 60
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/engineer
+
+ access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
+ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
+ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER
+
+/datum/outfit/job/engineer
+ name = "Station Engineer"
+ jobtype = /datum/job/engineer
+
+ belt = /obj/item/storage/belt/utility/full/engi
+ l_pocket = /obj/item/pda/engineering
+ ears = /obj/item/radio/headset/headset_eng
+ uniform = /obj/item/clothing/under/rank/engineer
+ shoes = /obj/item/clothing/shoes/workboots
+ head = /obj/item/clothing/head/hardhat
+ r_pocket = /obj/item/t_scanner
+
+ backpack = /obj/item/storage/backpack/industrial
+ satchel = /obj/item/storage/backpack/satchel/eng
+ duffelbag = /obj/item/storage/backpack/duffelbag/engineering
+ box = /obj/item/storage/box/engineer
+ pda_slot = SLOT_L_STORE
+ backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
+
+/datum/outfit/job/engineer/gloved
+ name = "Station Engineer (Gloves)"
+ gloves = /obj/item/clothing/gloves/color/yellow
+
+/datum/outfit/job/engineer/gloved/rig
+ name = "Station Engineer (Hardsuit)"
+ mask = /obj/item/clothing/mask/breath
+ suit = /obj/item/clothing/suit/space/hardsuit/engine
+ suit_store = /obj/item/tank/internals/oxygen
+ head = null
+ internals_slot = SLOT_S_STORE
+
+
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
new file mode 100644
index 0000000000..dcc13af627
--- /dev/null
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -0,0 +1,35 @@
+/datum/job/virologist
+ title = "Virologist"
+ flag = VIROLOGIST
+ department_head = list("Chief Medical Officer")
+ department_flag = MEDSCI
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the chief medical officer"
+ selection_color = "#74b5e0"
+ exp_type = EXP_TYPE_CREW
+ exp_requirements = 60
+
+ outfit = /datum/outfit/job/virologist
+
+ access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
+
+ display_order = JOB_DISPLAY_ORDER_VIROLOGIST
+
+/datum/outfit/job/virologist
+ name = "Virologist"
+ jobtype = /datum/job/virologist
+
+ belt = /obj/item/pda/viro
+ ears = /obj/item/radio/headset/headset_med
+ uniform = /obj/item/clothing/under/rank/virologist
+ mask = /obj/item/clothing/mask/surgical
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ suit = /obj/item/clothing/suit/toggle/labcoat/virologist
+ suit_store = /obj/item/flashlight/pen
+
+ backpack = /obj/item/storage/backpack/virology
+ satchel = /obj/item/storage/backpack/satchel/vir
+ duffelbag = /obj/item/storage/backpack/duffelbag/med
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
new file mode 100644
index 0000000000..a5c16ab5cf
--- /dev/null
+++ b/code/modules/jobs/job_types/warden.dm
@@ -0,0 +1,56 @@
+/datum/job/warden
+ title = "Warden"
+ flag = WARDEN
+// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY
+ department_head = list("Head of Security")
+ department_flag = ENGSEC
+ faction = "Station"
+ total_positions = 1
+ spawn_positions = 1
+ supervisors = "the head of security"
+ selection_color = "#c02f2f"
+ minimal_player_age = 7
+ exp_requirements = 300
+ exp_type = EXP_TYPE_CREW
+
+ outfit = /datum/outfit/job/warden
+
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
+
+ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ display_order = JOB_DISPLAY_ORDER_WARDEN
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
+
+/datum/job/warden/get_access()
+ var/list/L = list()
+ L = ..() | check_config_for_sec_maint()
+ return L
+
+/datum/outfit/job/warden
+ name = "Warden"
+ jobtype = /datum/job/warden
+
+ belt = /obj/item/pda/warden
+ ears = /obj/item/radio/headset/headset_sec/alt
+ uniform = /obj/item/clothing/under/rank/warden
+ shoes = /obj/item/clothing/shoes/jackboots
+ suit = /obj/item/clothing/suit/armor/vest/warden/alt
+ gloves = /obj/item/clothing/gloves/color/black
+ head = /obj/item/clothing/head/warden
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ r_pocket = /obj/item/assembly/flash/handheld
+ l_pocket = /obj/item/restraints/handcuffs
+ suit_store = /obj/item/gun/energy/e_gun/advtaser
+ backpack_contents = list(/obj/item/melee/baton/loaded=1)
+
+ backpack = /obj/item/storage/backpack/security
+ satchel = /obj/item/storage/backpack/satchel/sec
+ duffelbag = /obj/item/storage/backpack/duffelbag/sec
+ box = /obj/item/storage/box/security
+
+ implants = list(/obj/item/implant/mindshield)
+
+ chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact
+
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 750805ae93..1cd32d43ac 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -1,604 +1,623 @@
-#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
- canmove = FALSE
-
- anchored = TRUE // don't get pushed around
- var/mob/living/new_character //for instant transfer once the round is set up
-
-/mob/dead/new_player/Initialize()
- if(client && SSticker.state == GAME_STATE_STARTUP)
- var/obj/screen/splash/S = new(client, TRUE, TRUE)
- S.Fade(TRUE)
-
- if(length(GLOB.newplayer_start))
- forceMove(pick(GLOB.newplayer_start))
- else
- forceMove(locate(1,1,1))
-
- ComponentInitialize()
-
- . = ..()
-
-/mob/dead/new_player/prepare_huds()
- return
-
-/mob/dead/new_player/proc/new_player_panel()
- var/output = "Welcome, [client ? client.prefs.real_name : "Unknown User"]
"
- output += "Setup Character
"
-
- if(SSticker.current_state <= GAME_STATE_PREGAME)
- switch(ready)
- if(PLAYER_NOT_READY)
- output += "\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | Not Ready | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]
"
- if(PLAYER_READY_TO_PLAY)
- output += "\[ Ready | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]
"
- if(PLAYER_READY_TO_OBSERVE)
- output += "\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | Observe \]
"
- else
- output += "View the Crew Manifest
"
- output += "Join Game!
"
- output += "[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]
"
-
- if(!IsGuestKey(src.key))
- if (SSdbcore.Connect())
- var/isadmin = 0
- if(src.client && src.client.holder)
- isadmin = 1
- var/datum/DBQuery/query_get_new_polls = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[sanitizeSQL(ckey)]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[sanitizeSQL(ckey)]\")")
- var/rs = REF(src)
- if(query_get_new_polls.Execute())
- var/newpoll = 0
- if(query_get_new_polls.NextRow())
- newpoll = 1
-
- if(newpoll)
- output += "Show Player Polls (NEW!)
"
- else
- output += "Show Player Polls
"
- qdel(query_get_new_polls)
- if(QDELETED(src))
- return
-
- output += " "
-
- //src << browse(output,"window=playersetup;size=210x240;can_close=0")
- var/datum/browser/popup = new(src, "playersetup", "New Player Options
", 250, 265)
- popup.set_window_options("can_close=0")
- popup.set_content(output)
- popup.open(0)
-
-/mob/dead/new_player/Topic(href, href_list[])
- if(src != usr)
- return 0
-
- if(!client)
- return 0
-
- //Determines Relevent Population Cap
- var/relevant_cap
- var/hpc = CONFIG_GET(number/hard_popcap)
- var/epc = CONFIG_GET(number/extreme_popcap)
- if(hpc && epc)
- relevant_cap = min(hpc, epc)
- else
- relevant_cap = max(hpc, epc)
-
- if(href_list["show_preferences"])
- client.prefs.ShowChoices(src)
- return 1
-
- if(href_list["ready"])
- var/tready = text2num(href_list["ready"])
- //Avoid updating ready if we're after PREGAME (they should use latejoin instead)
- //This is likely not an actual issue but I don't have time to prove that this
- //no longer is required
- if(SSticker.current_state <= GAME_STATE_PREGAME)
- ready = tready
- //if it's post initialisation and they're trying to observe we do the needful
- if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE)
- ready = tready
- make_me_an_observer()
- return
-
- if(href_list["refresh"])
- src << browse(null, "window=playersetup") //closes the player setup window
- new_player_panel()
-
- if(href_list["late_join"])
- if(!SSticker || !SSticker.IsRoundInProgress())
- to_chat(usr, "The round is either not ready, or has already finished... ")
- return
-
- if(href_list["late_join"] == "override")
- LateChoices()
- return
-
- if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
- to_chat(usr, "[CONFIG_GET(string/hard_popcap_message)] ")
-
- var/queue_position = SSticker.queued_players.Find(usr)
- if(queue_position == 1)
- to_chat(usr, "You are next in line to join the game. You will be notified when a slot opens up. ")
- else if(queue_position)
- to_chat(usr, "There are [queue_position-1] players in front of you in the queue to join the game. ")
- else
- SSticker.queued_players += usr
- to_chat(usr, "You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len]. ")
- return
- LateChoices()
-
- if(href_list["manifest"])
- ViewManifest()
-
- if(href_list["SelectedJob"])
-
- if(!GLOB.enter_allowed)
- to_chat(usr, "There is an administrative lock on entering the game! ")
- return
-
- if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
- if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
- to_chat(usr, "Server is full. ")
- return
-
- AttemptLateSpawn(href_list["SelectedJob"])
- return
-
- if(href_list["JoinAsGhostRole"])
- if(!GLOB.enter_allowed)
- to_chat(usr, " There is an administrative lock on entering the game! ")
-
- if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
- if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
- to_chat(usr, "Server is full. ")
- return
-
- var/obj/effect/mob_spawn/MS = pick(GLOB.mob_spawners[href_list["JoinAsGhostRole"]])
- if(MS.attack_ghost(src, latejoinercalling = TRUE))
- SSticker.queued_players -= src
- SSticker.queue_delay = 4
- qdel(src)
-
- if(!ready && href_list["preference"])
- if(client)
- client.prefs.process_link(src, href_list)
- else if(!href_list["late_join"])
- new_player_panel()
-
- if(href_list["showpoll"])
- handle_player_polling()
- return
-
- if(href_list["pollid"])
- var/pollid = href_list["pollid"]
- if(istext(pollid))
- pollid = text2num(pollid)
- if(isnum(pollid) && ISINTEGER(pollid))
- src.poll_player(pollid)
- return
-
- if(href_list["votepollid"] && href_list["votetype"])
- var/pollid = text2num(href_list["votepollid"])
- var/votetype = href_list["votetype"]
- //lets take data from the user to decide what kind of poll this is, without validating it
- //what could go wrong
- switch(votetype)
- if(POLLTYPE_OPTION)
- var/optionid = text2num(href_list["voteoptionid"])
- if(vote_on_poll(pollid, optionid))
- to_chat(usr, "Vote successful. ")
- else
- to_chat(usr, "Vote failed, please try again or contact an administrator. ")
- if(POLLTYPE_TEXT)
- var/replytext = href_list["replytext"]
- if(log_text_poll_reply(pollid, replytext))
- to_chat(usr, "Feedback logging successful. ")
- else
- to_chat(usr, "Feedback logging failed, please try again or contact an administrator. ")
- if(POLLTYPE_RATING)
- var/id_min = text2num(href_list["minid"])
- var/id_max = text2num(href_list["maxid"])
-
- if( (id_max - id_min) > 100 ) //Basic exploit prevention
- //(protip, this stops no exploits)
- to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
- return
-
- for(var/optionid = id_min; optionid <= id_max; optionid++)
- if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to
- var/rating
- if(href_list["o[optionid]"] == "abstain")
- rating = null
- else
- rating = text2num(href_list["o[optionid]"])
- if(!isnum(rating) || !ISINTEGER(rating))
- return
-
- if(!vote_on_numval_poll(pollid, optionid, rating))
- to_chat(usr, "Vote failed, please try again or contact an administrator. ")
- return
- to_chat(usr, "Vote successful. ")
- if(POLLTYPE_MULTI)
- var/id_min = text2num(href_list["minoptionid"])
- var/id_max = text2num(href_list["maxoptionid"])
-
- if( (id_max - id_min) > 100 ) //Basic exploit prevention
- to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
- return
-
- for(var/optionid = id_min; optionid <= id_max; optionid++)
- if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected
- var/i = vote_on_multi_poll(pollid, optionid)
- switch(i)
- if(0)
- continue
- if(1)
- to_chat(usr, "Vote failed, please try again or contact an administrator. ")
- return
- if(2)
- to_chat(usr, "Maximum replies reached. ")
- break
- to_chat(usr, "Vote successful. ")
- if(POLLTYPE_IRV)
- if (!href_list["IRVdata"])
- to_chat(src, "No ordering data found. Please try again or contact an administrator. ")
- return
- var/list/votelist = splittext(href_list["IRVdata"], ",")
- if (!vote_on_irv_poll(pollid, votelist))
- to_chat(src, "Vote failed, please try again or contact an administrator. ")
- return
- to_chat(src, "Vote successful. ")
-
-//When you cop out of the round (NB: this HAS A SLEEP FOR PLAYER INPUT IN IT)
-/mob/dead/new_player/proc/make_me_an_observer()
- if(QDELETED(src) || !src.client)
- ready = PLAYER_NOT_READY
- return FALSE
-
- var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No")
-
- if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes")
- ready = PLAYER_NOT_READY
- src << browse(null, "window=playersetup") //closes the player setup window
- new_player_panel()
- return FALSE
-
- var/mob/dead/observer/observer = new()
- spawning = TRUE
-
- observer.started_as_observer = TRUE
- close_spawn_windows()
- var/obj/effect/landmark/observer_start/O = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list
- to_chat(src, "Now teleporting. ")
- if (O)
- observer.forceMove(O.loc)
- else
- to_chat(src, "Teleporting failed. Ahelp an admin please ")
- stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
- observer.key = key
- observer.client = client
- observer.set_ghost_appearance()
- if(observer.client && observer.client.prefs)
- observer.real_name = observer.client.prefs.real_name
- observer.name = observer.real_name
- observer.update_icon()
- observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
- QDEL_NULL(mind)
- qdel(src)
- return TRUE
-
-/proc/get_job_unavailable_error_message(retval, jobtitle)
- switch(retval)
- if(JOB_AVAILABLE)
- return "[jobtitle] is available."
- if(JOB_UNAVAILABLE_GENERIC)
- return "[jobtitle] is unavailable."
- if(JOB_UNAVAILABLE_BANNED)
- return "You are currently banned from [jobtitle]."
- if(JOB_UNAVAILABLE_PLAYTIME)
- return "You do not have enough relevant playtime for [jobtitle]."
- if(JOB_UNAVAILABLE_ACCOUNTAGE)
- return "Your account is not old enough for [jobtitle]."
- if(JOB_UNAVAILABLE_SLOTFULL)
- return "[jobtitle] is already filled to capacity."
- return "Error: Unknown job availability."
-
-/mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE)
- var/datum/job/job = SSjob.GetJob(rank)
- if(!job)
- return JOB_UNAVAILABLE_GENERIC
- if((job.current_positions >= job.total_positions) && job.total_positions != -1)
- if(job.title == "Assistant")
- 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)
- return JOB_UNAVAILABLE_SLOTFULL
- else
- return JOB_UNAVAILABLE_SLOTFULL
- if(jobban_isbanned(src,rank))
- return JOB_UNAVAILABLE_BANNED
- if(QDELETED(src))
- return JOB_UNAVAILABLE_GENERIC
- if(!job.player_old_enough(client))
- return JOB_UNAVAILABLE_ACCOUNTAGE
- if(job.required_playtime_remaining(client))
- return JOB_UNAVAILABLE_PLAYTIME
- if(latejoin && !job.special_check_latejoin(client))
- return JOB_UNAVAILABLE_GENERIC
- return JOB_AVAILABLE
-
-/mob/dead/new_player/proc/AttemptLateSpawn(rank)
- var/error = IsJobUnavailable(rank)
- if(error != JOB_AVAILABLE)
- alert(src, get_job_unavailable_error_message(error, rank))
- return FALSE
-
- if(SSticker.late_join_disabled)
- alert(src, "An administrator has disabled late join spawning.")
- 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))
- src << alert("The arrivals shuttle is currently malfunctioning! You cannot join.")
- return FALSE
-
- 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/equip = SSjob.EquipRank(character, rank, TRUE)
- 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/obj/screen/splash/Spl = new(character.client, TRUE)
- Spl.Fade(TRUE)
- character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
-
- character.update_parallax_teleport()
-
- SSticker.minds += character.mind
-
- var/mob/living/carbon/human/humanc
- if(ishuman(character))
- humanc = character //Let's retypecast the var to be human,
-
- if(humanc) //These procs all expect humans
- GLOB.data_core.manifest_inject(humanc)
- if(SSshuttle.arrivals)
- SSshuttle.arrivals.QueueAnnounce(humanc, rank)
- else
- AnnounceArrival(humanc, rank)
- AddEmploymentContract(humanc)
- if(GLOB.highlander)
- to_chat(humanc, "THERE CAN BE ONLY ONE!!! ")
- humanc.make_scottish()
-
- if(GLOB.summon_guns_triggered)
- give_guns(humanc)
- if(GLOB.summon_magic_triggered)
- give_magic(humanc)
-
- GLOB.joined_player_list += character.ckey
- GLOB.latejoiners += character
-
- if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais.
- if(SSshuttle.emergency)
- switch(SSshuttle.emergency.mode)
- if(SHUTTLE_RECALL, SHUTTLE_IDLE)
- SSticker.mode.make_antag_chance(humanc)
- if(SHUTTLE_CALL)
- if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
- SSticker.mode.make_antag_chance(humanc)
-
- if(humanc && CONFIG_GET(flag/roundstart_traits))
- SSquirks.AssignQuirks(humanc, humanc.client, TRUE, FALSE, job, FALSE)
-
- log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
-
-/mob/dead/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee)
- //TODO: figure out a way to exclude wizards/nukeops/demons from this.
- for(var/C in GLOB.employmentCabinets)
- var/obj/structure/filingcabinet/employment/employmentCabinet = C
- if(!employmentCabinet.virgin)
- employmentCabinet.addFile(employee)
-
-
-/mob/dead/new_player/proc/LateChoices()
-
- var/level = "green"
- switch(GLOB.security_level)
- if(SEC_LEVEL_BLUE)
- level = "blue"
- if(SEC_LEVEL_AMBER)
- level = "amber"
- if(SEC_LEVEL_RED)
- level = "red"
- if(SEC_LEVEL_DELTA)
- level = "delta"
-
- var/dat = "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)] Alert Level: [capitalize(level)]
"
-
- if(SSshuttle.emergency)
- switch(SSshuttle.emergency.mode)
- if(SHUTTLE_ESCAPE)
- dat += "The station has been evacuated.
"
- if(SHUTTLE_CALL)
- if(!SSshuttle.canRecall())
- dat += "The station is currently undergoing evacuation procedures.
"
-
- var/available_job_count = 0
- for(var/datum/job/job in SSjob.occupations)
- if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
- available_job_count++
- for(var/spawner in GLOB.mob_spawners)
- if(!LAZYLEN(spawner))
- continue
- var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner])
- if(!istype(S) || !S.can_latejoin())
- continue
- available_job_count++
- break
-
- if(!available_job_count)
- dat += "There are currently no open positions!
"
-
- else
- dat += "Choose from the following open positions:
"
- var/list/categorizedJobs = list(
- "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"),
- "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"),
- "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"),
- "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE),
- "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"),
- "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"),
- "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"),
- "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE),
- "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"),
- "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"),
- )
- for(var/spawner in GLOB.mob_spawners)
- if(!LAZYLEN(spawner))
- continue
- var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner])
- if(!istype(S) || !S.can_latejoin())
- continue
- categorizedJobs["Ghost Role"]["jobs"] += spawner
-
- for(var/datum/job/job in SSjob.occupations)
- if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
- var/categorized = FALSE
- for(var/jobcat in categorizedJobs)
- var/list/jobs = categorizedJobs[jobcat]["jobs"]
- if(job.title in categorizedJobs[jobcat]["titles"])
- categorized = TRUE
- if(jobcat == "Command")
-
- if(job.title == "Captain") // Put captain at top of command jobs
- jobs.Insert(1, job)
- else
- jobs += job
- else // Put heads at top of non-command jobs
- if(job.title in GLOB.command_positions)
- jobs.Insert(1, job)
- else
- jobs += job
- if(!categorized)
- categorizedJobs["Miscellaneous"]["jobs"] += job
-
-
- dat += ""
- for(var/jobcat in categorizedJobs)
- if(categorizedJobs[jobcat]["colBreak"])
- dat += " "
- if(!length(categorizedJobs[jobcat]["jobs"]))
- continue
- var/color = categorizedJobs[jobcat]["color"]
- dat += ""
- dat += "[jobcat] "
- for(var/datum/job/job in categorizedJobs[jobcat]["jobs"])
- var/position_class = "otherPosition"
- if(job.title in GLOB.command_positions)
- position_class = "commandPosition"
- if(job in SSjob.prioritized_jobs)
- dat += "[job.title] ([job.current_positions]) "
- else
- dat += "[job.title] ([job.current_positions]) "
- categorizedJobs[jobcat]["jobs"] -= job
-
- for(var/spawner in categorizedJobs[jobcat]["jobs"])
- dat += "[spawner] "
-
- dat += " "
- dat += "
"
- dat += ""
-
- // Removing the old window method but leaving it here for reference
- //src << browse(dat, "window=latechoices;size=300x640;can_close=1")
-
- // Added the new browser window method
- var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580)
- popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
- popup.set_content(dat)
- popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc
-
-
-/mob/dead/new_player/proc/create_character(transfer_after)
- spawning = 1
- close_spawn_windows()
-
- var/mob/living/carbon/human/H = new(loc)
-
- var/frn = CONFIG_GET(flag/force_random_names)
- if(!frn)
- frn = jobban_isbanned(src, "appearance")
- if(QDELETED(src))
- return
- if(frn)
- client.prefs.random_character()
- client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
- client.prefs.copy_to(H)
- H.dna.update_dna_identity()
- if(mind)
- if(transfer_after)
- mind.late_joiner = TRUE
- mind.active = 0 //we wish to transfer the key manually
- mind.transfer_to(H) //won't transfer key since the mind is not active
-
- H.name = real_name
-
- . = H
- 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)
-
-/mob/dead/new_player/proc/ViewManifest()
- var/dat = ""
- dat += "Crew Manifest "
- dat += GLOB.data_core.get_manifest(OOC = 1)
-
- src << browse(dat, "window=manifest;size=387x420;can_close=1")
-
-/mob/dead/new_player/Move()
- return 0
-
-
-/mob/dead/new_player/proc/close_spawn_windows()
-
- src << browse(null, "window=latechoices") //closes late choices window
- src << browse(null, "window=playersetup") //closes the player setup window
- src << browse(null, "window=preferences") //closes job selection
- src << browse(null, "window=mob_occupation")
- src << browse(null, "window=latechoices") //closes late job selection
+#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
+ canmove = FALSE
+
+ anchored = TRUE // don't get pushed around
+
+ 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/ineligible_for_roles = FALSE
+
+/mob/dead/new_player/Initialize()
+ if(client && SSticker.state == GAME_STATE_STARTUP)
+ var/obj/screen/splash/S = new(client, TRUE, TRUE)
+ S.Fade(TRUE)
+
+ if(length(GLOB.newplayer_start))
+ forceMove(pick(GLOB.newplayer_start))
+ else
+ forceMove(locate(1,1,1))
+
+ ComponentInitialize()
+
+ . = ..()
+
+/mob/dead/new_player/prepare_huds()
+ return
+
+/mob/dead/new_player/proc/new_player_panel()
+ var/output = "Welcome, [client ? client.prefs.real_name : "Unknown User"]
"
+ output += "Setup Character
"
+
+ if(SSticker.current_state <= GAME_STATE_PREGAME)
+ switch(ready)
+ if(PLAYER_NOT_READY)
+ output += "\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | Not Ready | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]
"
+ if(PLAYER_READY_TO_PLAY)
+ output += "\[ Ready | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]
"
+ if(PLAYER_READY_TO_OBSERVE)
+ output += "\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | Observe \]
"
+ else
+ output += "View the Crew Manifest
"
+ output += "Join Game!
"
+ output += "[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]
"
+
+ if(!IsGuestKey(src.key))
+ if (SSdbcore.Connect())
+ var/isadmin = 0
+ if(src.client && src.client.holder)
+ isadmin = 1
+ var/datum/DBQuery/query_get_new_polls = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[sanitizeSQL(ckey)]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[sanitizeSQL(ckey)]\")")
+ var/rs = REF(src)
+ if(query_get_new_polls.Execute())
+ var/newpoll = 0
+ if(query_get_new_polls.NextRow())
+ newpoll = 1
+
+ if(newpoll)
+ output += "Show Player Polls (NEW!)
"
+ else
+ output += "Show Player Polls
"
+ qdel(query_get_new_polls)
+ if(QDELETED(src))
+ return
+
+ output += " "
+
+ //src << browse(output,"window=playersetup;size=210x240;can_close=0")
+ var/datum/browser/popup = new(src, "playersetup", "New Player Options
", 250, 265)
+ popup.set_window_options("can_close=0")
+ popup.set_content(output)
+ popup.open(FALSE)
+
+/mob/dead/new_player/Topic(href, href_list[])
+ if(src != usr)
+ return 0
+
+ if(!client)
+ return 0
+
+ //Determines Relevent Population Cap
+ var/relevant_cap
+ var/hpc = CONFIG_GET(number/hard_popcap)
+ var/epc = CONFIG_GET(number/extreme_popcap)
+ if(hpc && epc)
+ relevant_cap = min(hpc, epc)
+ else
+ relevant_cap = max(hpc, epc)
+
+ if(href_list["show_preferences"])
+ client.prefs.ShowChoices(src)
+ return 1
+
+ if(href_list["ready"])
+ var/tready = text2num(href_list["ready"])
+ //Avoid updating ready if we're after PREGAME (they should use latejoin instead)
+ //This is likely not an actual issue but I don't have time to prove that this
+ //no longer is required
+ if(SSticker.current_state <= GAME_STATE_PREGAME)
+ ready = tready
+ //if it's post initialisation and they're trying to observe we do the needful
+ if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE)
+ ready = tready
+ make_me_an_observer()
+ return
+
+ if(href_list["refresh"])
+ src << browse(null, "window=playersetup") //closes the player setup window
+ new_player_panel()
+
+ if(href_list["late_join"])
+ if(!SSticker || !SSticker.IsRoundInProgress())
+ to_chat(usr, "The round is either not ready, or has already finished... ")
+ return
+
+ if(href_list["late_join"] == "override")
+ LateChoices()
+ return
+
+ if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
+ to_chat(usr, "[CONFIG_GET(string/hard_popcap_message)] ")
+
+ var/queue_position = SSticker.queued_players.Find(usr)
+ if(queue_position == 1)
+ to_chat(usr, "You are next in line to join the game. You will be notified when a slot opens up. ")
+ else if(queue_position)
+ to_chat(usr, "There are [queue_position-1] players in front of you in the queue to join the game. ")
+ else
+ SSticker.queued_players += usr
+ to_chat(usr, "You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len]. ")
+ return
+ LateChoices()
+
+ if(href_list["manifest"])
+ ViewManifest()
+
+ if(href_list["SelectedJob"])
+
+ if(!GLOB.enter_allowed)
+ to_chat(usr, "There is an administrative lock on entering the game! ")
+ return
+
+ if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
+ if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
+ to_chat(usr, "Server is full. ")
+ return
+
+ AttemptLateSpawn(href_list["SelectedJob"])
+ return
+
+ if(href_list["JoinAsGhostRole"])
+ if(!GLOB.enter_allowed)
+ to_chat(usr, " There is an administrative lock on entering the game! ")
+
+ if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
+ if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
+ to_chat(usr, "Server is full. ")
+ return
+
+ var/obj/effect/mob_spawn/MS = pick(GLOB.mob_spawners[href_list["JoinAsGhostRole"]])
+ if(MS.attack_ghost(src, latejoinercalling = TRUE))
+ SSticker.queued_players -= src
+ SSticker.queue_delay = 4
+ qdel(src)
+
+ if(!ready && href_list["preference"])
+ if(client)
+ client.prefs.process_link(src, href_list)
+ else if(!href_list["late_join"])
+ new_player_panel()
+
+ if(href_list["showpoll"])
+ handle_player_polling()
+ return
+
+ if(href_list["pollid"])
+ var/pollid = href_list["pollid"]
+ if(istext(pollid))
+ pollid = text2num(pollid)
+ if(isnum(pollid) && ISINTEGER(pollid))
+ src.poll_player(pollid)
+ return
+
+ if(href_list["votepollid"] && href_list["votetype"])
+ var/pollid = text2num(href_list["votepollid"])
+ var/votetype = href_list["votetype"]
+ //lets take data from the user to decide what kind of poll this is, without validating it
+ //what could go wrong
+ switch(votetype)
+ if(POLLTYPE_OPTION)
+ var/optionid = text2num(href_list["voteoptionid"])
+ if(vote_on_poll(pollid, optionid))
+ to_chat(usr, "Vote successful. ")
+ else
+ to_chat(usr, "Vote failed, please try again or contact an administrator. ")
+ if(POLLTYPE_TEXT)
+ var/replytext = href_list["replytext"]
+ if(log_text_poll_reply(pollid, replytext))
+ to_chat(usr, "Feedback logging successful. ")
+ else
+ to_chat(usr, "Feedback logging failed, please try again or contact an administrator. ")
+ if(POLLTYPE_RATING)
+ var/id_min = text2num(href_list["minid"])
+ var/id_max = text2num(href_list["maxid"])
+
+ if( (id_max - id_min) > 100 ) //Basic exploit prevention
+ //(protip, this stops no exploits)
+ to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
+ return
+
+ for(var/optionid = id_min; optionid <= id_max; optionid++)
+ if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to
+ var/rating
+ if(href_list["o[optionid]"] == "abstain")
+ rating = null
+ else
+ rating = text2num(href_list["o[optionid]"])
+ if(!isnum(rating) || !ISINTEGER(rating))
+ return
+
+ if(!vote_on_numval_poll(pollid, optionid, rating))
+ to_chat(usr, "Vote failed, please try again or contact an administrator. ")
+ return
+ to_chat(usr, "Vote successful. ")
+ if(POLLTYPE_MULTI)
+ var/id_min = text2num(href_list["minoptionid"])
+ var/id_max = text2num(href_list["maxoptionid"])
+
+ if( (id_max - id_min) > 100 ) //Basic exploit prevention
+ to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.")
+ return
+
+ for(var/optionid = id_min; optionid <= id_max; optionid++)
+ if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected
+ var/i = vote_on_multi_poll(pollid, optionid)
+ switch(i)
+ if(0)
+ continue
+ if(1)
+ to_chat(usr, "Vote failed, please try again or contact an administrator. ")
+ return
+ if(2)
+ to_chat(usr, "Maximum replies reached. ")
+ break
+ to_chat(usr, "Vote successful. ")
+ if(POLLTYPE_IRV)
+ if (!href_list["IRVdata"])
+ to_chat(src, "No ordering data found. Please try again or contact an administrator. ")
+ return
+ var/list/votelist = splittext(href_list["IRVdata"], ",")
+ if (!vote_on_irv_poll(pollid, votelist))
+ to_chat(src, "Vote failed, please try again or contact an administrator. ")
+ return
+ to_chat(src, "Vote successful. ")
+
+//When you cop out of the round (NB: this HAS A SLEEP FOR PLAYER INPUT IN IT)
+/mob/dead/new_player/proc/make_me_an_observer()
+ if(QDELETED(src) || !src.client)
+ ready = PLAYER_NOT_READY
+ return FALSE
+
+ var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No")
+
+ if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes")
+ ready = PLAYER_NOT_READY
+ src << browse(null, "window=playersetup") //closes the player setup window
+ new_player_panel()
+ return FALSE
+
+ var/mob/dead/observer/observer = new()
+ spawning = TRUE
+
+ observer.started_as_observer = TRUE
+ close_spawn_windows()
+ var/obj/effect/landmark/observer_start/O = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list
+ to_chat(src, "Now teleporting. ")
+ if (O)
+ observer.forceMove(O.loc)
+ else
+ to_chat(src, "Teleporting failed. Ahelp an admin please ")
+ stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
+ observer.key = key
+ observer.client = client
+ observer.set_ghost_appearance()
+ if(observer.client && observer.client.prefs)
+ observer.real_name = observer.client.prefs.real_name
+ observer.name = observer.real_name
+ observer.update_icon()
+ observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
+ QDEL_NULL(mind)
+ qdel(src)
+ return TRUE
+
+/proc/get_job_unavailable_error_message(retval, jobtitle)
+ switch(retval)
+ if(JOB_AVAILABLE)
+ return "[jobtitle] is available."
+ if(JOB_UNAVAILABLE_GENERIC)
+ return "[jobtitle] is unavailable."
+ if(JOB_UNAVAILABLE_BANNED)
+ return "You are currently banned from [jobtitle]."
+ if(JOB_UNAVAILABLE_PLAYTIME)
+ return "You do not have enough relevant playtime for [jobtitle]."
+ if(JOB_UNAVAILABLE_ACCOUNTAGE)
+ return "Your account is not old enough for [jobtitle]."
+ if(JOB_UNAVAILABLE_SLOTFULL)
+ return "[jobtitle] is already filled to capacity."
+ return "Error: Unknown job availability."
+
+/mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE)
+ var/datum/job/job = SSjob.GetJob(rank)
+ if(!job)
+ return JOB_UNAVAILABLE_GENERIC
+ if((job.current_positions >= job.total_positions) && job.total_positions != -1)
+ if(job.title == "Assistant")
+ 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)
+ return JOB_UNAVAILABLE_SLOTFULL
+ else
+ return JOB_UNAVAILABLE_SLOTFULL
+ if(jobban_isbanned(src,rank))
+ return JOB_UNAVAILABLE_BANNED
+ if(QDELETED(src))
+ return JOB_UNAVAILABLE_GENERIC
+ if(!job.player_old_enough(client))
+ return JOB_UNAVAILABLE_ACCOUNTAGE
+ if(job.required_playtime_remaining(client))
+ return JOB_UNAVAILABLE_PLAYTIME
+ if(latejoin && !job.special_check_latejoin(client))
+ return JOB_UNAVAILABLE_GENERIC
+ return JOB_AVAILABLE
+
+/mob/dead/new_player/proc/AttemptLateSpawn(rank)
+ var/error = IsJobUnavailable(rank)
+ if(error != JOB_AVAILABLE)
+ alert(src, get_job_unavailable_error_message(error, rank))
+ return FALSE
+
+ if(SSticker.late_join_disabled)
+ alert(src, "An administrator has disabled late join spawning.")
+ 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))
+ src << alert("The arrivals shuttle is currently malfunctioning! You cannot join.")
+ return FALSE
+
+ 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/equip = SSjob.EquipRank(character, rank, TRUE)
+ 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/obj/screen/splash/Spl = new(character.client, TRUE)
+ Spl.Fade(TRUE)
+ character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
+
+ character.update_parallax_teleport()
+
+ SSticker.minds += character.mind
+
+ var/mob/living/carbon/human/humanc
+ if(ishuman(character))
+ humanc = character //Let's retypecast the var to be human,
+
+ if(humanc) //These procs all expect humans
+ GLOB.data_core.manifest_inject(humanc)
+ if(SSshuttle.arrivals)
+ SSshuttle.arrivals.QueueAnnounce(humanc, rank)
+ else
+ AnnounceArrival(humanc, rank)
+ AddEmploymentContract(humanc)
+ if(GLOB.highlander)
+ to_chat(humanc, "THERE CAN BE ONLY ONE!!! ")
+ humanc.make_scottish()
+
+ if(GLOB.summon_guns_triggered)
+ give_guns(humanc)
+ if(GLOB.summon_magic_triggered)
+ give_magic(humanc)
+
+ GLOB.joined_player_list += character.ckey
+ GLOB.latejoiners += character
+
+ if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais.
+ if(SSshuttle.emergency)
+ switch(SSshuttle.emergency.mode)
+ if(SHUTTLE_RECALL, SHUTTLE_IDLE)
+ SSticker.mode.make_antag_chance(humanc)
+ if(SHUTTLE_CALL)
+ if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
+ SSticker.mode.make_antag_chance(humanc)
+
+ if(humanc && CONFIG_GET(flag/roundstart_traits))
+ SSquirks.AssignQuirks(humanc, humanc.client, TRUE, FALSE, job, FALSE)
+
+ log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
+
+/mob/dead/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee)
+ //TODO: figure out a way to exclude wizards/nukeops/demons from this.
+ for(var/C in GLOB.employmentCabinets)
+ var/obj/structure/filingcabinet/employment/employmentCabinet = C
+ if(!employmentCabinet.virgin)
+ employmentCabinet.addFile(employee)
+
+
+/mob/dead/new_player/proc/LateChoices()
+
+ var/level = "green"
+ switch(GLOB.security_level)
+ if(SEC_LEVEL_GREEN)
+ level = "green"
+ if(SEC_LEVEL_BLUE)
+ level = "blue"
+ if(SEC_LEVEL_AMBER)
+ level = "amber"
+ if(SEC_LEVEL_RED)
+ level = "red"
+ if(SEC_LEVEL_DELTA)
+ level = "delta"
+
+ var/dat = "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)] Alert Level: [capitalize(level)]
"
+ if(SSshuttle.emergency)
+ switch(SSshuttle.emergency.mode)
+ if(SHUTTLE_ESCAPE)
+ dat += "The station has been evacuated.
"
+ if(SHUTTLE_CALL)
+ if(!SSshuttle.canRecall())
+ dat += "The station is currently undergoing evacuation procedures.
"
+ for(var/datum/job/prioritized_job in SSjob.prioritized_jobs)
+ if(prioritized_job.current_positions >= prioritized_job.total_positions)
+ SSjob.prioritized_jobs -= prioritized_job
+ dat += ""
+ var/column_counter = 0
+ var/free_space = 0
+ for(var/list/category in list(GLOB.command_positions) + list(GLOB.supply_positions) + list(GLOB.engineering_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions))
+ var/cat_color = "fff" //random default
+ if(SSjob.name_occupations && SSjob.name_occupations[category[1]])
+ cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color
+ else
+ cat_color = SSjob.occupations[category[1]].selection_color
+ dat += ""
+ dat += "[SSjob.name_occupations[category[1]].exp_type_department] "
+
+ var/list/dept_dat = list()
+ for(var/job in category)
+ var/datum/job/job_datum = SSjob.name_occupations[job]
+ if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE)
+ var/command_bold = ""
+ if(job in GLOB.command_positions)
+ command_bold = " command"
+ 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]) "
+ if(!dept_dat.len)
+ dept_dat += "No positions open. "
+ dat += jointext(dept_dat, "")
+ dat += " "
+ column_counter++
+ if(free_space <=4)
+ free_space++
+ if(column_counter > 0 && (column_counter % 3 == 0))
+ dat += " "
+ if(free_space >= 5 && (free_space % 5 == 0) && (column_counter % 3 != 0))
+ free_space = 0
+ column_counter = 0
+ dat += " "
+
+ dat += "
"
+
+ var/available_ghosts = 0
+ for(var/spawner in GLOB.mob_spawners)
+ if(!LAZYLEN(spawner))
+ continue
+ var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner])
+ if(!istype(S) || !S.can_latejoin())
+ continue
+ available_ghosts++
+ break
+
+ if(!available_ghosts)
+ dat += "There are currently no open ghost spawners.
"
+ else
+ var/list/categorizedJobs = list("Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"))
+ for(var/spawner in GLOB.mob_spawners)
+ if(!LAZYLEN(spawner))
+ continue
+ var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner])
+ if(!istype(S) || !S.can_latejoin())
+ continue
+ categorizedJobs["Ghost Role"]["jobs"] += spawner
+
+ dat += ""
+ for(var/jobcat in categorizedJobs)
+ if(!length(categorizedJobs[jobcat]["jobs"]))
+ continue
+ var/color = categorizedJobs[jobcat]["color"]
+ dat += ""
+ dat += "[jobcat] "
+ for(var/spawner in categorizedJobs[jobcat]["jobs"])
+ dat += "[spawner] "
+
+ dat += " "
+ dat += "
"
+ dat += ""
+
+ var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 720, 600)
+ popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
+ popup.set_content(jointext(dat, ""))
+ popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc
+
+/mob/dead/new_player/proc/create_character(transfer_after)
+ spawning = 1
+ close_spawn_windows()
+
+ var/mob/living/carbon/human/H = new(loc)
+
+ var/frn = CONFIG_GET(flag/force_random_names)
+ if(!frn)
+ frn = jobban_isbanned(src, "appearance")
+ if(QDELETED(src))
+ return
+ if(frn)
+ client.prefs.random_character()
+ client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
+ client.prefs.copy_to(H)
+ H.dna.update_dna_identity()
+ if(mind)
+ if(transfer_after)
+ mind.late_joiner = TRUE
+ mind.active = 0 //we wish to transfer the key manually
+ mind.transfer_to(H) //won't transfer key since the mind is not active
+
+ H.name = real_name
+
+ . = H
+ 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)
+
+/mob/dead/new_player/proc/ViewManifest()
+ var/dat = ""
+ dat += "Crew Manifest "
+ dat += GLOB.data_core.get_manifest(OOC = 1)
+
+ src << browse(dat, "window=manifest;size=387x420;can_close=1")
+
+/mob/dead/new_player/Move()
+ return 0
+
+
+/mob/dead/new_player/proc/close_spawn_windows()
+
+ src << browse(null, "window=latechoices") //closes late choices window
+ src << browse(null, "window=playersetup") //closes the player setup window
+ src << browse(null, "window=preferences") //closes job selection
+ src << browse(null, "window=mob_occupation")
+ src << browse(null, "window=latechoices") //closes late job selection
+
+/* Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense.
+ A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled
+ Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not availible"
+ Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role
+ This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong
+*/
+
+/mob/dead/new_player/proc/check_preferences()
+ if(!client)
+ return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe.
+ if(client.prefs.joblessrole != RETURNTOLOBBY)
+ return TRUE
+ // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so.
+ var/has_antags = FALSE
+ if(client.prefs.be_special.len > 0)
+ has_antags = TRUE
+ if(client.prefs.job_preferences.len == 0)
+ if(!ineligible_for_roles)
+ to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences. ")
+ ineligible_for_roles = TRUE
+ ready = PLAYER_NOT_READY
+ if(has_antags)
+ log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.")
+ message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.")
+
+ return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
+ return TRUE
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index 6e91b58506..b08fadefcb 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -24,50 +24,35 @@
age = rand(AGE_MIN,AGE_MAX)
/datum/preferences/proc/update_preview_icon()
- // Silicons only need a very basic preview since there is no customization for them.
-// var/wide_icon = FALSE //CITDEL THINGS
-// if(features["taur"] != "None")
-// wide_icon = TRUE
- if(job_engsec_high)
- switch(job_engsec_high)
- if(AI_JF)
- parent.show_character_previews(image('icons/mob/ai.dmi', resolve_ai_icon(preferred_ai_core_display), dir = SOUTH))
- return
- if(CYBORG)
- parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH))
- return
+ // Determine what job is marked as 'High' priority, and dress them up as such.
+ var/datum/job/previewJob
+ var/highest_pref = 0
+ for(var/job in job_preferences)
+ if(job_preferences[job] > highest_pref)
+ previewJob = SSjob.GetJob(job)
+ highest_pref = job_preferences[job]
+
+ if(previewJob)
+ // Silicons only need a very basic preview since there is no customization for them.
+ if(istype(previewJob,/datum/job/ai))
+ parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = resolve_ai_icon(preferred_ai_core_display), dir = SOUTH))
+ return
+ if(istype(previewJob,/datum/job/cyborg))
+ parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH))
+ return
// Set up the dummy for its photoshoot
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
mannequin.cut_overlays()
+ // Apply the Dummy's preview background first so we properly layer everything else on top of it.
mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER))
copy_to(mannequin)
- // Determine what job is marked as 'High' priority, and dress them up as such.
- var/datum/job/previewJob
- var/highRankFlag = job_civilian_high | job_medsci_high | job_engsec_high
-
- if(job_civilian_low & ASSISTANT)
- previewJob = SSjob.GetJob("Assistant")
- else if(highRankFlag)
- var/highDeptFlag
- if(job_civilian_high)
- highDeptFlag = CIVILIAN
- else if(job_medsci_high)
- highDeptFlag = MEDSCI
- else if(job_engsec_high)
- highDeptFlag = ENGSEC
-
- for(var/datum/job/job in SSjob.occupations)
- if(job.flag == highRankFlag && job.department_flag == highDeptFlag)
- previewJob = job
- break
-
if(previewJob)
- if(current_tab != 2)
- mannequin.job = previewJob.title
- previewJob.equip(mannequin, TRUE)
+ mannequin.job = previewJob.title
+ previewJob.equip(mannequin, TRUE, preference_source = parent)
COMPILE_OVERLAYS(mannequin)
parent.show_character_previews(new /mutable_appearance(mannequin))
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
+
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm
new file mode 100644
index 0000000000..020776a75f
--- /dev/null
+++ b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm
@@ -0,0 +1,53 @@
+/datum/sprite_accessory/mam_tails/shark/datashark
+ name = "DataShark"
+ icon_state = "datashark"
+ ckeys_allowed = list("rubyflamewing")
+
+/datum/sprite_accessory/mam_tails_animated/shark/datashark
+ name = "DataShark"
+ icon_state = "datashark"
+ ckeys_allowed = list("rubyflamewing")
+
+/datum/sprite_accessory/mam_body_markings/shark/datashark
+ name = "DataShark"
+ icon_state = "datashark"
+ ckeys_allowed = list("rubyflamewing")
+
+//Sabresune
+/datum/sprite_accessory/mam_ears/sabresune
+ name = "Sabresune"
+ icon_state = "sabresune"
+ ckeys_allowed = list("poojawa")
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_tails/sabresune
+ name = "Sabresune"
+ icon_state = "sabresune"
+ ckeys_allowed = list("poojawa")
+
+/datum/sprite_accessory/mam_tails_animated/sabresune
+ name = "Sabresune"
+ icon_state = "sabresune"
+ ckeys_allowed = list("poojawa")
+
+/datum/sprite_accessory/mam_body_markings/sabresune
+ name = "Sabresune"
+ icon_state = "sabresune"
+ ckeys_allowed = list("poojawa")
+
+//Lunasune
+/datum/sprite_accessory/mam_ears/lunasune
+ name = "lunasune"
+ icon_state = "lunasune"
+ ckeys_allowed = list("invader4352")
+
+/datum/sprite_accessory/mam_tails/lunasune
+ name = "lunasune"
+ icon_state = "lunasune"
+ ckeys_allowed = list("invader4352")
+
+/datum/sprite_accessory/mam_tails_animated/lunasune
+ name = "lunasune"
+ icon_state = "lunasune"
+ ckeys_allowed = list("invader4352")
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
index 5e24d0630b..dd66f68e5d 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
@@ -61,6 +61,17 @@
var/dimension_y = 32
var/center = FALSE //Should we center the sprite?
+ //Special / holdover traits for Citadel specific sprites.
+ var/extra = FALSE
+ var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
+ var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ var/extra2 = FALSE
+ var/extra2_color_src = MUTCOLORS3
+ var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+ //for snowflake/donor specific sprites
+ var/list/ckeys_allowed
+
/datum/sprite_accessory/underwear
icon = 'icons/mob/underwear.dmi'
var/has_color = FALSE
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm
new file mode 100644
index 0000000000..6c0659f851
--- /dev/null
+++ b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm
@@ -0,0 +1,53 @@
+
+/******************************************
+*********** Xeno Dorsal Tubes *************
+*******************************************/
+/datum/sprite_accessory/xeno_dorsal
+ icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
+
+/datum/sprite_accessory/xeno_dorsal/standard
+ name = "Standard"
+ icon_state = "standard"
+
+/datum/sprite_accessory/xeno_dorsal/royal
+ name = "Royal"
+ icon_state = "royal"
+
+/datum/sprite_accessory/xeno_dorsal/down
+ name = "Dorsal Down"
+ icon_state = "down"
+
+/******************************************
+************* Xeno Tails ******************
+*******************************************/
+/datum/sprite_accessory/xeno_tail
+ icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
+
+/datum/sprite_accessory/xeno_tail/none
+ name = "None"
+
+/datum/sprite_accessory/xeno_tail/standard
+ name = "Xenomorph Tail"
+ icon_state = "xeno"
+
+/******************************************
+************* Xeno Heads ******************
+*******************************************/
+/datum/sprite_accessory/xeno_head
+ icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
+
+/datum/sprite_accessory/xeno_head/standard
+ name = "Standard"
+ icon_state = "standard"
+
+/datum/sprite_accessory/xeno_head/royal
+ name = "royal"
+ icon_state = "royal"
+
+/datum/sprite_accessory/xeno_head/hollywood
+ name = "hollywood"
+ icon_state = "hollywood"
+
+/datum/sprite_accessory/xeno_head/warrior
+ name = "warrior"
+ icon_state = "warrior"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
index 6bce18d7ce..2f1d48cfa7 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
@@ -1,6 +1,6 @@
-//////////.//////////////////
-// MutantParts Definitions //
-/////////////////////////////
+/******************************************
+************* Lizard Markings *************
+*******************************************/
/datum/sprite_accessory/body_markings
icon = 'icons/mob/mutant_bodyparts.dmi'
@@ -22,4 +22,271 @@
/datum/sprite_accessory/body_markings/lbelly
name = "Light Belly"
icon_state = "lbelly"
- gender_specific = 1
\ No newline at end of file
+ gender_specific = 1
+
+/******************************************
+************ Furry Markings ***************
+*******************************************/
+
+// These are all color matrixed and applied per-limb by default. you MUST comply with this if you want to have your markings work --Pooj
+// use the HumanScissors tool to break your sprite up into the zones easier.
+// Although Byond supposedly doesn't have an icon limit anymore of 512 states after 512.1478, just be careful about too many additions.
+
+/datum/sprite_accessory/mam_body_markings
+ extra = FALSE
+ extra2 = FALSE
+ color_src = MATRIXED
+ gender_specific = 0
+ icon = 'modular_citadel/icons/mob/mam_markings.dmi'
+
+/datum/sprite_accessory/mam_body_markings/none
+ name = "None"
+ icon_state = "none"
+ ckeys_allowed = list("yousshouldnteverbeseeingthisyoumeme")
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/plain
+ name = "Plain"
+ icon_state = "plain"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/redpanda
+ name = "Redpanda"
+ icon_state = "redpanda"
+
+/datum/sprite_accessory/mam_body_markings/bee
+ name = "Bee"
+ icon_state = "bee"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/belly
+ name = "Belly"
+ icon_state = "belly"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/bellyslim
+ name = "Bellyslim"
+ icon_state = "bellyslim"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/corgi
+ name = "Corgi"
+ icon_state = "corgi"
+
+/datum/sprite_accessory/mam_body_markings/cow
+ name = "Bovine"
+ icon_state = "bovine"
+
+/datum/sprite_accessory/mam_body_markings/corvid
+ name = "Corvid"
+ icon_state = "corvid"
+
+/datum/sprite_accessory/mam_body_markings/dalmation
+ name = "Dalmation"
+ icon_state = "dalmation"
+
+/datum/sprite_accessory/mam_body_markings/deer
+ name = "Deer"
+ icon_state = "deer"
+
+/datum/sprite_accessory/mam_body_markings/dog
+ name = "Dog"
+ icon_state = "dog"
+
+/datum/sprite_accessory/mam_body_markings/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+/datum/sprite_accessory/mam_body_markings/fennec
+ name = "Fennec"
+ icon_state = "Fennec"
+
+/datum/sprite_accessory/mam_body_markings/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_body_markings/frog
+ name = "Frog"
+ icon_state = "frog"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/goat
+ name = "Goat"
+ icon_state = "goat"
+
+/datum/sprite_accessory/mam_body_markings/handsfeet
+ name = "Handsfeet"
+ icon_state = "handsfeet"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/hawk
+ name = "Hawk"
+ icon_state = "hawk"
+
+/datum/sprite_accessory/mam_body_markings/husky
+ name = "Husky"
+ icon_state = "husky"
+
+/datum/sprite_accessory/mam_body_markings/hyena
+ name = "Hyena"
+ icon_state = "hyena"
+
+/datum/sprite_accessory/mam_body_markings/lab
+ name = "Lab"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_body_markings/insect
+ name = "Insect"
+ icon_state = "insect"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/otie
+ name = "Otie"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_body_markings/otter
+ name = "Otter"
+ icon_state = "otter"
+
+/datum/sprite_accessory/mam_body_markings/orca
+ name = "Orca"
+ icon_state = "orca"
+
+/datum/sprite_accessory/mam_body_markings/panther
+ name = "Panther"
+ icon_state = "panther"
+
+/datum/sprite_accessory/mam_body_markings/possum
+ name = "Possum"
+ icon_state = "possum"
+
+/datum/sprite_accessory/mam_body_markings/raccoon
+ name = "Raccoon"
+ icon_state = "raccoon"
+
+/datum/sprite_accessory/mam_body_markings/pede
+ name = "Scolipede"
+ icon_state = "scolipede"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_body_markings/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_body_markings/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_body_markings/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+
+/datum/sprite_accessory/mam_body_markings/tajaran
+ name = "Tajaran"
+ icon_state = "tajaran"
+
+/datum/sprite_accessory/mam_body_markings/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_body_markings/turian
+ name = "Turian"
+ icon_state = "turian"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/mam_body_markings/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+
+/datum/sprite_accessory/mam_body_markings/xeno
+ name = "Xeno"
+ icon_state = "xeno"
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/******************************************
+************* Insect Markings *************
+*******************************************/
+
+/datum/sprite_accessory/insect_fluff
+ icon = 'icons/mob/wings.dmi'
+ color_src = 0
+
+/datum/sprite_accessory/insect_fluff/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/insect_fluff/plain
+ name = "Plain"
+ icon_state = "plain"
+
+/datum/sprite_accessory/insect_fluff/reddish
+ name = "Reddish"
+ icon_state = "redish"
+
+/datum/sprite_accessory/insect_fluff/royal
+ name = "Royal"
+ icon_state = "royal"
+
+/datum/sprite_accessory/insect_fluff/gothic
+ name = "Gothic"
+ icon_state = "gothic"
+
+/datum/sprite_accessory/insect_fluff/lovers
+ name = "Lovers"
+ icon_state = "lovers"
+
+/datum/sprite_accessory/insect_fluff/whitefly
+ name = "White Fly"
+ icon_state = "whitefly"
+
+/datum/sprite_accessory/insect_fluff/punished
+ name = "Burnt Off"
+ icon_state = "punished"
+
+/datum/sprite_accessory/insect_fluff/firewatch
+ name = "Firewatch"
+ icon_state = "firewatch"
+
+/datum/sprite_accessory/insect_fluff/deathhead
+ name = "Deathshead"
+ icon_state = "deathhead"
+
+/datum/sprite_accessory/insect_fluff/poison
+ name = "Poison"
+ icon_state = "poison"
+
+/datum/sprite_accessory/insect_fluff/ragged
+ name = "Ragged"
+ icon_state = "ragged"
+
+/datum/sprite_accessory/insect_fluff/moonfly
+ name = "Moon Fly"
+ icon_state = "moonfly"
+
+/datum/sprite_accessory/insect_fluff/snow
+ name = "Snow"
+ icon_state = "snow"
+
+/datum/sprite_accessory/insect_fluff/colored
+ name = "Colored (Hair)"
+ icon_state = "snow"
+ color_src = HAIR
+
+/datum/sprite_accessory/insect_fluff/colored1
+ name = "Colored (Primary)"
+ icon_state = "snow"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/insect_fluff/colored2
+ name = "Colored (Secondary)"
+ icon_state = "snow"
+ color_src = MUTCOLORS2
+
+/datum/sprite_accessory/insect_fluff/colored3
+ name = "Colored (Tertiary)"
+ icon_state = "snow"
+ color_src = MUTCOLORS3
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
index 163f8370a2..1496ca030a 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
@@ -5,8 +5,295 @@
name = "None"
icon_state = "none"
+/******************************************
+*************** Human Ears ****************
+*******************************************/
+
+/datum/sprite_accessory/ears/human/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+/datum/sprite_accessory/ears/human/bear
+ name = "Bear"
+ icon_state = "bear"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/bigwolf
+ name = "Big Wolf"
+ icon_state = "bigwolf"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/bigwolfinner
+ name = "Big Wolf (ALT)"
+ icon_state = "bigwolfinner"
+ hasinner = 1
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/bigwolfdark
+ name = "Dark Big Wolf"
+ icon_state = "bigwolfdark"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/bigwolfinnerdark
+ name = "Dark Big Wolf (ALT)"
+ icon_state = "bigwolfinnerdark"
+ hasinner = 1
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
/datum/sprite_accessory/ears/cat
name = "Cat"
icon_state = "cat"
hasinner = 1
- color_src = HAIR
\ No newline at end of file
+ color_src = HAIR
+
+/datum/sprite_accessory/ears/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/curled
+ name = "Curled Horn"
+ icon_state = "horn1"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MUTCOLORS3
+
+/datum/sprite_accessory/ears/human/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/elf
+ name = "Elf"
+ icon_state = "elf"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = SKINTONE
+
+/datum/sprite_accessory/ears/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/fish
+ name = "Fish"
+ icon_state = "fish"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/fox
+ name = "Fox"
+ icon_state = "fox"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+/datum/sprite_accessory/ears/human/jellyfish
+ name = "Jellyfish"
+ icon_state = "jellyfish"
+ color_src = HAIR
+
+/datum/sprite_accessory/ears/lab
+ name = "Dog, Floppy"
+ icon_state = "lab"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+/datum/sprite_accessory/ears/murid
+ name = "Murid"
+ icon_state = "murid"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/otie
+ name = "Otusian"
+ icon_state = "otie"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+/datum/sprite_accessory/ears/human/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+/datum/sprite_accessory/ears/human/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/human/skunk
+ name = "skunk"
+ icon_state = "skunk"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/ears/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+
+
+/******************************************
+*************** Furry Ears ****************
+*******************************************/
+
+/datum/sprite_accessory/mam_ears
+ icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/mam_ears/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/mam_ears/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+
+/datum/sprite_accessory/mam_ears/bear
+ name = "Bear"
+ icon_state = "bear"
+
+/datum/sprite_accessory/mam_ears/bigwolf
+ name = "Big Wolf"
+ icon_state = "bigwolf"
+
+/datum/sprite_accessory/mam_ears/bigwolfinner
+ name = "Big Wolf (ALT)"
+ icon_state = "bigwolfinner"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/bigwolfdark
+ name = "Dark Big Wolf"
+ icon_state = "bigwolfdark"
+
+/datum/sprite_accessory/mam_ears/bigwolfinnerdark
+ name = "Dark Big Wolf (ALT)"
+ icon_state = "bigwolfinnerdark"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/cat
+ name = "Cat"
+ icon_state = "cat"
+ hasinner = 1
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_ears/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+
+/datum/sprite_accessory/mam_ears/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_ears/curled
+ name = "Curled Horn"
+ icon_state = "horn1"
+ color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_ears/deer
+ name = "Deer"
+ icon_state = "deer"
+ color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_ears/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+
+/datum/sprite_accessory/mam_ears/elf
+ name = "Elf"
+ icon_state = "elf"
+ color_src = MUTCOLORS3
+
+
+/datum/sprite_accessory/mam_ears/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+
+/datum/sprite_accessory/mam_ears/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+
+/datum/sprite_accessory/mam_ears/fish
+ name = "Fish"
+ icon_state = "fish"
+
+/datum/sprite_accessory/mam_ears/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_ears/husky
+ name = "Husky"
+ icon_state = "wolf"
+
+/datum/sprite_accessory/mam_ears/kangaroo
+ name = "kangaroo"
+ icon_state = "kangaroo"
+
+/datum/sprite_accessory/mam_ears/jellyfish
+ name = "Jellyfish"
+ icon_state = "jellyfish"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_ears/lab
+ name = "Dog, Long"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_ears/murid
+ name = "Murid"
+ icon_state = "murid"
+
+/datum/sprite_accessory/mam_ears/otie
+ name = "Otusian"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_ears/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+
+/datum/sprite_accessory/mam_ears/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_ears/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_ears/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_ears/skunk
+ name = "skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_ears/wolf
+ name = "Wolf"
+ icon_state = "wolf"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
index 3566f3dea5..d11299fd5b 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
@@ -86,4 +86,45 @@
/datum/sprite_accessory/facial_hair/elvis
name = "Sideburns (Elvis)"
- icon_state = "facial_elvis"
\ No newline at end of file
+ icon_state = "facial_elvis"
+
+#define VFACE(_name, new_state) /datum/sprite_accessory/facial_hair/##new_state/icon_state=#new_state;;/datum/sprite_accessory/facial_hair/##new_state/name= #_name + " (Virgo)"
+VFACE("Watson", facial_watson_s)
+VFACE("Chaplin", facial_chaplin_s)
+VFACE("Fullbeard", facial_fullbeard_s)
+VFACE("Vandyke", facial_vandyke_s)
+VFACE("Elvis", facial_elvis_s)
+VFACE("Abe", facial_abe_s)
+VFACE("Chin", facial_chin_s)
+VFACE("GT", facial_gt_s)
+VFACE("Hip", facial_hip_s)
+VFACE("Hogan", facial_hogan_s)
+VFACE("Selleck", facial_selleck_s)
+VFACE("Neckbeard", facial_neckbeard_s)
+VFACE("Longbeard", facial_longbeard_s)
+VFACE("Dwarf", facial_dwarf_s)
+VFACE("Sideburn", facial_sideburn_s)
+VFACE("Mutton", facial_mutton_s)
+VFACE("Moustache", facial_moustache_s)
+VFACE("Pencilstache", facial_pencilstache_s)
+VFACE("Goatee", facial_goatee_s)
+VFACE("Smallstache", facial_smallstache_s)
+VFACE("Volaju", facial_volaju_s)
+VFACE("3 O\'clock", facial_3oclock_s)
+VFACE("5 O\'clock", facial_5oclock_s)
+VFACE("7 O\'clock", facial_7oclock_s)
+VFACE("5 O\'clock Moustache", facial_5oclockmoustache_s)
+VFACE("7 O\'clock", facial_7oclockmoustache_s)
+VFACE("Walrus", facial_walrus_s)
+VFACE("Muttonmus", facial_muttonmus_s)
+VFACE("Wise", facial_wise_s)
+VFACE("Martial Artist", facial_martialartist_s)
+VFACE("Dorsalfnil", facial_dorsalfnil_s)
+VFACE("Hornadorns", facial_hornadorns_s)
+VFACE("Spike", facial_spike_s)
+VFACE("Chinhorns", facial_chinhorns_s)
+VFACE("Cropped Fullbeard", facial_croppedfullbeard_s)
+VFACE("Chinless Beard", facial_chinlessbeard_s)
+VFACE("Moonshiner", facial_moonshiner_s)
+VFACE("Tribearder", facial_tribearder_s)
+#undef VFACE
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
index f8d8d26328..abcc90c0ee 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
@@ -461,4 +461,163 @@
/datum/sprite_accessory/hair/longestalt
name = "Very Long with Fringe"
- icon_state = "hair_vlongfringe"
\ No newline at end of file
+ icon_state = "hair_vlongfringe"
+
+/*************** VIRGO PORTED HAIRS ****************************/
+#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = #_name + " (Virgo)"
+//VIRGO PORTED HAIRS
+VHAIR("Short Hair Rosa", hair_rosa_s)
+VHAIR("Short Hair 80s", hair_80s_s)
+VHAIR("Long Bedhead", hair_long_bedhead_s)
+VHAIR("Dave", hair_dave_s)
+VHAIR("Country", hair_country_s)
+VHAIR("Shy", hair_shy_s)
+VHAIR("Unshaven Mohawk", hair_unshaven_mohawk_s)
+VHAIR("Manbun", hair_manbun_s)
+VHAIR("Longer Bedhead", hair_longer_bedhead_s)
+VHAIR("Ponytail", hair_ponytail_s)
+VHAIR("Ziegler", hair_ziegler_s)
+VHAIR("Emo Fringe", hair_emofringe_s)
+VHAIR("Very Short Over Eye Alt", hair_veryshortovereyealternate_s)
+VHAIR("Shorthime", hair_shorthime_s)
+VHAIR("High Tight", hair_hightight_s)
+VHAIR("Thinning Front", hair_thinningfront_s)
+VHAIR("Big Afro", hair_bigafro_s)
+VHAIR("Afro", hair_afro_s)
+VHAIR("High Braid", hair_hbraid_s)
+VHAIR("Braid", hair_braid_s)
+VHAIR("Sargeant", hair_sargeant_s)
+VHAIR("Gelled", hair_gelled_s)
+VHAIR("Kagami", hair_kagami_s)
+VHAIR("ShortTail", hair_stail_s)
+VHAIR("Gentle", hair_gentle_s)
+VHAIR("Grande", hair_grande_s)
+VHAIR("Bobcurl", hair_bobcurl_s)
+VHAIR("Pompadeur", hair_pompadour_s)
+VHAIR("Plait", hair_plait_s)
+VHAIR("Long", hair_long_s)
+VHAIR("Rattail", hair_rattail_s)
+VHAIR("Tajspiky", hair_tajspiky_s)
+VHAIR("Messy", hair_messy_s)
+VHAIR("Bangs", hair_bangs_s)
+VHAIR("TBraid", hair_tbraid_s)
+VHAIR("Toriyama2", hair_toriyama2_s)
+VHAIR("CIA", hair_cia_s)
+VHAIR("Mulder", hair_mulder_s)
+VHAIR("Scully", hair_scully_s)
+VHAIR("Nitori", hair_nitori_s)
+VHAIR("Joestar", hair_joestar_s)
+VHAIR("Ponytail4", hair_ponytail4_s)
+VHAIR("Ponytail5", hair_ponytail5_s)
+VHAIR("Beehive2", hair_beehive2_s)
+VHAIR("Short Braid", hair_shortbraid_s)
+VHAIR("Reverse Mohawk", hair_reversemohawk_s)
+VHAIR("SHort Bangs", hair_shortbangs_s)
+VHAIR("Half Shaved", hair_halfshaved_s)
+VHAIR("Longer Alt 2", hair_longeralt2_s)
+VHAIR("Bun", hair_bun_s)
+VHAIR("Curly", hair_curly_s)
+VHAIR("Victory", hair_victory_s)
+VHAIR("Ponytail6", hair_ponytail6_s)
+VHAIR("Undercut3", hair_undercut3_s)
+VHAIR("Bobcut Alt", hair_bobcultalt_s)
+VHAIR("Fingerwave", hair_fingerwave_s)
+VHAIR("Oxton", hair_oxton_s)
+VHAIR("Poofy2", hair_poofy2_s)
+VHAIR("Fringe Tail", hair_fringetail_s)
+VHAIR("Bun3", hair_bun3_s)
+VHAIR("Wisp", hair_wisp_s)
+VHAIR("Undercut2", hair_undercut2_s)
+VHAIR("TBob", hair_tbob_s)
+VHAIR("Spiky Ponytail", hair_spikyponytail_s)
+VHAIR("Rowbun", hair_rowbun_s)
+VHAIR("Rowdualtail", hair_rowdualtail_s)
+VHAIR("Rowbraid", hair_rowbraid_s)
+VHAIR("Shaved Mohawk", hair_shavedmohawk_s)
+VHAIR("Topknot", hair_topknot_s)
+VHAIR("Ronin", hair_ronin_s)
+VHAIR("Bowlcut2", hair_bowlcut2_s)
+VHAIR("Thinning Rear", hair_thinningrear_s)
+VHAIR("Thinning", hair_thinning_s)
+VHAIR("Jade", hair_jade_s)
+VHAIR("Bedhead", hair_bedhead_s)
+VHAIR("Dreadlocks", hair_dreads_s)
+VHAIR("Very Long", hair_vlong_s)
+VHAIR("Jensen", hair_jensen_s)
+VHAIR("Halfbang", hair_halfbang_s)
+VHAIR("Kusangi", hair_kusangi_s)
+VHAIR("Ponytail", hair_ponytail_s)
+VHAIR("Ponytail3", hair_ponytail3_s)
+VHAIR("Halfbang Alt", hair_halfbang_alt_s)
+VHAIR("Bedhead V2", hair_bedheadv2_s)
+VHAIR("Long Fringe", hair_longfringe_s)
+VHAIR("Flair", hair_flair_s)
+VHAIR("Bedhead V3", hair_bedheadv3_s)
+VHAIR("Himecut", hair_himecut_s)
+VHAIR("Curls", hair_curls_s)
+VHAIR("Very Long Fringe", hair_vlongfringe_s)
+VHAIR("Longest", hair_longest_s)
+VHAIR("Father", hair_father_s)
+VHAIR("Emo Long", hair_emolong_s)
+VHAIR("Short Hair 3", hair_shorthair3_s)
+VHAIR("Double Bun", hair_doublebun_s)
+VHAIR("Sleeze", hair_sleeze_s)
+VHAIR("Twintail", hair_twintail_s)
+VHAIR("Emo 2", hair_emo2_s)
+VHAIR("Low Fade", hair_lowfade_s)
+VHAIR("Med Fade", hair_medfade_s)
+VHAIR("High Fade", hair_highfade_s)
+VHAIR("Bald Fade", hair_baldfade_s)
+VHAIR("No Fade", hair_nofade_s)
+VHAIR("Trim Flat", hair_trimflat_s)
+VHAIR("Shaved", hair_shaved_s)
+VHAIR("Trimmed", hair_trimmed_s)
+VHAIR("Tight Bun", hair_tightbun_s)
+VHAIR("Short Hair 4", hair_d_s)
+VHAIR("Short Hair 5", hair_e_s)
+VHAIR("Short Hair 6", hair_f_s)
+VHAIR("Skinhead", hair_skinhead_s)
+VHAIR("Afro2", hair_afro2_s)
+VHAIR("Bobcut", hair_bobcut_s)
+VHAIR("Emo", hair_emo_s)
+VHAIR("Long Over Eye", hair_longovereye_s)
+VHAIR("Feather", hair_feather_s)
+VHAIR("Hitop", hair_hitop_s)
+VHAIR("Short Over Eye", hair_shortoverye_s)
+VHAIR("Straight", hair_straight_s)
+VHAIR("Buzzcut", hair_buzzcut_s)
+VHAIR("Combover", hair_combover_s)
+VHAIR("Crewcut", hair_crewcut_s)
+VHAIR("Devillock", hair_devilock_s)
+VHAIR("Clean", hair_clean_s)
+VHAIR("Shaggy", hair_shaggy_s)
+VHAIR("Updo", hair_updo_s)
+VHAIR("Mohawk", hair_mohawk_s)
+VHAIR("Odango", hair_odango_s)
+VHAIR("Ombre", hair_ombre_s)
+VHAIR("Parted", hair_parted_s)
+VHAIR("Quiff", hair_quiff_s)
+VHAIR("Volaju", hair_volaju_s)
+VHAIR("Bun2", hair_bun2_s)
+VHAIR("Rows1", hair_rows1_s)
+VHAIR("Rows2", hair_rows2_s)
+VHAIR("Dandy Pompadour", hair_dandypompadour_s)
+VHAIR("Poofy", hair_poofy_s)
+VHAIR("Toriyama", hair_toriyama_s)
+VHAIR("Drillruru", hair_drillruru_s)
+VHAIR("Bowlcut", hair_bowlcut_s)
+VHAIR("Coffee House", hair_coffeehouse_s)
+VHAIR("Family Man", hair_thefamilyman_s)
+VHAIR("Shaved Part", hair_shavedpart_s)
+VHAIR("Modern", hair_modern_s)
+VHAIR("One Shoulder", hair_oneshoulder_s)
+VHAIR("Very Short Over Eye", hair_veryshortovereye_s)
+VHAIR("Unkept", hair_unkept_s)
+VHAIR("Wife", hair_wife_s)
+VHAIR("Nia", hair_nia_s)
+VHAIR("Undercut", hair_undercut_s)
+VHAIR("Bobcut Alt", hair_bobcutalt_s)
+VHAIR("Short Hair 4 alt", hair_shorthair4_s)
+VHAIR("Tressshoulder", hair_tressshoulder_s)
+ //END
+#undef VHAIR
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
index 607ad650e3..a630ead7b3 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
@@ -1,5 +1,6 @@
/datum/sprite_accessory/horns
icon = 'icons/mob/mutant_bodyparts.dmi'
+ color_src = HORNCOLOR
/datum/sprite_accessory/horns/none
name = "None"
@@ -23,4 +24,13 @@
/datum/sprite_accessory/horns/angler
name = "Angeler"
- icon_state = "angler"
\ No newline at end of file
+ icon_state = "angler"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/horns/antler
+ name = "Deer Antlers"
+ icon_state = "deer"
+
+/datum/sprite_accessory/horns/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm
new file mode 100644
index 0000000000..6d2ab1a39b
--- /dev/null
+++ b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm
@@ -0,0 +1,158 @@
+
+/******************************************
+************** IPC SCREENS ****************
+*******************************************/
+/datum/sprite_accessory/screen
+ icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
+ color_src = null
+
+/datum/sprite_accessory/screen/blank
+ name = "Blank"
+ icon_state = "blank"
+
+/datum/sprite_accessory/screen/pink
+ name = "Pink"
+ icon_state = "pink"
+
+/datum/sprite_accessory/screen/green
+ name = "Green"
+ icon_state = "green"
+
+/datum/sprite_accessory/screen/red
+ name = "Red"
+ icon_state = "red"
+
+/datum/sprite_accessory/screen/blue
+ name = "Blue"
+ icon_state = "blue"
+
+/datum/sprite_accessory/screen/yellow
+ name = "Yellow"
+ icon_state = "yellow"
+
+/datum/sprite_accessory/screen/shower
+ name = "Shower"
+ icon_state = "shower"
+
+/datum/sprite_accessory/screen/nature
+ name = "Nature"
+ icon_state = "nature"
+
+/datum/sprite_accessory/screen/eight
+ name = "Eight"
+ icon_state = "eight"
+
+/datum/sprite_accessory/screen/goggles
+ name = "Goggles"
+ icon_state = "goggles"
+
+/datum/sprite_accessory/screen/heart
+ name = "Heart"
+ icon_state = "heart"
+
+/datum/sprite_accessory/screen/monoeye
+ name = "Mono eye"
+ icon_state = "monoeye"
+
+/datum/sprite_accessory/screen/breakout
+ name = "Breakout"
+ icon_state = "breakout"
+
+/datum/sprite_accessory/screen/purple
+ name = "Purple"
+ icon_state = "purple"
+
+/datum/sprite_accessory/screen/scroll
+ name = "Scroll"
+ icon_state = "scroll"
+
+/datum/sprite_accessory/screen/console
+ name = "Console"
+ icon_state = "console"
+
+/datum/sprite_accessory/screen/rgb
+ name = "RGB"
+ icon_state = "rgb"
+
+/datum/sprite_accessory/screen/golglider
+ name = "Gol Glider"
+ icon_state = "golglider"
+
+/datum/sprite_accessory/screen/rainbow
+ name = "Rainbow"
+ icon_state = "rainbow"
+
+/datum/sprite_accessory/screen/sunburst
+ name = "Sunburst"
+ icon_state = "sunburst"
+
+/datum/sprite_accessory/screen/static
+ name = "Static"
+ icon_state = "static"
+
+//Oracle Station sprites
+
+/datum/sprite_accessory/screen/bsod
+ name = "BSOD"
+ icon_state = "bsod"
+
+/datum/sprite_accessory/screen/redtext
+ name = "Red Text"
+ icon_state = "retext"
+
+/datum/sprite_accessory/screen/sinewave
+ name = "Sine wave"
+ icon_state = "sinewave"
+
+/datum/sprite_accessory/screen/squarewave
+ name = "Square wave"
+ icon_state = "squarwave"
+
+/datum/sprite_accessory/screen/ecgwave
+ name = "ECG wave"
+ icon_state = "ecgwave"
+
+/datum/sprite_accessory/screen/eyes
+ name = "Eyes"
+ icon_state = "eyes"
+
+/datum/sprite_accessory/screen/textdrop
+ name = "Text drop"
+ icon_state = "textdrop"
+
+/datum/sprite_accessory/screen/stars
+ name = "Stars"
+ icon_state = "stars"
+
+
+/******************************************
+************** IPC Antennas ***************
+*******************************************/
+
+/datum/sprite_accessory/antenna
+ icon = 'modular_citadel/icons/mob/ipc_antennas.dmi'
+ color_src = MUTCOLORS2
+
+/datum/sprite_accessory/antenna/none
+ name = "None"
+ icon_state = "None"
+
+/datum/sprite_accessory/antenna/antennae
+ name = "Angled Antennae"
+ icon_state = "antennae"
+
+/datum/sprite_accessory/antenna/tvantennae
+ name = "TV Antennae"
+ icon_state = "tvantennae"
+
+/datum/sprite_accessory/antenna/cyberhead
+ name = "Cyberhead"
+ icon_state = "cyberhead"
+
+/datum/sprite_accessory/antenna/antlers
+ name = "Antlers"
+ icon_state = "antlers"
+
+/datum/sprite_accessory/antenna/crowned
+ name = "Crowned"
+ icon_state = "crowned"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs.dm
deleted file mode 100644
index 7663100822..0000000000
--- a/code/modules/mob/dead/new_player/sprite_accessories/legs.dm
+++ /dev/null
@@ -1,8 +0,0 @@
-/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them.
- icon = null //These datums exist for selecting legs on preference, and little else
-
-/datum/sprite_accessory/legs/none
- name = "Normal Legs"
-
-/datum/sprite_accessory/legs/digitigrade_lizard
- name = "Digitigrade Legs"
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
new file mode 100644
index 0000000000..15640a2699
--- /dev/null
+++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
@@ -0,0 +1,124 @@
+/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them. -- OR SO THEY USED TO BE
+ icon = null //These datums exist for selecting legs on preference, and little else
+
+/******************************************
+***************** Leggy *******************
+*******************************************/
+
+/datum/sprite_accessory/legs/none
+ name = "Plantigrade"
+
+/datum/sprite_accessory/legs/digitigrade_lizard
+ name = "Digitigrade"
+
+/datum/sprite_accessory/legs/digitigrade_bird
+ name = "Avian"
+
+
+/******************************************
+************** Taur Bodies ****************
+*******************************************/
+
+/datum/sprite_accessory/taur
+ icon = 'modular_citadel/icons/mob/mam_taur.dmi'
+ extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
+ extra = TRUE
+ extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
+ extra2 = TRUE
+ center = TRUE
+ dimension_x = 64
+ var/taur_mode = NOT_TAURIC
+ color_src = MATRIXED
+
+/datum/sprite_accessory/taur/none
+ name = "None"
+ icon_state = "None"
+
+/datum/sprite_accessory/taur/cow
+ name = "Cow"
+ icon_state = "cow"
+ taur_mode = HOOF_TAURIC
+
+/datum/sprite_accessory/taur/deer
+ name = "Deer"
+ icon_state = "deer"
+ taur_mode = HOOF_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/drake
+ name = "Drake"
+ icon_state = "drake"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/drider
+ name = "Drider"
+ icon_state = "drider"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/fox
+ name = "Fox"
+ icon_state = "fox"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/husky
+ name = "Husky"
+ icon_state = "husky"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/horse
+ name = "Horse"
+ icon_state = "horse"
+ taur_mode = HOOF_TAURIC
+
+/datum/sprite_accessory/taur/lab
+ name = "Lab"
+ icon_state = "lab"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/naga
+ name = "Naga"
+ icon_state = "naga"
+ taur_mode = SNEK_TAURIC
+
+/datum/sprite_accessory/taur/otie
+ name = "Otie"
+ icon_state = "otie"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/panther
+ name = "Panther"
+ icon_state = "panther"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+ taur_mode = SNEK_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ taur_mode = PAW_TAURIC
+
+/datum/sprite_accessory/taur/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ taur_mode = PAW_TAURIC
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm
deleted file mode 100644
index 6b8036bd69..0000000000
--- a/code/modules/mob/dead/new_player/sprite_accessories/moth_wings.dm
+++ /dev/null
@@ -1,68 +0,0 @@
-/datum/sprite_accessory/moth_wings
- icon = 'icons/mob/wings.dmi'
- color_src = null
-
-/datum/sprite_accessory/moth_wings/plain
- name = "Plain"
- icon_state = "plain"
-
-/datum/sprite_accessory/moth_wings/monarch
- name = "Monarch"
- icon_state = "monarch"
-
-/datum/sprite_accessory/moth_wings/luna
- name = "Luna"
- icon_state = "luna"
-
-/datum/sprite_accessory/moth_wings/atlas
- name = "Atlas"
- icon_state = "atlas"
-
-/datum/sprite_accessory/moth_wings/reddish
- name = "Reddish"
- icon_state = "redish"
-
-/datum/sprite_accessory/moth_wings/royal
- name = "Royal"
- icon_state = "royal"
-
-/datum/sprite_accessory/moth_wings/gothic
- name = "Gothic"
- icon_state = "gothic"
-
-/datum/sprite_accessory/moth_wings/lovers
- name = "Lovers"
- icon_state = "lovers"
-
-/datum/sprite_accessory/moth_wings/whitefly
- name = "White Fly"
- icon_state = "whitefly"
-
-/datum/sprite_accessory/moth_wings/punished
- name = "Burnt Off"
- icon_state = "punished"
- locked = TRUE
-
-/datum/sprite_accessory/moth_wings/firewatch
- name = "Firewatch"
- icon_state = "firewatch"
-
-/datum/sprite_accessory/moth_wings/deathhead
- name = "Deathshead"
- icon_state = "deathhead"
-
-/datum/sprite_accessory/moth_wings/poison
- name = "Poison"
- icon_state = "poison"
-
-/datum/sprite_accessory/moth_wings/ragged
- name = "Ragged"
- icon_state = "ragged"
-
-/datum/sprite_accessory/moth_wings/moonfly
- name = "Moon Fly"
- icon_state = "moonfly"
-
-/datum/sprite_accessory/moth_wings/snow
- name = "Snow"
- icon_state = "snow"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
index c663c08d69..7252f85324 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
@@ -15,4 +15,359 @@
/datum/sprite_accessory/snouts/roundlight
name = "Round + Light"
- icon_state = "roundlight"
\ No newline at end of file
+ icon_state = "roundlight"
+
+/datum/sprite_accessory/snout/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+
+//christ this was a mistake, but it's here just in case someone wants to selectively fix -- Pooj
+/************* Lizard compatable snoots ***********
+/datum/sprite_accessory/snouts/bird
+ name = "Beak"
+ icon_state = "bird"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bigbeak
+ name = "Big Beak"
+ icon_state = "bigbeak"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/lcanid
+ name = "Mammal, Long"
+ icon_state = "lcanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanid
+ name = "Mammal, Short"
+ icon_state = "scanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolf
+ name = "Mammal, Thick"
+ icon_state = "wolf"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/rhino
+ name = "Horn"
+ icon_state = "rhino"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/otie
+ name = "Otie"
+ icon_state = "otie"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+
+/datum/sprite_accessory/snouts/toucan
+ name = "Toucan"
+ icon_state = "toucan"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+*/
+
+/******************************************
+************** Mammal Snouts **************
+*******************************************/
+
+/datum/sprite_accessory/mam_snouts
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+
+/datum/sprite_accessory/mam_snouts/none
+ name = "None"
+ icon_state = "none"
+
+
+/datum/sprite_accessory/mam_snouts/bird
+ name = "Beak"
+ icon_state = "bird"
+
+/datum/sprite_accessory/mam_snouts/bigbeak
+ name = "Big Beak"
+ icon_state = "bigbeak"
+
+/datum/sprite_accessory/mam_snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/lcanid
+ name = "Mammal, Long"
+ icon_state = "lcanid"
+
+/datum/sprite_accessory/mam_snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+
+/datum/sprite_accessory/mam_snouts/scanid
+ name = "Mammal, Short"
+ icon_state = "scanid"
+
+/datum/sprite_accessory/mam_snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+
+/datum/sprite_accessory/mam_snouts/wolf
+ name = "Mammal, Thick"
+ icon_state = "wolf"
+
+/datum/sprite_accessory/mam_snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+
+/datum/sprite_accessory/mam_snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+
+/datum/sprite_accessory/mam_snouts/redpandaalt
+ name = "WahCoon ALT"
+ icon_state = "wahalt"
+
+/datum/sprite_accessory/mam_snouts/rhino
+ name = "Horn"
+ icon_state = "rhino"
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+
+/datum/sprite_accessory/mam_snouts/husky
+ name = "Husky"
+ icon_state = "husky"
+
+/datum/sprite_accessory/mam_snouts/otie
+ name = "Otie"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_snouts/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_snouts/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_snouts/toucan
+ name = "Toucan"
+ icon_state = "toucan"
+
+/datum/sprite_accessory/mam_snouts/sharp
+ name = "Sharp"
+ icon_state = "sharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/round
+ name = "Round"
+ icon_state = "round"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/sharplight
+ name = "Sharp + Light"
+ icon_state = "sharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/roundlight
+ name = "Round + Light"
+ icon_state = "roundlight"
+ color_src = MUTCOLORS
+
+
+/******************************************
+**************** Snouts *******************
+*************but higher up*****************/
+
+/datum/sprite_accessory/mam_snouts/fbird
+ name = "Beak (Top)"
+ icon_state = "fbird"
+
+/datum/sprite_accessory/mam_snouts/fbigbeak
+ name = "Big Beak (Top)"
+ icon_state = "fbigbeak"
+
+/datum/sprite_accessory/mam_snouts/fbug
+ name = "Bug (Top)"
+ icon_state = "fbug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/felephant
+ name = "Elephant (Top)"
+ icon_state = "felephant"
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/flcanid
+ name = "Mammal, Long (Top)"
+ icon_state = "flcanid"
+
+/datum/sprite_accessory/mam_snouts/flcanidalt
+ name = "Mammal, Long ALT (Top)"
+ icon_state = "flcanidalt"
+
+/datum/sprite_accessory/mam_snouts/fscanid
+ name = "Mammal, Short (Top)"
+ icon_state = "fscanid"
+
+/datum/sprite_accessory/mam_snouts/fscanidalt
+ name = "Mammal, Short ALT (Top)"
+ icon_state = "fscanidalt"
+
+/datum/sprite_accessory/mam_snouts/fwolf
+ name = "Mammal, Thick (Top)"
+ icon_state = "fwolf"
+
+/datum/sprite_accessory/mam_snouts/fwolfalt
+ name = "Mammal, Thick ALT (Top)"
+ icon_state = "fwolfalt"
+
+/datum/sprite_accessory/mam_snouts/fredpanda
+ name = "WahCoon (Top)"
+ icon_state = "fwah"
+
+/datum/sprite_accessory/mam_snouts/frhino
+ name = "Horn (Top)"
+ icon_state = "frhino"
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/frodent
+ name = "Rodent (Top)"
+ icon_state = "frodent"
+
+/datum/sprite_accessory/mam_snouts/fhusky
+ name = "Husky (Top)"
+ icon_state = "fhusky"
+
+/datum/sprite_accessory/mam_snouts/fotie
+ name = "Otie (Top)"
+ icon_state = "fotie"
+
+/datum/sprite_accessory/mam_snouts/fpede
+ name = "Scolipede (Top)"
+ icon_state = "fpede"
+
+/datum/sprite_accessory/mam_snouts/fsergal
+ name = "Sergal (Top)"
+ icon_state = "fsergal"
+
+/datum/sprite_accessory/mam_snouts/fshark
+ name = "Shark (Top)"
+ icon_state = "fshark"
+
+/datum/sprite_accessory/mam_snouts/ftoucan
+ name = "Toucan (Top)"
+ icon_state = "ftoucan"
+
+/datum/sprite_accessory/mam_snouts/fsharp
+ name = "Sharp (Top)"
+ icon_state = "fsharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fround
+ name = "Round (Top)"
+ icon_state = "fround"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fsharplight
+ name = "Sharp + Light (Top)"
+ icon_state = "fsharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/froundlight
+ name = "Round + Light (Top)"
+ icon_state = "froundlight"
+ color_src = MUTCOLORS
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
index 31faabf663..6042d97247 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
@@ -4,6 +4,10 @@
/datum/sprite_accessory/tails_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
+/******************************************
+************* Lizard Tails ****************
+*******************************************/
+
/datum/sprite_accessory/tails/lizard/smooth
name = "Smooth"
icon_state = "smooth"
@@ -36,6 +40,48 @@
name = "Spikes"
icon_state = "spikes"
+/datum/sprite_accessory/tails/lizard/none
+ name = "None"
+ icon_state = "None"
+
+/datum/sprite_accessory/tails_animated/lizard/none
+ name = "None"
+ icon_state = "None"
+
+/datum/sprite_accessory/tails/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/body_markings/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/tails/lizard/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/******************************************
+************** Human Tails ****************
+*******************************************/
+
/datum/sprite_accessory/tails/human/none
name = "None"
icon_state = "none"
@@ -43,13 +89,626 @@
/datum/sprite_accessory/tails_animated/human/none
name = "None"
icon_state = "none"
-/*
+
+/datum/sprite_accessory/tails/human/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/bee
+ name = "Bee"
+ icon_state = "bee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/bee
+ name = "Bee"
+ icon_state = "bee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
/datum/sprite_accessory/tails/human/cat
name = "Cat"
icon_state = "cat"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
color_src = HAIR
/datum/sprite_accessory/tails_animated/human/cat
name = "Cat"
icon_state = "cat"
- color_src = HAIR*/
\ No newline at end of file
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails/human/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/tails_animated/human/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/tails/human/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fish
+ name = "Fish"
+ icon_state = "fish"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fish
+ name = "Fish"
+ icon_state = "fish"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fox
+ name = "Fox"
+ icon_state = "fox"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fox
+ name = "Fox"
+ icon_state = "fox"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails_animated/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails/human/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/insect
+ name = "Insect"
+ icon_state = "insect"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/insect
+ name = "insect"
+ icon_state = "insect"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/murid
+ name = "Murid"
+ icon_state = "murid"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/murid
+ name = "Murid"
+ icon_state = "murid"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/otie
+ name = "Otusian"
+ icon_state = "otie"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/otie
+ name = "Otusian"
+ icon_state = "otie"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/orca
+ name = "Orca"
+ icon_state = "orca"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/orca
+ name = "Orca"
+ icon_state = "orca"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/skunk
+ name = "skunk"
+ icon_state = "skunk"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/skunk
+ name = "skunk"
+ icon_state = "skunk"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/datashark
+ name = "datashark"
+ icon_state = "datashark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/datashark
+ name = "datashark"
+ icon_state = "datashark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/tails_animated/human/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/tails/human/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/******************************************
+************** Furry Tails ****************
+*******************************************/
+
+/datum/sprite_accessory/mam_tails
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/mam_tails/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/mam_tails_animated
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/mam_tails_animated/none
+ name = "None"
+ icon_state = "none"
+ color_src = MATRIXED
+
+/datum/sprite_accessory/mam_tails/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ extra = TRUE
+
+/datum/sprite_accessory/mam_tails_animated/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ extra = TRUE
+
+/datum/sprite_accessory/mam_tails/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+
+/datum/sprite_accessory/mam_tails_animated/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+
+/datum/sprite_accessory/mam_tails/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_tails_animated/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_tails/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+
+/datum/sprite_accessory/mam_tails_animated/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+
+/datum/sprite_accessory/mam_tails/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tails_animated/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tail/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_tails_animated/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_tails/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+/datum/sprite_accessory/mam_tails_animated/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+/datum/sprite_accessory/mam_tails/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+
+/datum/sprite_accessory/mam_tails_animated/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+
+/datum/sprite_accessory/mam_tails/human/fish
+ name = "Fish"
+ icon_state = "fish"
+
+/datum/sprite_accessory/mam_tails_animated/human/fish
+ name = "Fish"
+ icon_state = "fish"
+
+/datum/sprite_accessory/mam_tails/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_tails_animated/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_tails/hawk
+ name = "Hawk"
+ icon_state = "hawk"
+
+/datum/sprite_accessory/mam_tails_animated/hawk
+ name = "Hawk"
+ icon_state = "hawk"
+
+/datum/sprite_accessory/mam_tails/horse
+ name = "Horse"
+ icon_state = "horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/horse
+ name = "Horse"
+ icon_state = "Horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails/husky
+ name = "Husky"
+ icon_state = "husky"
+
+/datum/sprite_accessory/mam_tails_animated/husky
+ name = "Husky"
+ icon_state = "husky"
+
+datum/sprite_accessory/mam_tails/insect
+ name = "Insect"
+ icon_state = "insect"
+
+/datum/sprite_accessory/mam_tails_animated/insect
+ name = "Insect"
+ icon_state = "insect"
+
+/datum/sprite_accessory/mam_tails/kangaroo
+ name = "kangaroo"
+ icon_state = "kangaroo"
+
+/datum/sprite_accessory/mam_tails_animated/kangaroo
+ name = "kangaroo"
+ icon_state = "kangaroo"
+
+/datum/sprite_accessory/mam_tails/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+
+/datum/sprite_accessory/mam_tails_animated/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+
+/datum/sprite_accessory/mam_tails/lab
+ name = "Lab"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_tails_animated/lab
+ name = "Lab"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_tails/murid
+ name = "Murid"
+ icon_state = "murid"
+
+/datum/sprite_accessory/mam_tails_animated/murid
+ name = "Murid"
+ icon_state = "murid"
+
+/datum/sprite_accessory/mam_tails/otie
+ name = "Otusian"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_tails_animated/otie
+ name = "Otusian"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_tails/orca
+ name = "Orca"
+ icon_state = "orca"
+
+/datum/sprite_accessory/mam_tails_animated/orca
+ name = "Orca"
+ icon_state = "orca"
+
+/datum/sprite_accessory/mam_tails/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_tails_animated/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_tails/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_tails_animated/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_tails/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_tails_animated/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_tails/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_tails_animated/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_tails/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_tails_animated/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_tails/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+
+/datum/sprite_accessory/mam_tails_animated/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+
+/datum/sprite_accessory/mam_tails/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails_animated/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+
+/datum/sprite_accessory/mam_tails_animated/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+
+/datum/sprite_accessory/mam_tails/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+
+/datum/sprite_accessory/mam_tails_animated/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+
+/datum/sprite_accessory/mam_tails/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails_animated/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+
+/datum/sprite_accessory/mam_tails_animated/wolf
+ name = "Wolf"
+ icon_state = "wolf"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
index d051b2f07a..dc0e0222bf 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
@@ -1,3 +1,5 @@
+//Angel Wings
+
/datum/sprite_accessory/wings/none
name = "None"
icon_state = "none"
@@ -23,4 +25,120 @@
dimension_x = 46
center = TRUE
dimension_y = 34
- locked = TRUE
\ No newline at end of file
+ locked = TRUE
+
+//INSECT WINGS
+
+/datum/sprite_accessory/insect_wings
+ icon = 'icons/mob/wings.dmi'
+ color_src = null
+
+/datum/sprite_accessory/insect_wings/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/insect_wings/plain
+ name = "Plain"
+ icon_state = "plain"
+
+/datum/sprite_accessory/insect_wings/monarch
+ name = "Monarch"
+ icon_state = "monarch"
+
+/datum/sprite_accessory/insect_wings/luna
+ name = "Luna"
+ icon_state = "luna"
+
+/datum/sprite_accessory/insect_wings/atlas
+ name = "Atlas"
+ icon_state = "atlas"
+
+/datum/sprite_accessory/insect_wings/reddish
+ name = "Reddish"
+ icon_state = "redish"
+
+/datum/sprite_accessory/insect_wings/royal
+ name = "Royal"
+ icon_state = "royal"
+
+/datum/sprite_accessory/insect_wings/gothic
+ name = "Gothic"
+ icon_state = "gothic"
+
+/datum/sprite_accessory/insect_wings/lovers
+ name = "Lovers"
+ icon_state = "lovers"
+
+/datum/sprite_accessory/insect_wings/whitefly
+ name = "White Fly"
+ icon_state = "whitefly"
+
+/datum/sprite_accessory/insect_wings/punished
+ name = "Burnt Off"
+ icon_state = "punished"
+ locked = TRUE
+
+/datum/sprite_accessory/insect_wings/firewatch
+ name = "Firewatch"
+ icon_state = "firewatch"
+
+/datum/sprite_accessory/insect_wings/deathhead
+ name = "Deathshead"
+ icon_state = "deathhead"
+
+/datum/sprite_accessory/insect_wings/poison
+ name = "Poison"
+ icon_state = "poison"
+
+/datum/sprite_accessory/insect_wings/ragged
+ name = "Ragged"
+ icon_state = "ragged"
+
+/datum/sprite_accessory/insect_wings/moonfly
+ name = "Moon Fly"
+ icon_state = "moonfly"
+
+/datum/sprite_accessory/insect_wings/snow
+ name = "Snow"
+ icon_state = "snow"
+
+/datum/sprite_accessory/insect_wings/colored
+ name = "Colored (Hair)"
+ icon_state = "snowplain"
+ color_src = HAIR
+
+/datum/sprite_accessory/insect_fluff/colored1
+ name = "Colored (Primary)"
+ icon_state = "snowplain"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/insect_fluff/colored2
+ name = "Colored (Secondary)"
+ icon_state = "snowplain"
+ color_src = MUTCOLORS2
+
+/datum/sprite_accessory/insect_fluff/colored3
+ name = "Colored (Tertiary)"
+ icon_state = "snowplain"
+ color_src = MUTCOLORS3
+
+/datum/sprite_accessory/insect_wings/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/insect_wings/bee_color
+ name = "Bee (Hair colored)"
+ icon_state = "bee"
+ color_src = HAIR
+
+/datum/sprite_accessory/insect_wings/fairy
+ name = "Fairy"
+ icon_state = "fairy"
+
+/datum/sprite_accessory/insect_wings/bat
+ name = "Bat"
+ icon_state = "bat"
+
+/datum/sprite_accessory/insect_wings/feathery
+ name = "Feathery"
+ icon_state = "feathery"
diff --git a/code/modules/mob/living/carbon/alien/larva/emote.dm b/code/modules/mob/living/carbon/alien/larva/emote.dm
deleted file mode 100644
index 62cb620ee4..0000000000
--- a/code/modules/mob/living/carbon/alien/larva/emote.dm
+++ /dev/null
@@ -1,113 +0,0 @@
-/mob/living/carbon/alien/larva/emote(act,m_type=1,message = null)
-
- var/param = null
- if (findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
-
- var/muzzled = is_muzzled()
-
- switch(act) //Alphabetically sorted please.
- if ("burp","burps")
- if (!muzzled)
- message = "[src] burps."
- m_type = 2
- if ("choke","chokes")
- message = "[src] chokes."
- m_type = 2
- if ("collapse","collapses")
- Paralyse(2)
- message = "[src] collapses!"
- m_type = 2
- if ("dance","dances")
- if (!src.restrained())
- message = "[src] dances around happily."
- m_type = 1
- if ("deathgasp","deathgasps")
- message = "[src] lets out a sickly hiss of air and falls limply to the floor..."
- m_type = 2
- if ("drool","drools")
- message = "[src] drools."
- m_type = 1
- if ("gasp","gasps")
- message = "[src] gasps."
- m_type = 2
- if ("gnarl","gnarls")
- if (!muzzled)
- message = "[src] gnarls and shows its teeth.."
- m_type = 2
- if ("hiss","hisses")
- message = "[src] hisses softly."
- m_type = 1
- if ("jump","jumps")
- message = "[src] jumps!"
- m_type = 1
- if ("me")
- ..()
- return
- if ("moan","moans")
- message = "[src] moans!"
- m_type = 2
- if ("nod","nods")
- message = "[src] nods its head."
- m_type = 1
- if ("roar","roars")
- if (!muzzled)
- message = "[src] softly roars."
- m_type = 2
- if ("roll","rolls")
- if (!src.restrained())
- message = "[src] rolls."
- m_type = 1
- if ("scratch","scratches")
- if (!src.restrained())
- message = "[src] scratches."
- m_type = 1
- if ("screech","screeches") //This orignally was called scretch, changing it. -Sum99
- if (!muzzled)
- message = "[src] screeches."
- m_type = 2
- if ("shake","shakes")
- message = "[src] shakes its head."
- m_type = 1
- if ("shiver","shivers")
- message = "[src] shivers."
- m_type = 2
- if ("sign","signs")
- if (!src.restrained())
- message = text("[src] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
- m_type = 1
- if ("snore","snores")
- message = "[src] snores."
- m_type = 2
- if ("sulk","sulks")
- message = "[src] sulks down sadly."
- m_type = 1
- if ("sway","sways")
- message = "[src] sways around dizzily."
- m_type = 1
- if ("tail")
- message = "[src] waves its tail."
- m_type = 1
- if ("twitch")
- message = "[src] twitches violently."
- m_type = 1
- if ("whimper","whimpers")
- if (!muzzled)
- message = "[src] whimpers."
- m_type = 2
-
- if ("help") //"The exception"
- src << "Help for larva emotes. You can use these emotes with say \"*emote\":\n\nburp, choke, collapse, dance, deathgasp, drool, gasp, gnarl, hiss, jump, me, moan, nod, roll, roar, scratch, screech, shake, shiver, sign-#, sulk, sway, tail, twitch, whimper"
-
- else
- src << "Unusable emote '[act]'. Say *help for a list. "
-
- if ((message && src.stat == 0))
- log_emote("[name]/[key] : [message]")
- if (m_type & 1)
- visible_message(message)
- else
- audible_message(message)
- return
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index d875644f5f..9cbf456737 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -803,6 +803,11 @@
else
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
+ if(hud_used.staminas)
+ hud_used.staminas.icon_state = staminahudamount()
+ if(hud_used.staminabuffer)
+ hud_used.staminabuffer.icon_state = staminabufferhudamount()
+
/mob/living/carbon/human/fully_heal(admin_revive = 0)
if(admin_revive)
regenerate_limbs()
@@ -1030,8 +1035,8 @@
/mob/living/carbon/human/species/lizard/ashwalker
race = /datum/species/lizard/ashwalker
-/mob/living/carbon/human/species/moth
- race = /datum/species/moth
+/mob/living/carbon/human/species/insect
+ race = /datum/species/insect
/mob/living/carbon/human/species/mush
race = /datum/species/mush
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index e04c1bb3b9..dffb9dbe62 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -17,6 +17,8 @@
//Eye colour
var/eye_color = "000"
+ var/horn_color = "85615a" //specific horn colors, because why not?
+
var/skin_tone = "caucasian1" //Skin tone
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 1af9dbc5f5..b1c31ffdff 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -39,6 +39,10 @@
//Stuff jammed in your limbs hurts
handle_embedded_objects()
+ if(stat != DEAD)
+ //process your dick energy
+ handle_arousal()
+
//Update our name based on whether our face is obscured/disfigured
name = get_visible_name()
@@ -54,7 +58,7 @@
var/obj/item/clothing/CH = head
if (CS.clothing_flags & CH.clothing_flags & STOPSPRESSUREDAMAGE)
return ONE_ATMOSPHERE
- if(istype(loc, /obj/belly)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn
+ if(isbelly(loc)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn
return ONE_ATMOSPHERE
if(istype(loc, /obj/item/dogborg/sleeper))
return ONE_ATMOSPHERE //END OF CIT CHANGES
diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm
deleted file mode 100644
index 1ac24cffa9..0000000000
--- a/code/modules/mob/living/carbon/human/login.dm
+++ /dev/null
@@ -1,9 +0,0 @@
-/mob/living/carbon/human/Login()
- ..()
- if(src.martial_art == default_martial_art && mind.stored_martial_art) //If the mind has a martial art stored and the body has the default one.
- src.mind.stored_martial_art.teach(src) //Running teach so that it deals with help verbs.
- else if(src.martial_art != default_martial_art && src.martial_art != mind.stored_martial_art) //If the body has a martial art which is not the default one and is not stored in the mind.
- if(src.martial_art_owner != mind)
- src.martial_art.remove(src)
- else
- src.mind.stored_martial_art = src.martial_art
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 59750a47e9..3027af626e 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1,6 +1,7 @@
// This code handles different species in the game.
GLOBAL_LIST_EMPTY(roundstart_races)
+GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
@@ -15,6 +16,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/hair_color // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
+ var/horn_color //specific horn colors, because why not?
+
var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans)
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
@@ -79,6 +82,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/fixed_mut_color3 = ""
var/whitelisted = 0 //Is this species restricted to certain players?
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
+ var/should_draw_citadel = FALSE
///////////
// PROCS //
@@ -97,6 +101,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/datum/species/S = new I
if(S.check_roundstart_eligible())
GLOB.roundstart_races += S.id
+ GLOB.roundstart_race_names["[S.name]"] = S.id
qdel(S)
if(!GLOB.roundstart_races.len)
GLOB.roundstart_races += "human"
@@ -259,7 +264,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
C.hud_used.update_locked_slots()
// this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits
- if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
+ if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
species_traits += DIGITIGRADE
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(FALSE)
@@ -293,8 +298,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
for(var/datum/disease/A in C.diseases)
A.cure(FALSE)
- SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
-
//CITADEL EDIT
if(NOAROUSAL in species_traits)
C.canbearoused = FALSE
@@ -305,6 +308,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/mob/living/carbon/human/H = C
if(NOGENITALS in H.dna.species.species_traits)
H.give_genitals(TRUE) //call the clean up proc to delete anything on the mob then return.
+ if("meat_type" in default_features) //I can't believe it's come to the meat
+ H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]]
+
+ SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
+
// EDIT ENDS
@@ -319,6 +327,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
+ if("meat_type" in default_features)
+ C.type_of_meat = GLOB.meat_types[C.dna.features["meat_type"]]
+ else
+ C.type_of_meat = initial(meat)
+
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
@@ -614,6 +627,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else if ("wings" in mutant_bodyparts)
bodyparts_to_add -= "wings_open"
+ if("insect_fluff" in mutant_bodyparts)
+ if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
+ bodyparts_to_add -= "insect_fluff"
+
//CITADEL EDIT
//Race specific bodyparts:
//Xenos
@@ -719,8 +736,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
S = GLOB.wings_open_list[H.dna.features["wings"]]
if("legs")
S = GLOB.legs_list[H.dna.features["legs"]]
- if("moth_wings")
- S = GLOB.moth_wings_list[H.dna.features["moth_wings"]]
+ if("insect_wings")
+ S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
+ if("insect_fluff")
+ S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
if("caps")
S = GLOB.caps_list[H.dna.features["caps"]]
if("ipc_screen")
@@ -817,6 +836,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
accessory_overlay.color = "#[H.facial_hair_color]"
if(EYECOLOR)
accessory_overlay.color = "#[H.eye_color]"
+ if(HORNCOLOR)
+ accessory_overlay.color = "#[H.horn_color]"
else
accessory_overlay.color = forced_colour
else
@@ -882,6 +903,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
extra_accessory_overlay.color = "#[H.facial_hair_color]"
if(EYECOLOR)
extra_accessory_overlay.color = "#[H.eye_color]"
+
+ if(HORNCOLOR)
+ extra_accessory_overlay.color = "#[H.horn_color]"
standing += extra_accessory_overlay
if(S.extra2) //apply the extra overlay, if there is one
@@ -914,6 +938,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
extra2_accessory_overlay.color = "#[H.dna.features["mcolor"]]"
else
extra2_accessory_overlay.color = "#[H.hair_color]"
+ if(HORNCOLOR)
+ extra2_accessory_overlay.color = "#[H.horn_color]"
standing += extra2_accessory_overlay
@@ -1744,6 +1770,161 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.forcesay(GLOB.hit_appends) //forcesay checks stat already.
return TRUE
+/datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
+ if(!istype(M))
+ return TRUE
+ CHECK_DNA_AND_SPECIES(M)
+ CHECK_DNA_AND_SPECIES(H)
+
+ if(!istype(M)) //sanity check for drones.
+ return TRUE
+ if(M.mind)
+ attacker_style = M.mind.martial_art
+ if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
+ log_combat(M, H, "attempted to touch")
+ H.visible_message("[M] attempted to touch [H]! ")
+ return TRUE
+ switch(M.a_intent)
+ if(INTENT_HELP)
+ if(M == H)
+ althelp(M, H, attacker_style)
+ return TRUE
+ return FALSE
+ if(INTENT_DISARM)
+ altdisarm(M, H, attacker_style)
+ return TRUE
+ return FALSE
+
+/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(user == target && istype(user))
+ if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
+ to_chat(user, "You're too exhausted for that. ")
+ return
+ if(!user.resting)
+ to_chat(user, "You can only force yourself up if you're on the ground. ")
+ return
+ user.visible_message("[user] forces [p_them()]self up to [p_their()] feet! ", "You force yourself up to your feet! ")
+ user.resting = 0
+ user.update_canmove()
+ user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting
+ playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
+ to_chat(user, "You're too exhausted. ")
+ return FALSE
+ if(target.check_block())
+ target.visible_message("[target] blocks [user]'s shoving attempt! ")
+ return FALSE
+ if(attacker_style && attacker_style.disarm_act(user,target))
+ return TRUE
+ if(user.resting)
+ return FALSE
+ else
+ if(user == target)
+ return
+ user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
+ user.adjustStaminaLossBuffered(4)
+ playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
+
+ if(target.w_uniform)
+ target.w_uniform.add_fingerprint(user)
+ SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
+
+ if(!target.resting)
+ target.adjustStaminaLoss(5)
+
+
+ var/turf/target_oldturf = target.loc
+ var/shove_dir = get_dir(user.loc, target_oldturf)
+ var/turf/target_shove_turf = get_step(target.loc, shove_dir)
+ var/mob/living/carbon/human/target_collateral_human
+ var/obj/structure/table/target_table
+ var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
+
+ //Thank you based whoneedsspace
+ target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
+ if(target_collateral_human)
+ shove_blocked = TRUE
+ else
+ target.Move(target_shove_turf, shove_dir)
+ if(get_turf(target) == target_oldturf)
+ if(target_shove_turf.density)
+ shove_blocked = TRUE
+ else
+ var/thoushallnotpass = FALSE
+ for(var/obj/O in target_shove_turf)
+ if(istype(O, /obj/structure/table))
+ target_table = O
+ else if(!O.CanPass(src, target_shove_turf))
+ shove_blocked = TRUE
+ thoushallnotpass = TRUE
+ if(thoushallnotpass)
+ target_table = null
+
+ if(target.is_shove_knockdown_blocked())
+ return
+
+ if(shove_blocked || target_table)
+ var/directional_blocked = FALSE
+ if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
+ var/target_turf = get_turf(target)
+ for(var/obj/O in target_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
+ directional_blocked = TRUE
+ break
+ if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
+ for(var/obj/O in target_shove_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
+ directional_blocked = TRUE
+ break
+ var/targetatrest = target.resting
+ if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
+ user.visible_message("[user.name] shoves [target.name], knocking them down! ",
+ "You shove [target.name], knocking them down! ", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "knocking them down")
+ else if(target_table)
+ if(!targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_TABLE)
+ user.visible_message("[user.name] shoves [target.name] onto \the [target_table]! ",
+ "You shove [target.name] onto \the [target_table]! ", null, COMBAT_MESSAGE_RANGE)
+ target.forceMove(target_shove_turf)
+ log_combat(user, target, "shoved", "onto [target_table]")
+ else if(target_collateral_human && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
+ if(!target_collateral_human.resting)
+ target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
+ user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]! ",
+ "You shove [target.name] into [target_collateral_human.name]! ", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "into [target_collateral_human.name]")
+
+ else
+ user.visible_message("[user.name] shoves [target.name]! ",
+ "You shove [target.name]! ", null, COMBAT_MESSAGE_RANGE)
+ var/target_held_item = target.get_active_held_item()
+ var/knocked_item = FALSE
+ if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
+ target_held_item = null
+ if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID))
+ target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
+ if(target_held_item)
+ target.visible_message("[target.name]'s grip on \the [target_held_item] loosens! ",
+ "Your grip on \the [target_held_item] loosens! ", null, COMBAT_MESSAGE_RANGE)
+ addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
+ else if(target_held_item)
+ target.dropItemToGround(target_held_item)
+ knocked_item = TRUE
+ target.visible_message("[target.name] drops \the [target_held_item]!! ",
+ "You drop \the [target_held_item]!! ", null, COMBAT_MESSAGE_RANGE)
+ var/append_message = ""
+ if(target_held_item)
+ if(knocked_item)
+ append_message = "causing them to drop [target_held_item]"
+ else
+ append_message = "loosening their grip on [target_held_item]"
+ log_combat(user, target, "shoved", append_message)
+
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
var/hit_percent = (100-(blocked+armor))/100
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
new file mode 100644
index 0000000000..94dba550b6
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
@@ -0,0 +1,64 @@
+/datum/species/insect
+ name = "Anthromorphic Insect"
+ id = "insect"
+ say_mod = "flutters"
+ default_color = "00FF00"
+ species_traits = list(LIPS,NOEYES,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR)
+ inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
+ mutant_bodyparts = list("mam_ears", "mam_snout", "mam_tail", "taur", "insect_wings", "mam_snouts", "insect_fluff","horns")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
+ "insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None","horns" = "None")
+ attack_verb = "slash"
+ attack_sound = 'sound/weapons/slash.ogg'
+ miss_sound = 'sound/weapons/slashmiss.ogg'
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect
+ liked_food = VEGETABLES | DAIRY
+ disliked_food = FRUIT | GROSS
+ toxic_food = MEAT | RAW
+ mutanteyes = /obj/item/organ/eyes/insect
+ should_draw_citadel = TRUE
+
+/datum/species/insect/on_species_gain(mob/living/carbon/C)
+ . = ..()
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(!H.dna.features["insect_wings"])
+ H.dna.features["insect_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["insect_wings"]) ? H.client.prefs.features["insect_wings"] : "None"]"
+ handle_mutant_bodyparts(H)
+
+/datum/species/insect/random_name(gender,unique,lastname)
+ if(unique)
+ return random_unique_moth_name()
+
+ var/randname = moth_name()
+
+ if(lastname)
+ randname += " [lastname]"
+
+ return randname
+
+/datum/species/insect/handle_fire(mob/living/carbon/human/H, no_protection = FALSE)
+ ..()
+ if(H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None" && H.bodytemperature >= 800 && H.fire_stacks > 0) //do not go into the extremely hot light. you will not survive
+ to_chat(H, "Your precious wings burn to a crisp! ")
+ if(H.dna.features["insect_wings"] != "None")
+ H.dna.features["insect_wings"] = "Burnt Off"
+ handle_mutant_bodyparts(H)
+
+/datum/species/insect/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ . = ..()
+ if(chem.id == "pestkiller")
+ H.adjustToxLoss(3)
+ H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
+
+/datum/species/insect/check_weakness(obj/item/weapon, mob/living/attacker)
+ if(istype(weapon, /obj/item/melee/flyswatter))
+ return 9 //flyswatters deal 10x damage to insects
+ return 0
+
+/datum/species/insect/space_move(mob/living/carbon/human/H)
+ . = ..()
+ if(H.loc && !isspaceturf(H.loc) && (H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None"))
+ var/datum/gas_mixture/current = H.loc.return_air()
+ if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index 4d3bbecdaa..0c3bcc2b00 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -1,5 +1,5 @@
/datum/species/fly
- name = "Flyperson"
+ name = "Anthromorphic Fly"
id = "fly"
say_mod = "buzzes"
species_traits = list(NOEYES)
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
new file mode 100644
index 0000000000..e726d45347
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -0,0 +1,98 @@
+/datum/species/mammal
+ name = "Anthromorph"
+ id = "mammal"
+ default_color = "4B4B4B"
+ should_draw_citadel = TRUE
+ species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR)
+ inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "horns", "legs")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky",
+ "mam_body_markings" = "Husky", "taur" = "None", "horns" = "None", "legs" = "Plantigrade", "meat_type" = "Mammalian")
+ attack_verb = "claw"
+ attack_sound = 'sound/weapons/slash.ogg'
+ miss_sound = 'sound/weapons/slashmiss.ogg'
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal
+ liked_food = MEAT | FRIED
+ disliked_food = TOXIC
+
+//Curiosity killed the cat's wagging tail.
+/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H)
+ if(H)
+ stop_wagging_tail(H)
+
+/datum/species/mammal/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ stop_wagging_tail(H)
+ . = ..()
+
+/datum/species/mammal/can_wag_tail(mob/living/carbon/human/H)
+ return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
+
+/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H)
+ return ("mam_waggingtail" in mutant_bodyparts)
+
+/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H)
+ if("mam_tail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_tail"
+ mutant_bodyparts |= "mam_waggingtail"
+ H.update_body()
+
+/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H)
+ if("mam_waggingtail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_waggingtail"
+ mutant_bodyparts |= "mam_tail"
+ H.update_body()
+
+
+/datum/species/mammal/qualifies_for_rank(rank, list/features)
+ return TRUE
+
+
+//Alien//
+/datum/species/xeno
+ // A cloning mistake, crossing human and xenomorph DNA
+ name = "Xenomorph Hybrid"
+ id = "xeno"
+ say_mod = "hisses"
+ default_color = "00FF00"
+ should_draw_citadel = TRUE
+ species_traits = list(MUTCOLORS,EYECOLOR,LIPS)
+ inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
+ mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur", "legs")
+ default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade")
+ attack_verb = "slash"
+ attack_sound = 'sound/weapons/slash.ogg'
+ miss_sound = 'sound/weapons/slashmiss.ogg'
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
+ skinned_type = /obj/item/stack/sheet/animalhide/xeno
+ exotic_bloodtype = "L"
+ damage_overlay_type = "xeno"
+ liked_food = MEAT
+
+/datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
+ if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
+ species_traits += DIGITIGRADE
+ if(DIGITIGRADE in species_traits)
+ C.Digitigrade_Leg_Swap(FALSE)
+ . = ..()
+
+/datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
+ if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade")
+ species_traits -= DIGITIGRADE
+ if(DIGITIGRADE in species_traits)
+ C.Digitigrade_Leg_Swap(TRUE)
+ . = ..()
+
+//Praise the Omnissiah, A challange worthy of my skills - HS
+
+//EXOTIC//
+//These races will likely include lots of downsides and upsides. Keep them relatively balanced.//
+
+//misc
+/mob/living/carbon/human/dummy
+ no_vore = TRUE
+
+/mob/living/carbon/human/vore
+ devourable = TRUE
+ digestable = TRUE
+ feeding = TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 88dd59749c..84c44ea81c 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -45,7 +45,7 @@
return golem_name
/datum/species/golem/random
- name = "Random Golem"
+ name = "Golem Mutant"
blacklisted = FALSE
dangerous_existence = FALSE
var/static/list/random_golem_types
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm
similarity index 98%
rename from modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
rename to code/modules/mob/living/carbon/human/species_types/ipc.dm
index ab0c7ea161..135c98860a 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -1,5 +1,5 @@
/datum/species/ipc
- name = "IPC"
+ name = "I.P.C."
id = "ipc"
say_mod = "beeps"
default_color = "00FF00"
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index b564ca33e4..45c2da8de0 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -120,7 +120,7 @@
//Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death.
/datum/species/jelly/slime
- name = "Slimeperson"
+ name = "Xenobiological Slime Entity"
id = "slime"
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
@@ -391,12 +391,268 @@
"...and move this one instead. ")
+////////////////////////////////////////////////////////Round Start Slimes///////////////////////////////////////////////////////////////////
+
+/datum/species/jelly/roundstartslime
+ name = "Xenobiological Slime Hybrid"
+ id = "slimeperson"
+ limbs_id = "slime"
+ default_color = "00FFFF"
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
+ inherent_traits = list(TRAIT_TOXINLOVER)
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur")
+ default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
+ say_mod = "says"
+ hair_color = "mutcolor"
+ hair_alpha = 160 //a notch brighter so it blends better.
+ coldmod = 3
+ heatmod = 1
+ burnmod = 1
+
+/datum/species/jelly/roundstartslime/spec_death(gibbed, mob/living/carbon/human/H)
+ if(H)
+ stop_wagging_tail(H)
+
+/datum/species/jelly/roundstartslime/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ stop_wagging_tail(H)
+ . = ..()
+
+/datum/species/jelly/roundstartslime/can_wag_tail(mob/living/carbon/human/H)
+ return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
+
+/datum/species/jelly/roundstartslime/is_wagging_tail(mob/living/carbon/human/H)
+ return ("mam_waggingtail" in mutant_bodyparts)
+
+/datum/species/jelly/roundstartslime/start_wagging_tail(mob/living/carbon/human/H)
+ if("mam_tail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_tail"
+ mutant_bodyparts |= "mam_waggingtail"
+ H.update_body()
+
+/datum/species/jelly/roundstartslime/stop_wagging_tail(mob/living/carbon/human/H)
+ if("mam_waggingtail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_waggingtail"
+ mutant_bodyparts |= "mam_tail"
+ H.update_body()
+
+
+/datum/action/innate/slime_change
+ name = "Alter Form"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "alter_form" //placeholder
+ icon_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/slime_change/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!isjellyperson(H))
+ return
+ else
+ H.visible_message("[owner] gains a look of \
+ concentration while standing perfectly still.\
+ Their body seems to shift and starts getting more goo-like. ",
+ "You focus intently on altering your body while \
+ standing perfectly still... ")
+ change_form()
+
+/datum/action/innate/slime_change/proc/change_form()
+ var/mob/living/carbon/human/H = owner
+ var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
+ if(select_alteration == "Hair Style")
+ if(H.gender == MALE)
+ var/new_style = input(owner, "Select a facial hair style", "Hair Alterations") as null|anything in GLOB.facial_hair_styles_list
+ if(new_style)
+ H.facial_hair_style = new_style
+ else
+ H.facial_hair_style = "Shaved"
+ //handle normal hair
+ var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list
+ if(new_style)
+ H.hair_style = new_style
+ H.update_hair()
+ else if (select_alteration == "Genitals")
+ var/list/organs = list()
+ var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add sexual organ", "remove sexual organ", "cancel")
+ switch(operation)
+ if("add sexual organ")
+ var/new_organ = input("Select sexual organ:", "Organ Manipulation") in list("Penis", "Testicles", "Breasts", "Vagina", "Womb", "Cancel")
+ if(new_organ == "Penis")
+ H.give_penis()
+ else if(new_organ == "Testicles")
+ H.give_balls()
+ else if(new_organ == "Breasts")
+ H.give_breasts()
+ else if(new_organ == "Vagina")
+ H.give_vagina()
+ else if(new_organ == "Womb")
+ H.give_womb()
+ else
+ return
+ if("remove sexual organ")
+ for(var/obj/item/organ/genital/X in H.internal_organs)
+ var/obj/item/organ/I = X
+ organs["[I.name] ([I.type])"] = I
+ var/obj/item/organ = input("Select sexual organ:", "Organ Manipulation", null) in organs
+ organ = organs[organ]
+ if(!organ)
+ return
+ var/obj/item/organ/genital/O
+ if(isorgan(organ))
+ O = organ
+ O.Remove(H)
+ organ.forceMove(get_turf(H))
+ qdel(organ)
+ H.update_genitals()
+
+ else if (select_alteration == "Ears")
+ var/list/snowflake_ears_list = list("Normal" = null)
+ for(var/path in GLOB.mam_ears_list)
+ var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
+ snowflake_ears_list[S.name] = path
+ var/new_ears
+ new_ears = input(owner, "Choose your character's ears:", "Ear Alteration") as null|anything in snowflake_ears_list
+ if(new_ears)
+ H.dna.features["mam_ears"] = new_ears
+ H.update_body()
+
+ else if (select_alteration == "Snout")
+ var/list/snowflake_snouts_list = list("Normal" = null)
+ for(var/path in GLOB.mam_snouts_list)
+ var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
+ snowflake_snouts_list[S.name] = path
+ var/new_snout
+ new_snout = input(owner, "Choose your character's face:", "Face Alteration") as null|anything in snowflake_snouts_list
+ if(new_snout)
+ H.dna.features["mam_snouts"] = new_snout
+ H.update_body()
+
+ else if (select_alteration == "Markings")
+ var/list/snowflake_markings_list = list()
+ for(var/path in GLOB.mam_body_markings_list)
+ var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
+ snowflake_markings_list[S.name] = path
+ var/new_mam_body_markings
+ new_mam_body_markings = input(H, "Choose your character's body markings:", "Marking Alteration") as null|anything in snowflake_markings_list
+ if(new_mam_body_markings)
+ H.dna.features["mam_body_markings"] = new_mam_body_markings
+ if(new_mam_body_markings == "None")
+ H.dna.features["mam_body_markings"] = "Plain"
+ for(var/X in H.bodyparts) //propagates the markings changes
+ var/obj/item/bodypart/BP = X
+ BP.update_limb(FALSE, H)
+ H.update_body()
+
+ else if (select_alteration == "Tail")
+ var/list/snowflake_tails_list = list("Normal" = null)
+ for(var/path in GLOB.mam_tails_list)
+ var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
+ snowflake_tails_list[S.name] = path
+ var/new_tail
+ new_tail = input(owner, "Choose your character's Tail(s):", "Tail Alteration") as null|anything in snowflake_tails_list
+ if(new_tail)
+ H.dna.features["mam_tail"] = new_tail
+ if(new_tail != "None")
+ H.dna.features["taur"] = "None"
+ H.update_body()
+
+ else if (select_alteration == "Taur body")
+ var/list/snowflake_taur_list = list("Normal" = null)
+ for(var/path in GLOB.taur_list)
+ var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
+ snowflake_taur_list[S.name] = path
+ var/new_taur
+ new_taur = input(owner, "Choose your character's tauric body:", "Tauric Alteration") as null|anything in snowflake_taur_list
+ if(new_taur)
+ H.dna.features["taur"] = new_taur
+ if(new_taur != "None")
+ H.dna.features["mam_tail"] = "None"
+ H.update_body()
+
+ else if (select_alteration == "Penis")
+ for(var/obj/item/organ/genital/penis/X in H.internal_organs)
+ qdel(X)
+ var/new_shape
+ new_shape = input(owner, "Choose your character's dong", "Genital Alteration") as null|anything in GLOB.cock_shapes_list
+ if(new_shape)
+ H.dna.features["cock_shape"] = new_shape
+ H.update_genitals()
+ H.give_balls()
+ H.give_penis()
+ H.apply_overlay()
+
+
+ else if (select_alteration == "Vagina")
+ for(var/obj/item/organ/genital/vagina/X in H.internal_organs)
+ qdel(X)
+ var/new_shape
+ new_shape = input(owner, "Choose your character's pussy", "Genital Alteration") as null|anything in GLOB.vagina_shapes_list
+ if(new_shape)
+ H.dna.features["vag_shape"] = new_shape
+ H.update_genitals()
+ H.give_womb()
+ H.give_vagina()
+ H.apply_overlay()
+
+ else if (select_alteration == "Penis Length")
+ for(var/obj/item/organ/genital/penis/X in H.internal_organs)
+ qdel(X)
+ var/new_length
+ new_length = input(owner, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Genital Alteration") as num|null
+ if(new_length)
+ H.dna.features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
+ H.update_genitals()
+ H.apply_overlay()
+ H.give_balls()
+ H.give_penis()
+
+ else if (select_alteration == "Breast Size")
+ for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
+ qdel(X)
+ var/new_size
+ new_size = input(owner, "Breast Size", "Genital Alteration") as null|anything in GLOB.breasts_size_list
+ if(new_size)
+ H.dna.features["breasts_size"] = new_size
+ H.update_genitals()
+ H.apply_overlay()
+ H.give_breasts()
+
+ else if (select_alteration == "Breast Shape")
+ for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
+ qdel(X)
+ var/new_shape
+ new_shape = input(owner, "Breast Shape", "Genital Alteration") as null|anything in GLOB.breasts_shapes_list
+ if(new_shape)
+ H.dna.features["breasts_shape"] = new_shape
+ H.update_genitals()
+ H.apply_overlay()
+ H.give_breasts()
+
+ else
+ return
+
+
///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
//Luminescents are able to consume and use slime extracts, without them decaying.
/datum/species/jelly/luminescent
- name = "Luminescent"
+ name = "Luminescent Slime Entity"
id = "lum"
say_mod = "says"
var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
@@ -563,7 +819,7 @@
//Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants.
/datum/species/jelly/stargazer
- name = "Stargazer"
+ name = "Stargazer Slime Entity"
id = "stargazer"
var/datum/action/innate/project_thought/project_thought
var/datum/action/innate/link_minds/link_minds
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index c6105deb33..4dbfd23df8 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -1,17 +1,19 @@
/datum/species/lizard
// Reptilian humanoids with scaled skin and tails.
- name = "Lizardperson"
+ name = "Anthromorphic Lizard"
id = "lizard"
say_mod = "hisses"
- default_color = "117720"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS)
+ default_color = "00FF00"
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_REPTILE)
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur")
mutanttongue = /obj/item/organ/tongue/lizard
mutanttail = /obj/item/organ/tail/lizard
coldmod = 1.5
heatmod = 0.67
- default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round", "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "taur" = "None")
+ default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round",
+ "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None",
+ "legs" = "Digitigrade", "taur" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -71,14 +73,14 @@
H.update_body()
/datum/species/lizard/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
- if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
+ if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
species_traits += DIGITIGRADE
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(FALSE)
return ..()
/datum/species/lizard/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
- if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Normal Legs")
+ if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade")
species_traits -= DIGITIGRADE
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(TRUE)
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
deleted file mode 100644
index 2b1d6cb5db..0000000000
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ /dev/null
@@ -1,62 +0,0 @@
-/datum/species/moth
- name = "Mothman"
- id = "moth"
- say_mod = "flutters"
- default_color = "00FF00"
- species_traits = list(LIPS, NOEYES)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
- mutant_bodyparts = list("moth_wings")
- default_features = list("moth_wings" = "Plain")
- attack_verb = "slash"
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth
- liked_food = VEGETABLES | DAIRY
- disliked_food = FRUIT | GROSS
- toxic_food = MEAT | RAW
- mutanteyes = /obj/item/organ/eyes/moth
- exotic_bloodtype = "BUG"
-
-/datum/species/moth/on_species_gain(mob/living/carbon/C)
- . = ..()
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(!H.dna.features["moth_wings"])
- H.dna.features["moth_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["moth_wings"]) ? H.client.prefs.features["moth_wings"] : "Plain"]"
- handle_mutant_bodyparts(H)
-
-/datum/species/moth/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_moth_name()
-
- var/randname = moth_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
-/datum/species/moth/handle_fire(mob/living/carbon/human/H, no_protection = FALSE)
- ..()
- if(H.dna.features["moth_wings"] != "Burnt Off" && H.bodytemperature >= 800 && H.fire_stacks > 0) //do not go into the extremely hot light. you will not survive
- to_chat(H, "Your precious wings burn to a crisp! ")
- H.dna.features["moth_wings"] = "Burnt Off"
- handle_mutant_bodyparts(H)
-
-/datum/species/moth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- . = ..()
- if(chem.id == "pestkiller")
- H.adjustToxLoss(3)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
-
-/datum/species/moth/check_weakness(obj/item/weapon, mob/living/attacker)
- if(istype(weapon, /obj/item/melee/flyswatter))
- return 9 //flyswatters deal 10x damage to moths
- return 0
-
-/datum/species/moth/space_move(mob/living/carbon/human/H)
- . = ..()
- if(H.loc && !isspaceturf(H.loc) && H.dna.features["moth_wings"] != "Burnt Off")
- var/datum/gas_mixture/current = H.loc.return_air()
- if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
- return TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index 7be0265cba..ceadb28115 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -1,5 +1,5 @@
/datum/species/mush //mush mush codecuck
- name = "Mushroomperson"
+ name = "Anthromorphic Mushroom"
id = "mush"
mutant_bodyparts = list("caps")
default_features = list("caps" = "Round")
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 d7bb151ddc..b4d47033f3 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -1,5 +1,5 @@
/datum/species/plasmaman
- name = "Plasmaman"
+ name = "Phoronoid"
id = "plasmaman"
say_mod = "rattles"
sexes = 0
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index 0da4073f1d..46207e5e60 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -1,6 +1,6 @@
/datum/species/pod
// A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness.
- name = "Podperson"
+ name = "Anthromorphic Plant"
id = "pod"
default_color = "59CE00"
species_traits = list(MUTCOLORS,EYECOLOR)
@@ -71,6 +71,7 @@
H.nutrition = min(H.nutrition+30, NUTRITION_LEVEL_FULL)
/datum/species/pod/pseudo_weak
+ name = "Anthromorphic Plant"
id = "podweak"
limbs_id = "pod"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index 0ebd6e795b..e325cbb4f4 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -1,5 +1,5 @@
/datum/species/synth
- name = "Synth" //inherited from the real species, for health scanners and things
+ name = "Synthetic" //inherited from the real species, for health scanners and things
id = "synth"
say_mod = "beep boops" //inherited from a user's real species
sexes = 0
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
deleted file mode 100644
index 51c7ad9d25..0000000000
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ /dev/null
@@ -1,91 +0,0 @@
-/mob/living/carbon/human/whisper_verb(message as text)
- whisper(message)
-
-/mob/living/carbon/human/whisper(message, datum/language/language=null)
- if(!IsVocal())
- return
- if(!message)
- return
- if(!language)
- language = get_default_language()
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "Speech is currently admin-disabled. ")
- return
-
- if(stat == DEAD)
- return
-
-
- message = trim(html_encode(message))
- if(!can_speak(message))
- return
-
- message = "[message]"
- log_whisper("[src.name]/[src.key] : [message]")
-
- if (src.client)
- if (src.client.prefs.muted & MUTE_IC)
- to_chat(src, "You cannot whisper (muted). ")
- return
-
- log_whisper("[src.name]/[src.key] : [message]")
-
- var/alt_name = get_alt_name()
-
- var/whispers = "whispers"
- var/critical = InCritical()
-
- // We are unconscious but not in critical, so don't allow them to whisper.
- if(stat == UNCONSCIOUS && !critical)
- return
-
- // If whispering your last words, limit the whisper based on how close you are to death.
- if(critical)
- var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health)
- // If we cut our message short, abruptly end it with a-..
- var/message_len = length(message)
- message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
- message = Ellipsis(message, 10, 1)
-
- message = treat_message(message)
- if(!message)
- return
-
- var/list/listening_dead = list()
- for(var/mob/M in GLOB.player_list)
- if(M.stat == DEAD && M.client && ((M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER) || (get_dist(M, src) <= 7)))
- listening_dead |= M
-
- var/list/listening = get_hearers_in_view(1, src)
- listening |= listening_dead
- var/list/eavesdropping = get_hearers_in_view(2, src)
- eavesdropping -= listening
- var/list/watching = hearers(5, src)
- watching -= listening
- watching -= eavesdropping
-
- var/rendered
- whispers = critical ? "whispers something in [p_their()] final breath." : "whispers something."
- rendered = "[src.name] [whispers] "
- for(var/mob/M in watching)
- M.show_message(rendered, 2)
-
- var/spans = list(SPAN_ITALICS)
- whispers = critical ? "whispers in [p_their()] final breath" : "whispers"
- rendered = "[GetVoice()] [alt_name] [whispers], \"[attach_spans(message, spans)]\" "
-
- for(var/atom/movable/AM in listening)
- if(istype(AM,/obj/item/radio))
- continue
- AM.Hear(rendered, src, language, message, , spans)
-
- message = stars(message)
- rendered = "[GetVoice()] [alt_name] [whispers], \"[attach_spans(message, spans)]\" "
- for(var/atom/movable/AM in eavesdropping)
- if(istype(AM,/obj/item/radio))
- continue
- AM.Hear(rendered, src, language, message, , spans)
-
- if(critical) //Dying words.
- succumb()
diff --git a/code/modules/oracle_ui/themed.dm b/code/modules/oracle_ui/themed.dm
index bdcd294ce8..56b82c2647 100644
--- a/code/modules/oracle_ui/themed.dm
+++ b/code/modules/oracle_ui/themed.dm
@@ -33,10 +33,10 @@ GLOBAL_LIST_EMPTY(oui_file_cache)
return errormsg
/datum/oracle_ui/themed/proc/get_content_file(filename)
- return get_file("./modular_citadel/html/oracle_ui/content/[content_root]/[filename]")
+ return get_file("./html/oracle_ui/content/[content_root]/[filename]")
/datum/oracle_ui/themed/proc/get_themed_file(filename)
- return get_file("./modular_citadel/html/oracle_ui/themes/[theme]/[filename]")
+ return get_file("./html/oracle_ui/themes/[theme]/[filename]")
/datum/oracle_ui/themed/proc/process_template(template, variables)
var/regex/pattern = regex("\\@\\{(\\w+)\\}","gi")
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 5e271cf710..4ec5bc469b 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -621,12 +621,12 @@
race = /datum/species/fly
mutationtext = "The pain subsides. You feel... buzzy. "
-/datum/reagent/mutationtoxin/moth
- name = "Moth Mutation Toxin"
+/datum/reagent/mutationtoxin/insect
+ name = "Insect Mutation Toxin"
id = "mothmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
- race = /datum/species/moth
+ race = /datum/species/insect
mutationtext = "The pain subsides. You feel... attracted to light. "
/datum/reagent/mutationtoxin/pod
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index e34f34675c..fb2e4c396c 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -623,7 +623,7 @@
required_temp = 450
/datum/chemical_reaction/moff
- name = "moth mutation toxic"
+ name = "insect mutation toxic"
id = "moffs"
results = list("mothmutationtoxin" = 1)
required_reagents = list("liquid_dark_matter" = 2, "ammonia" = 5, "lithium" = 1, "stablemutationtoxin" = 1)
diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm
index 71f7234e34..dae59408c8 100644
--- a/code/modules/research/designs/limbgrower_designs.dm
+++ b/code/modules/research/designs/limbgrower_designs.dm
@@ -8,7 +8,7 @@
build_type = LIMBGROWER
reagents_list = list("synthflesh" = 25)
build_path = /obj/item/bodypart/l_arm
- category = list("initial","human","lizard","fly","moth","plasmaman")
+ category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno")
/datum/design/rightarm
name = "Right Arm"
@@ -16,7 +16,7 @@
build_type = LIMBGROWER
reagents_list = list("synthflesh" = 25)
build_path = /obj/item/bodypart/r_arm
- category = list("initial","human","lizard","fly","moth","plasmaman")
+ category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno")
/datum/design/leftleg
name = "Left Leg"
@@ -24,7 +24,7 @@
build_type = LIMBGROWER
reagents_list = list("synthflesh" = 25)
build_path = /obj/item/bodypart/l_leg
- category = list("initial","human","lizard","fly","moth","plasmaman")
+ category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno")
/datum/design/rightleg
name = "Right Leg"
@@ -32,7 +32,7 @@
build_type = LIMBGROWER
reagents_list = list("synthflesh" = 25)
build_path = /obj/item/bodypart/r_leg
- category = list("initial","human","lizard","fly","moth","plasmaman")
+ category = list("initial","human","lizard","fly","insect","plasmaman","mammal","xeno")
/datum/design/armblade
name = "Arm Blade"
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index fb3de4c1c5..7c7111181f 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -40,6 +40,7 @@
var/skin_tone = ""
var/body_gender = ""
var/species_id = ""
+ var/should_draw_citadel = FALSE
var/should_draw_gender = FALSE
var/should_draw_greyscale = FALSE
var/species_color = ""
@@ -48,8 +49,8 @@
var/body_markings = "" //for bodypart markings
var/body_markings_icon = 'modular_citadel/icons/mob/mam_markings.dmi'
var/list/markings_color = list()
- var/auxmarking = ""
- var/list/auxmarking_color = list()
+ var/aux_marking
+ var/digitigrade_type
var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
var/dismemberable = 1 //whether it can be dismembered with a weapon.
@@ -309,7 +310,7 @@
should_draw_greyscale = FALSE
no_update = TRUE
body_markings = "husk" // reeee
- auxmarking = "husk"
+ aux_marking = "husk"
if(no_update)
return
@@ -351,6 +352,13 @@
else
species_color = ""
+ if("legs" in S.default_features)
+ if(body_zone == BODY_ZONE_L_LEG || body_zone == BODY_ZONE_R_LEG)
+ if(DIGITIGRADE in S.species_traits)
+ digitigrade_type = lowertext(H.dna.features.["legs"])
+ else
+ digitigrade_type = null
+
if("mam_body_markings" in S.default_features)
var/datum/sprite_accessory/Smark
Smark = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
@@ -358,15 +366,15 @@
body_markings_icon = Smark.icon
if(H.dna.features.["mam_body_markings"] != "None")
body_markings = lowertext(H.dna.features.["mam_body_markings"])
- auxmarking = lowertext(H.dna.features.["mam_body_markings"])
+ aux_marking = lowertext(H.dna.features.["mam_body_markings"])
else
body_markings = "plain"
- auxmarking = "plain"
+ aux_marking = "plain"
markings_color = list(colorlist)
else
body_markings = null
- auxmarking = null
+ aux_marking = null
if(!dropping_limb && H.dna.check_mutation(HULK))
mutation_color = "00aa00"
@@ -381,7 +389,7 @@
if(status == BODYPART_ROBOTIC)
dmg_overlay_type = "robotic"
body_markings = null
- auxmarking = null
+ aux_marking = null
if(dropping_limb)
no_update = TRUE //when attached, the limb won't be affected by the appearance changes of its mob owner.
@@ -423,7 +431,7 @@
else
. += image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
else
- . += image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ . += image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir)
var/image/aux
@@ -453,21 +461,25 @@
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
else if(use_digitigrade)
- limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]"
+ limb.icon_state = "[digitigrade_type]_[use_digitigrade]_[body_zone]"
else
limb.icon_state = "[species_id]_[body_zone]"
else
limb.icon = 'icons/mob/human_parts.dmi'
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
+ else if(use_digitigrade)
+ limb.icon_state = "[species_id]_[digitigrade_type]_[use_digitigrade]_[body_zone]"
else
limb.icon_state = "[species_id]_[body_zone]"
// Citadel Start
- if(should_draw_citadel && !use_digitigrade)
+ if(should_draw_citadel)
limb.icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
+ else if(use_digitigrade)
+ limb.icon_state = "[species_id]_[digitigrade_type]_[use_digitigrade]_[body_zone]"
else
limb.icon_state = "[species_id]_[body_zone]"
@@ -476,7 +488,7 @@
if(species_id == "husk")
marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir)
else if(species_id == "husk" && use_digitigrade)
- marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ marking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
else if(!use_digitigrade)
if(body_zone == BODY_ZONE_CHEST)
@@ -484,20 +496,21 @@
else
marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
else
- marking = image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+
. += marking
// Citadel End
if(aux_zone)
aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
- . += aux
- if(!isnull(auxmarking))
+ if(!isnull(aux_marking))
if(species_id == "husk")
auxmarking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
else
auxmarking = image(body_markings_icon, "[body_markings]_[aux_zone]", -aux_layer, image_dir)
- . += auxmarking
+ . += aux
+ . += auxmarking
else
limb.icon = icon
@@ -509,7 +522,7 @@
if(aux_zone)
aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir)
. += aux
- if(!isnull(auxmarking))
+ if(!isnull(aux_marking))
if(species_id == "husk")
auxmarking = image('modular_citadel/icons/mob/markings_notmammals.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
else
@@ -528,7 +541,7 @@
else
marking = image(body_markings_icon, "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
else
- marking = image(body_markings_icon, "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ marking = image(body_markings_icon, "[body_markings]_[digitigrade_type]_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
. += marking
return
@@ -538,8 +551,11 @@
limb.color = "#[draw_color]"
if(aux_zone)
aux.color = "#[draw_color]"
- if(!isnull(auxmarking))
- auxmarking.color = list(markings_color)
+ if(!isnull(aux_marking))
+ if(species_id == "husk")
+ auxmarking.color = "#141414"
+ else
+ auxmarking.color = list(markings_color)
if(!isnull(body_markings))
if(species_id == "husk")
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index eeaaaf2a03..40d11ca2a4 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -321,7 +321,7 @@
if(!istype(parent))
return INITIALIZE_HINT_QDEL
-/obj/item/organ/eyes/moth
- name = "moth eyes"
+/obj/item/organ/eyes/insect
+ name = "insect eyes"
desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision."
flash_protect = -1
diff --git a/config/game_options.txt b/config/game_options.txt
index 6d59f10807..2e346ce0ac 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -410,7 +410,7 @@ ROUNDSTART_RACES human
## Races that are strictly worse than humans that could probably be turned on without balance concerns
ROUNDSTART_RACES lizard
#ROUNDSTART_RACES fly
-#ROUNDSTART_RACES moth
+#ROUNDSTART_RACES insect
ROUNDSTART_RACES plasmaman
#ROUNDSTART_RACES shadow
ROUNDSTART_RACES felinid
diff --git a/html/changelogs/AutoChangeLog-pr-9277.yml b/html/changelogs/AutoChangeLog-pr-9277.yml
new file mode 100644
index 0000000000..4bf92cd32e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9277.yml
@@ -0,0 +1,11 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "Added new wings to Insects and separated fluff from old ones, they're Insect's new body markings now without being per-limb (for now)."
+ - rscadd: "Horns are now available to mammals, and they have their own color."
+ - rscadd: "Legs are no longer a binary hack code, but actually something that can be changed. Framework for tauric adaptations."
+ - rscdel: "Purged Modular Citadel's sprite_accessories."
+ - bugfix: "improved the quality of a number of sprites."
+ - tweak: "Moths are now all insects. Avians and Aquatics are all anthromorphics. Just as planned."
+ - rscadd: "Anthromorphs can choose their preferred gibbing meat. I guess. Snowflakes are weird."
+ - bugfix: "Additional Gentlemen names."
diff --git a/html/changelogs/AutoChangeLog-pr-9288.yml b/html/changelogs/AutoChangeLog-pr-9288.yml
new file mode 100644
index 0000000000..8a684431bf
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9288.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "UI memes"
diff --git a/html/changelogs/AutoChangeLog-pr-9289.yml b/html/changelogs/AutoChangeLog-pr-9289.yml
new file mode 100644
index 0000000000..7abf947bfc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9289.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - bugfix: "fixing chems for strained muscles"
diff --git a/icons/mob/human_parts.dmi b/icons/mob/human_parts.dmi
index fc6fafb275..6bd504674f 100644
Binary files a/icons/mob/human_parts.dmi and b/icons/mob/human_parts.dmi differ
diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi
index 7f10d992bc..8b894fea6b 100644
Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ
diff --git a/icons/mob/mutant_bodyparts.dmi b/icons/mob/mutant_bodyparts.dmi
index 19ebe0a4be..f8d1f22860 100644
Binary files a/icons/mob/mutant_bodyparts.dmi and b/icons/mob/mutant_bodyparts.dmi differ
diff --git a/icons/mob/wings.dmi b/icons/mob/wings.dmi
index b2990a1509..58f4cb735c 100644
Binary files a/icons/mob/wings.dmi and b/icons/mob/wings.dmi differ
diff --git a/modular_citadel/code/game/objects/items/meat.dm b/modular_citadel/code/game/objects/items/meat.dm
deleted file mode 100644
index 3891c5ca9d..0000000000
--- a/modular_citadel/code/game/objects/items/meat.dm
+++ /dev/null
@@ -1,26 +0,0 @@
-/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
- icon = 'modular_citadel/icons/obj/foods.dmi'
- icon_state = "ipcmeat"
- desc = "Gross robot meat."
- filling_color = "#000000"
- tastes = list("metal" = 1)
-
-/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth
- icon = 'modular_citadel/icons/obj/foods.dmi'
- icon_state = "mothmeat"
- desc = "Moth meat."
- filling_color = "#BF896B"
- tastes = list("insects" = 1)
-
-
-/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/avian
- icon = 'modular_citadel/icons/obj/foods.dmi'
- icon_state = "birdmeat"
- desc = "Quality bird meat."
- filling_color = "#BF896B"
- tastes = list("chicken" = 1)
-
-/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal
- desc = "Furry meat. WHO DID THIS?!"
- filling_color = "#6B8E23"
- tastes = list("brains" = 1, "meat" = 1)
\ No newline at end of file
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
index ce80580af2..a85c3a249c 100644
--- a/modular_citadel/code/init.dm
+++ b/modular_citadel/code/init.dm
@@ -3,23 +3,3 @@
/proc/cit_initialize()
load_mentors()
initialize_global_loadout_items()
-
- //body parts and things
- init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/screen, GLOB.ipc_screens_list, roundstart = TRUE)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/antenna, GLOB.ipc_antennas_list, roundstart = TRUE)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
- for(var/K in GLOB.cock_shapes_list)
- var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
- GLOB.cock_shapes_icons[K] = value.icon_state
- init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
- //GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. This is defined twice?
diff --git a/modular_citadel/code/modules/food_and_drinks/snacks/meat.dm b/modular_citadel/code/modules/food_and_drinks/snacks/meat.dm
index eba3660f8d..f1b5d622bc 100644
--- a/modular_citadel/code/modules/food_and_drinks/snacks/meat.dm
+++ b/modular_citadel/code/modules/food_and_drinks/snacks/meat.dm
@@ -1,3 +1,29 @@
/obj/item/reagent_containers/food/snacks/carpmeat/aquatic
name = "fillet"
desc = "A fillet of one of the local water dwelling species."
+
+/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
+ icon = 'modular_citadel/icons/obj/foods.dmi'
+ icon_state = "ipcmeat"
+ desc = "Gross robot meat."
+ filling_color = "#000000"
+ tastes = list("metal" = 1)
+
+/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect
+ desc = "Tastes like chicken, that's... not what it is!"
+ icon = 'modular_citadel/icons/obj/foods.dmi'
+ icon_state = "mothmeat"
+ filling_color = "#BF896B"
+ tastes = list("insects" = 1)
+
+/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/avian
+ desc = "Tastes like chicken, that's because it is!"
+ icon = 'modular_citadel/icons/obj/foods.dmi'
+ icon_state = "birdmeat"
+ filling_color = "#BF896B"
+ tastes = list("chicken" = 1)
+
+/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal
+ desc = "Tastes sweet... reminds you vaguely of chicken."
+ filling_color = "#6B8E23"
+ tastes = list("brains" = 1, "meat" = 1)
diff --git a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
deleted file mode 100644
index bf811b777c..0000000000
--- a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ /dev/null
@@ -1,2083 +0,0 @@
-/datum/sprite_accessory
- var/extra = FALSE
- var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
- var/extra2 = FALSE
- var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- var/extra2_color_src = MUTCOLORS3
- var/list/ckeys_allowed
-
-/datum/sprite_accessory/moth_wings/none
- name = "None"
- icon_state = "none"
-
-/***************** Alphabetical Order please ***************
-************* Keep it to Ears, Tails, Tails Animated *********/
-
-
-/datum/sprite_accessory/tails/lizard/none
- name = "None"
- icon_state = "None"
-
-/datum/sprite_accessory/tails_animated/lizard/none
- name = "None"
- icon_state = "None"
-
-
-/datum/sprite_accessory/tails/lizard/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/lizard/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/body_markings/guilmon
- name = "Guilmon"
- icon_state = "guilmon"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/tails/lizard/guilmon
- name = "Guilmon"
- icon_state = "guilmon"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/lizard/guilmon
- name = "Guilmon"
- icon_state = "guilmon"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-//christ this was a mistake, but it's here just in case someone wants to selectively fix
-/************* Lizard compatable snoots ***********
-/datum/sprite_accessory/snouts/bird
- name = "Beak"
- icon_state = "bird"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/bigbeak
- name = "Big Beak"
- icon_state = "bigbeak"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/bug
- name = "Bug"
- icon_state = "bug"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra2 = TRUE
- extra2_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/snouts/elephant
- name = "Elephant"
- icon_state = "elephant"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
- extra = TRUE
- extra_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/snouts/lcanid
- name = "Mammal, Long"
- icon_state = "lcanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/lcanidalt
- name = "Mammal, Long ALT"
- icon_state = "lcanidalt"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/scanid
- name = "Mammal, Short"
- icon_state = "scanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/scanidalt
- name = "Mammal, Short ALT"
- icon_state = "scanidalt"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/wolf
- name = "Mammal, Thick"
- icon_state = "wolf"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/wolfalt
- name = "Mammal, Thick ALT"
- icon_state = "wolfalt"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/redpanda
- name = "WahCoon"
- icon_state = "wah"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/rhino
- name = "Horn"
- icon_state = "rhino"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
- extra = TRUE
- extra = MUTCOLORS3
-
-/datum/sprite_accessory/snouts/rodent
- name = "Rodent"
- icon_state = "rodent"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/husky
- name = "Husky"
- icon_state = "husky"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/otie
- name = "Otie"
- icon_state = "otie"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/pede
- name = "Scolipede"
- icon_state = "pede"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/sergal
- name = "Sergal"
- icon_state = "sergal"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/snouts/shark
- name = "Shark"
- icon_state = "shark"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
-
-/datum/sprite_accessory/snouts/toucan
- name = "Toucan"
- icon_state = "toucan"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MATRIXED
-*/
-
-/******************************************
-*************** Human Ears ****************
-*******************************************/
-
-/datum/sprite_accessory/ears/human/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/ears/human/bear
- name = "Bear"
- icon_state = "bear"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/bigwolf
- name = "Big Wolf"
- icon_state = "bigwolf"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/bigwolfinner
- name = "Big Wolf (ALT)"
- icon_state = "bigwolfinner"
- hasinner = 1
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/bigwolfdark
- name = "Dark Big Wolf"
- icon_state = "bigwolfdark"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/bigwolfinnerdark
- name = "Dark Big Wolf (ALT)"
- icon_state = "bigwolfinnerdark"
- hasinner = 1
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/cow
- name = "Cow"
- icon_state = "cow"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/curled
- name = "Curled Horn"
- icon_state = "horn1"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MUTCOLORS3
-
-/datum/sprite_accessory/ears/human/eevee
- name = "Eevee"
- icon_state = "eevee"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/elephant
- name = "Elephant"
- icon_state = "elephant"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/elf
- name = "Elf"
- icon_state = "elf"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = SKINTONE
-
-/datum/sprite_accessory/ears/fennec
- name = "Fennec"
- icon_state = "fennec"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/fish
- name = "Fish"
- icon_state = "fish"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/fox
- name = "Fox"
- icon_state = "fox"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/ears/human/jellyfish
- name = "Jellyfish"
- icon_state = "jellyfish"
- color_src = HAIR
-
-/datum/sprite_accessory/ears/lab
- name = "Dog, Floppy"
- icon_state = "lab"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/ears/murid
- name = "Murid"
- icon_state = "murid"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/otie
- name = "Otusian"
- icon_state = "otie"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/ears/human/pede
- name = "Scolipede"
- icon_state = "pede"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/ears/human/sergal
- name = "Sergal"
- icon_state = "sergal"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/human/skunk
- name = "skunk"
- icon_state = "skunk"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/ears/wolf
- name = "Wolf"
- icon_state = "wolf"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-
-
-/******************************************
-************** Human Tails ****************
-*******************************************/
-
-/datum/sprite_accessory/tails/human/ailurus
- name = "Red Panda"
- icon_state = "wah"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/ailurus
- name = "Red Panda"
- icon_state = "wah"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/bee
- name = "Bee"
- icon_state = "bee"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/bee
- name = "Bee"
- icon_state = "bee"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/cat
- name = "Cat"
- icon_state = "cat"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = HAIR
-
-/datum/sprite_accessory/tails_animated/human/cat
- name = "Cat"
- icon_state = "cat"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = HAIR
-
-/datum/sprite_accessory/tails/human/catbig
- name = "Cat, Big"
- icon_state = "catbig"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/catbig
- name = "Cat, Big"
- icon_state = "catbig"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/cow
- name = "Cow"
- icon_state = "cow"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/cow
- name = "Cow"
- icon_state = "cow"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/corvid
- name = "Corvid"
- icon_state = "crow"
-
-/datum/sprite_accessory/tails_animated/human/corvid
- name = "Corvid"
- icon_state = "crow"
-
-/datum/sprite_accessory/tails/human/eevee
- name = "Eevee"
- icon_state = "eevee"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/eevee
- name = "Eevee"
- icon_state = "eevee"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/fennec
- name = "Fennec"
- icon_state = "fennec"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/fennec
- name = "Fennec"
- icon_state = "fennec"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/fish
- name = "Fish"
- icon_state = "fish"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/fish
- name = "Fish"
- icon_state = "fish"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/fox
- name = "Fox"
- icon_state = "fox"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/fox
- name = "Fox"
- icon_state = "fox"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/horse
- name = "Horse"
- icon_state = "horse"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = HAIR
-
-/datum/sprite_accessory/tails_animated/human/horse
- name = "Horse"
- icon_state = "horse"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = HAIR
-
-/datum/sprite_accessory/tails/human/husky
- name = "Husky"
- icon_state = "husky"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/husky
- name = "Husky"
- icon_state = "husky"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/insect
- name = "Insect"
- icon_state = "insect"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails_animated/human/insect
- name = "insect"
- icon_state = "insect"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/tails/human/kitsune
- name = "Kitsune"
- icon_state = "kitsune"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/kitsune
- name = "Kitsune"
- icon_state = "kitsune"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/murid
- name = "Murid"
- icon_state = "murid"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/murid
- name = "Murid"
- icon_state = "murid"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/otie
- name = "Otusian"
- icon_state = "otie"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/otie
- name = "Otusian"
- icon_state = "otie"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/orca
- name = "Orca"
- icon_state = "orca"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/orca
- name = "Orca"
- icon_state = "orca"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/pede
- name = "Scolipede"
- icon_state = "pede"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/pede
- name = "Scolipede"
- icon_state = "pede"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/sergal
- name = "Sergal"
- icon_state = "sergal"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/sergal
- name = "Sergal"
- icon_state = "sergal"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/skunk
- name = "skunk"
- icon_state = "skunk"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/skunk
- name = "skunk"
- icon_state = "skunk"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/shark
- name = "Shark"
- icon_state = "shark"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/shark
- name = "Shark"
- icon_state = "shark"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/datashark
- name = "datashark"
- icon_state = "datashark"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/datashark
- name = "datashark"
- icon_state = "datashark"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/straighttail
- name = "Straight Tail"
- icon_state = "straighttail"
-
-/datum/sprite_accessory/tails_animated/human/straighttail
- name = "Straight Tail"
- icon_state = "straighttail"
-
-/datum/sprite_accessory/tails/human/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/tentacle
- name = "Tentacle"
- icon_state = "tentacle"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/tentacle
- name = "Tentacle"
- icon_state = "tentacle"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/tiger
- name = "Tiger"
- icon_state = "tiger"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/tiger
- name = "Tiger"
- icon_state = "tiger"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails/human/wolf
- name = "Wolf"
- icon_state = "wolf"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/tails_animated/human/wolf
- name = "Wolf"
- icon_state = "wolf"
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/******************************************
-*********** Mammal Body Parts *************
-*******************************************/
-
-/datum/sprite_accessory/mam_ears
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MATRIXED
-
-/datum/sprite_accessory/mam_ears/none
- name = "None"
- icon_state = "none"
-
-/datum/sprite_accessory/mam_tails
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/mam_tails/none
- name = "None"
- icon_state = "none"
-
-/datum/sprite_accessory/mam_tails_animated
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-
-/datum/sprite_accessory/mam_tails_animated/none
- name = "None"
- icon_state = "none"
- color_src = MATRIXED
-
-/datum/sprite_accessory/mam_snouts
- color_src = MATRIXED
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
-
-/datum/sprite_accessory/mam_snouts/none
- name = "None"
- icon_state = "none"
-
-
-/******************************************
-**************** Snouts *******************
-*******************************************/
-
-/datum/sprite_accessory/mam_snouts/bird
- name = "Beak"
- icon_state = "bird"
-
-/datum/sprite_accessory/mam_snouts/bigbeak
- name = "Big Beak"
- icon_state = "bigbeak"
-
-/datum/sprite_accessory/mam_snouts/bug
- name = "Bug"
- icon_state = "bug"
- color_src = MUTCOLORS
- extra2 = TRUE
- extra2_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/elephant
- name = "Elephant"
- icon_state = "elephant"
- extra = TRUE
- extra_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/lcanid
- name = "Mammal, Long"
- icon_state = "lcanid"
-
-/datum/sprite_accessory/mam_snouts/lcanidalt
- name = "Mammal, Long ALT"
- icon_state = "lcanidalt"
-
-/datum/sprite_accessory/mam_snouts/scanid
- name = "Mammal, Short"
- icon_state = "scanid"
-
-/datum/sprite_accessory/mam_snouts/scanidalt
- name = "Mammal, Short ALT"
- icon_state = "scanidalt"
-
-/datum/sprite_accessory/mam_snouts/wolf
- name = "Mammal, Thick"
- icon_state = "wolf"
-
-/datum/sprite_accessory/mam_snouts/wolfalt
- name = "Mammal, Thick ALT"
- icon_state = "wolfalt"
-
-/datum/sprite_accessory/mam_snouts/redpanda
- name = "WahCoon"
- icon_state = "wah"
-
-/datum/sprite_accessory/mam_snouts/redpandaalt
- name = "WahCoon ALT"
- icon_state = "wahalt"
-
-/datum/sprite_accessory/mam_snouts/rhino
- name = "Horn"
- icon_state = "rhino"
- extra = TRUE
- extra = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/rodent
- name = "Rodent"
- icon_state = "rodent"
-
-/datum/sprite_accessory/mam_snouts/husky
- name = "Husky"
- icon_state = "husky"
-
-/datum/sprite_accessory/mam_snouts/otie
- name = "Otie"
- icon_state = "otie"
-
-/datum/sprite_accessory/mam_snouts/pede
- name = "Scolipede"
- icon_state = "pede"
-
-/datum/sprite_accessory/mam_snouts/sergal
- name = "Sergal"
- icon_state = "sergal"
-
-/datum/sprite_accessory/mam_snouts/shark
- name = "Shark"
- icon_state = "shark"
-
-/datum/sprite_accessory/mam_snouts/toucan
- name = "Toucan"
- icon_state = "toucan"
-
-/datum/sprite_accessory/mam_snouts/sharp
- name = "Sharp"
- icon_state = "sharp"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/round
- name = "Round"
- icon_state = "round"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/sharplight
- name = "Sharp + Light"
- icon_state = "sharplight"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/roundlight
- name = "Round + Light"
- icon_state = "roundlight"
- color_src = MUTCOLORS
-
-
-/******************************************
-**************** Snouts *******************
-*************but higher up*****************/
-
-/datum/sprite_accessory/mam_snouts/fbird
- name = "Beak (Top)"
- icon_state = "fbird"
-
-/datum/sprite_accessory/mam_snouts/fbigbeak
- name = "Big Beak (Top)"
- icon_state = "fbigbeak"
-
-/datum/sprite_accessory/mam_snouts/fbug
- name = "Bug (Top)"
- icon_state = "fbug"
- color_src = MUTCOLORS
- extra2 = TRUE
- extra2_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/felephant
- name = "Elephant (Top)"
- icon_state = "felephant"
- extra = TRUE
- extra_color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/flcanid
- name = "Mammal, Long (Top)"
- icon_state = "flcanid"
-
-/datum/sprite_accessory/mam_snouts/flcanidalt
- name = "Mammal, Long ALT (Top)"
- icon_state = "flcanidalt"
-
-/datum/sprite_accessory/mam_snouts/fscanid
- name = "Mammal, Short (Top)"
- icon_state = "fscanid"
-
-/datum/sprite_accessory/mam_snouts/fscanidalt
- name = "Mammal, Short ALT (Top)"
- icon_state = "fscanidalt"
-
-/datum/sprite_accessory/mam_snouts/fwolf
- name = "Mammal, Thick (Top)"
- icon_state = "fwolf"
-
-/datum/sprite_accessory/mam_snouts/fwolfalt
- name = "Mammal, Thick ALT (Top)"
- icon_state = "fwolfalt"
-
-/datum/sprite_accessory/mam_snouts/fredpanda
- name = "WahCoon (Top)"
- icon_state = "fwah"
-
-/datum/sprite_accessory/mam_snouts/frhino
- name = "Horn (Top)"
- icon_state = "frhino"
- extra = TRUE
- extra = MUTCOLORS3
-
-/datum/sprite_accessory/mam_snouts/frodent
- name = "Rodent (Top)"
- icon_state = "frodent"
-
-/datum/sprite_accessory/mam_snouts/fhusky
- name = "Husky (Top)"
- icon_state = "fhusky"
-
-/datum/sprite_accessory/mam_snouts/fotie
- name = "Otie (Top)"
- icon_state = "fotie"
-
-/datum/sprite_accessory/mam_snouts/fpede
- name = "Scolipede (Top)"
- icon_state = "fpede"
-
-/datum/sprite_accessory/mam_snouts/fsergal
- name = "Sergal (Top)"
- icon_state = "fsergal"
-
-/datum/sprite_accessory/mam_snouts/fshark
- name = "Shark (Top)"
- icon_state = "fshark"
-
-/datum/sprite_accessory/mam_snouts/ftoucan
- name = "Toucan (Top)"
- icon_state = "ftoucan"
-
-/datum/sprite_accessory/mam_snouts/fsharp
- name = "Sharp (Top)"
- icon_state = "fsharp"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/fround
- name = "Round (Top)"
- icon_state = "fround"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/fsharplight
- name = "Sharp + Light (Top)"
- icon_state = "fsharplight"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/mam_snouts/froundlight
- name = "Round + Light (Top)"
- icon_state = "froundlight"
- color_src = MUTCOLORS
-
-/******************************************
-***************** Ears ********************
-*******************************************/
-
-/datum/sprite_accessory/mam_ears/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
-
-/datum/sprite_accessory/mam_ears/bear
- name = "Bear"
- icon_state = "bear"
-
-/datum/sprite_accessory/mam_ears/bigwolf
- name = "Big Wolf"
- icon_state = "bigwolf"
-
-/datum/sprite_accessory/mam_ears/bigwolfinner
- name = "Big Wolf (ALT)"
- icon_state = "bigwolfinner"
- hasinner = 1
-
-/datum/sprite_accessory/mam_ears/bigwolfdark
- name = "Dark Big Wolf"
- icon_state = "bigwolfdark"
-
-/datum/sprite_accessory/mam_ears/bigwolfinnerdark
- name = "Dark Big Wolf (ALT)"
- icon_state = "bigwolfinnerdark"
- hasinner = 1
-
-/datum/sprite_accessory/mam_ears/cat
- name = "Cat"
- icon_state = "cat"
- hasinner = 1
- color_src = HAIR
-
-/datum/sprite_accessory/mam_ears/catbig
- name = "Cat, Big"
- icon_state = "catbig"
-
-/datum/sprite_accessory/mam_ears/cow
- name = "Cow"
- icon_state = "cow"
-
-/datum/sprite_accessory/mam_ears/curled
- name = "Curled Horn"
- icon_state = "horn1"
- color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_ears/deer
- name = "Deer"
- icon_state = "deer"
- color_src = MUTCOLORS3
-
-/datum/sprite_accessory/mam_ears/eevee
- name = "Eevee"
- icon_state = "eevee"
-
-
-/datum/sprite_accessory/mam_ears/elf
- name = "Elf"
- icon_state = "elf"
- color_src = MUTCOLORS3
-
-
-/datum/sprite_accessory/mam_ears/elephant
- name = "Elephant"
- icon_state = "elephant"
-
-/datum/sprite_accessory/mam_ears/fennec
- name = "Fennec"
- icon_state = "fennec"
-
-/datum/sprite_accessory/mam_ears/fish
- name = "Fish"
- icon_state = "fish"
-
-/datum/sprite_accessory/mam_ears/fox
- name = "Fox"
- icon_state = "fox"
-
-/datum/sprite_accessory/mam_ears/husky
- name = "Husky"
- icon_state = "wolf"
-
-/datum/sprite_accessory/mam_ears/kangaroo
- name = "kangaroo"
- icon_state = "kangaroo"
-
-/datum/sprite_accessory/mam_ears/jellyfish
- name = "Jellyfish"
- icon_state = "jellyfish"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_ears/lab
- name = "Dog, Long"
- icon_state = "lab"
-
-/datum/sprite_accessory/mam_ears/murid
- name = "Murid"
- icon_state = "murid"
-
-/datum/sprite_accessory/mam_ears/otie
- name = "Otusian"
- icon_state = "otie"
-
-/datum/sprite_accessory/mam_ears/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
-
-/datum/sprite_accessory/mam_ears/pede
- name = "Scolipede"
- icon_state = "pede"
-
-/datum/sprite_accessory/mam_ears/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
-
-/datum/sprite_accessory/mam_ears/sergal
- name = "Sergal"
- icon_state = "sergal"
-
-/datum/sprite_accessory/mam_ears/skunk
- name = "skunk"
- icon_state = "skunk"
-
-/datum/sprite_accessory/mam_ears/wolf
- name = "Wolf"
- icon_state = "wolf"
-
-/******************************************
-*********** Tails and Things **************
-*******************************************/
-
-/datum/sprite_accessory/mam_tails/ailurus
- name = "Red Panda"
- icon_state = "wah"
- extra = TRUE
-
-/datum/sprite_accessory/mam_tails_animated/ailurus
- name = "Red Panda"
- icon_state = "wah"
- extra = TRUE
-
-/datum/sprite_accessory/mam_tails/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
-
-/datum/sprite_accessory/mam_tails_animated/axolotl
- name = "Axolotl"
- icon_state = "axolotl"
-
-/datum/sprite_accessory/mam_tails/bee
- name = "Bee"
- icon_state = "bee"
-
-/datum/sprite_accessory/mam_tails_animated/bee
- name = "Bee"
- icon_state = "bee"
-
-/datum/sprite_accessory/mam_tails/cat
- name = "Cat"
- icon_state = "cat"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails_animated/cat
- name = "Cat"
- icon_state = "cat"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails/catbig
- name = "Cat, Big"
- icon_state = "catbig"
-
-/datum/sprite_accessory/mam_tails_animated/catbig
- name = "Cat, Big"
- icon_state = "catbig"
-
-/datum/sprite_accessory/mam_tails/corvid
- name = "Corvid"
- icon_state = "crow"
-
-/datum/sprite_accessory/mam_tails_animated/corvid
- name = "Corvid"
- icon_state = "crow"
-
-/datum/sprite_accessory/mam_tail/cow
- name = "Cow"
- icon_state = "cow"
-
-/datum/sprite_accessory/mam_tails_animated/cow
- name = "Cow"
- icon_state = "cow"
-
-/datum/sprite_accessory/mam_tails/eevee
- name = "Eevee"
- icon_state = "eevee"
-
-/datum/sprite_accessory/mam_tails_animated/eevee
- name = "Eevee"
- icon_state = "eevee"
-
-/datum/sprite_accessory/mam_tails/fennec
- name = "Fennec"
- icon_state = "fennec"
-
-/datum/sprite_accessory/mam_tails_animated/fennec
- name = "Fennec"
- icon_state = "fennec"
-
-/datum/sprite_accessory/mam_tails/human/fish
- name = "Fish"
- icon_state = "fish"
-
-/datum/sprite_accessory/mam_tails_animated/human/fish
- name = "Fish"
- icon_state = "fish"
-
-/datum/sprite_accessory/mam_tails/fox
- name = "Fox"
- icon_state = "fox"
-
-/datum/sprite_accessory/mam_tails_animated/fox
- name = "Fox"
- icon_state = "fox"
-
-/datum/sprite_accessory/mam_tails/hawk
- name = "Hawk"
- icon_state = "hawk"
-
-/datum/sprite_accessory/mam_tails_animated/hawk
- name = "Hawk"
- icon_state = "hawk"
-
-/datum/sprite_accessory/mam_tails/horse
- name = "Horse"
- icon_state = "horse"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails_animated/horse
- name = "Horse"
- icon_state = "Horse"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails/husky
- name = "Husky"
- icon_state = "husky"
-
-/datum/sprite_accessory/mam_tails_animated/husky
- name = "Husky"
- icon_state = "husky"
-
-datum/sprite_accessory/mam_tails/insect
- name = "Insect"
- icon_state = "insect"
-
-/datum/sprite_accessory/mam_tails_animated/insect
- name = "Insect"
- icon_state = "insect"
-
-/datum/sprite_accessory/mam_tails/kangaroo
- name = "kangaroo"
- icon_state = "kangaroo"
-
-/datum/sprite_accessory/mam_tails_animated/kangaroo
- name = "kangaroo"
- icon_state = "kangaroo"
-
-/datum/sprite_accessory/mam_tails/kitsune
- name = "Kitsune"
- icon_state = "kitsune"
-
-/datum/sprite_accessory/mam_tails_animated/kitsune
- name = "Kitsune"
- icon_state = "kitsune"
-
-/datum/sprite_accessory/mam_tails/lab
- name = "Lab"
- icon_state = "lab"
-
-/datum/sprite_accessory/mam_tails_animated/lab
- name = "Lab"
- icon_state = "lab"
-
-/datum/sprite_accessory/mam_tails/murid
- name = "Murid"
- icon_state = "murid"
-
-/datum/sprite_accessory/mam_tails_animated/murid
- name = "Murid"
- icon_state = "murid"
-
-/datum/sprite_accessory/mam_tails/otie
- name = "Otusian"
- icon_state = "otie"
-
-/datum/sprite_accessory/mam_tails_animated/otie
- name = "Otusian"
- icon_state = "otie"
-
-/datum/sprite_accessory/mam_tails/orca
- name = "Orca"
- icon_state = "orca"
-
-/datum/sprite_accessory/mam_tails_animated/orca
- name = "Orca"
- icon_state = "orca"
-
-/datum/sprite_accessory/mam_tails/pede
- name = "Scolipede"
- icon_state = "pede"
-
-/datum/sprite_accessory/mam_tails_animated/pede
- name = "Scolipede"
- icon_state = "pede"
-
-/datum/sprite_accessory/mam_tails/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
-
-/datum/sprite_accessory/mam_tails_animated/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
-
-/datum/sprite_accessory/mam_tails/sergal
- name = "Sergal"
- icon_state = "sergal"
-
-/datum/sprite_accessory/mam_tails_animated/sergal
- name = "Sergal"
- icon_state = "sergal"
-
-/datum/sprite_accessory/mam_tails/skunk
- name = "Skunk"
- icon_state = "skunk"
-
-/datum/sprite_accessory/mam_tails_animated/skunk
- name = "Skunk"
- icon_state = "skunk"
-
-/datum/sprite_accessory/mam_tails/shark
- name = "Shark"
- icon_state = "shark"
-
-/datum/sprite_accessory/mam_tails_animated/shark
- name = "Shark"
- icon_state = "shark"
-
-/datum/sprite_accessory/mam_tails/shepherd
- name = "Shepherd"
- icon_state = "shepherd"
-
-/datum/sprite_accessory/mam_tails_animated/shepherd
- name = "Shepherd"
- icon_state = "shepherd"
-
-/datum/sprite_accessory/mam_tails/straighttail
- name = "Straight Tail"
- icon_state = "straighttail"
-
-/datum/sprite_accessory/mam_tails_animated/straighttail
- name = "Straight Tail"
- icon_state = "straighttail"
-
-/datum/sprite_accessory/mam_tails/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
-
-/datum/sprite_accessory/mam_tails_animated/squirrel
- name = "Squirrel"
- icon_state = "squirrel"
-
-/datum/sprite_accessory/mam_tails/tentacle
- name = "Tentacle"
- icon_state = "tentacle"
-
-/datum/sprite_accessory/mam_tails_animated/tentacle
- name = "Tentacle"
- icon_state = "tentacle"
-
-/datum/sprite_accessory/mam_tails/tiger
- name = "Tiger"
- icon_state = "tiger"
-
-/datum/sprite_accessory/mam_tails_animated/tiger
- name = "Tiger"
- icon_state = "tiger"
-
-/datum/sprite_accessory/mam_tails/wolf
- name = "Wolf"
- icon_state = "wolf"
-
-/datum/sprite_accessory/mam_tails_animated/wolf
- name = "Wolf"
- icon_state = "wolf"
-
-/******************************************
-************ Body Markings ****************
-*******************************************/
-
-/datum/sprite_accessory/mam_body_markings
- extra = FALSE
- extra2 = FALSE
- color_src = MATRIXED
- gender_specific = 0
- icon = 'modular_citadel/icons/mob/mam_markings.dmi'
-
-/datum/sprite_accessory/mam_body_markings/none
- name = "None"
- icon_state = "none"
- ckeys_allowed = list("yousshouldnteverbeseeingthisyoumeme")
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/plain
- name = "Plain"
- icon_state = "plain"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/redpanda
- name = "Redpanda"
- icon_state = "redpanda"
-
-/datum/sprite_accessory/mam_body_markings/bee
- name = "Bee"
- icon_state = "bee"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/belly
- name = "Belly"
- icon_state = "belly"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/bellyslim
- name = "Bellyslim"
- icon_state = "bellyslim"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/corgi
- name = "Corgi"
- icon_state = "corgi"
-
-/datum/sprite_accessory/mam_body_markings/cow
- name = "Bovine"
- icon_state = "bovine"
-
-/datum/sprite_accessory/mam_body_markings/corvid
- name = "Corvid"
- icon_state = "corvid"
-
-/datum/sprite_accessory/mam_body_markings/dalmation
- name = "Dalmation"
- icon_state = "dalmation"
-
-/datum/sprite_accessory/mam_body_markings/deer
- name = "Deer"
- icon_state = "deer"
-
-/datum/sprite_accessory/mam_body_markings/dog
- name = "Dog"
- icon_state = "dog"
-
-/datum/sprite_accessory/mam_body_markings/eevee
- name = "Eevee"
- icon_state = "eevee"
-
-/datum/sprite_accessory/mam_body_markings/hippo
- name = "Hippo"
- icon_state = "hippo"
-
-/datum/sprite_accessory/mam_body_markings/fennec
- name = "Fennec"
- icon_state = "Fennec"
-
-/datum/sprite_accessory/mam_body_markings/fox
- name = "Fox"
- icon_state = "fox"
-
-/datum/sprite_accessory/mam_body_markings/frog
- name = "Frog"
- icon_state = "frog"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/goat
- name = "Goat"
- icon_state = "goat"
-
-/datum/sprite_accessory/mam_body_markings/handsfeet
- name = "Handsfeet"
- icon_state = "handsfeet"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/hawk
- name = "Hawk"
- icon_state = "hawk"
-
-/datum/sprite_accessory/mam_body_markings/husky
- name = "Husky"
- icon_state = "husky"
-
-/datum/sprite_accessory/mam_body_markings/hyena
- name = "Hyena"
- icon_state = "hyena"
-
-/datum/sprite_accessory/mam_body_markings/lab
- name = "Lab"
- icon_state = "lab"
-
-/datum/sprite_accessory/mam_body_markings/moth
- name = "Moth"
- icon_state = "moth"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/otie
- name = "Otie"
- icon_state = "otie"
-
-/datum/sprite_accessory/mam_body_markings/otter
- name = "Otter"
- icon_state = "otter"
-
-/datum/sprite_accessory/mam_body_markings/orca
- name = "Orca"
- icon_state = "orca"
-
-/datum/sprite_accessory/mam_body_markings/panther
- name = "Panther"
- icon_state = "panther"
-
-/datum/sprite_accessory/mam_body_markings/possum
- name = "Possum"
- icon_state = "possum"
-
-/datum/sprite_accessory/mam_body_markings/raccoon
- name = "Raccoon"
- icon_state = "raccoon"
-
-/datum/sprite_accessory/mam_body_markings/pede
- name = "Scolipede"
- icon_state = "scolipede"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/shark
- name = "Shark"
- icon_state = "shark"
-
-/datum/sprite_accessory/mam_body_markings/skunk
- name = "Skunk"
- icon_state = "skunk"
-
-/datum/sprite_accessory/mam_body_markings/sergal
- name = "Sergal"
- icon_state = "sergal"
-
-/datum/sprite_accessory/mam_body_markings/shepherd
- name = "Shepherd"
- icon_state = "shepherd"
-
-/datum/sprite_accessory/mam_body_markings/tajaran
- name = "Tajaran"
- icon_state = "tajaran"
-
-/datum/sprite_accessory/mam_body_markings/tiger
- name = "Tiger"
- icon_state = "tiger"
-
-/datum/sprite_accessory/mam_body_markings/turian
- name = "Turian"
- icon_state = "turian"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-/datum/sprite_accessory/mam_body_markings/wolf
- name = "Wolf"
- icon_state = "wolf"
-
-/datum/sprite_accessory/mam_body_markings/xeno
- name = "Xeno"
- icon_state = "xeno"
- icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
-
-
-/******************************************
-************ Taur Bodies ******************
-*******************************************/
-/datum/sprite_accessory/taur
- icon = 'modular_citadel/icons/mob/mam_taur.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
- extra = TRUE
- extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
- extra2 = TRUE
- center = TRUE
- dimension_x = 64
- var/taur_mode = NOT_TAURIC
- color_src = MATRIXED
-
-/datum/sprite_accessory/taur/none
- name = "None"
- icon_state = "None"
-
-/datum/sprite_accessory/taur/cow
- name = "Cow"
- icon_state = "cow"
- taur_mode = HOOF_TAURIC
-
-/datum/sprite_accessory/taur/deer
- name = "Deer"
- icon_state = "deer"
- taur_mode = HOOF_TAURIC
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/taur/drake
- name = "Drake"
- icon_state = "drake"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/drider
- name = "Drider"
- icon_state = "drider"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/taur/eevee
- name = "Eevee"
- icon_state = "eevee"
- taur_mode = PAW_TAURIC
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/taur/fox
- name = "Fox"
- icon_state = "fox"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/husky
- name = "Husky"
- icon_state = "husky"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/horse
- name = "Horse"
- icon_state = "horse"
- taur_mode = HOOF_TAURIC
-
-/datum/sprite_accessory/taur/lab
- name = "Lab"
- icon_state = "lab"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/naga
- name = "Naga"
- icon_state = "naga"
- taur_mode = SNEK_TAURIC
-
-/datum/sprite_accessory/taur/otie
- name = "Otie"
- icon_state = "otie"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/pede
- name = "Scolipede"
- icon_state = "pede"
- taur_mode = PAW_TAURIC
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/taur/panther
- name = "Panther"
- icon_state = "panther"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/shepherd
- name = "Shepherd"
- icon_state = "shepherd"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/tentacle
- name = "Tentacle"
- icon_state = "tentacle"
- taur_mode = SNEK_TAURIC
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/taur/tiger
- name = "Tiger"
- icon_state = "tiger"
- taur_mode = PAW_TAURIC
-
-/datum/sprite_accessory/taur/wolf
- name = "Wolf"
- icon_state = "wolf"
- taur_mode = PAW_TAURIC
-
-/******************************************
-*************** Ayyliums ******************
-*******************************************/
-
-//Xeno Dorsal Tubes
-/datum/sprite_accessory/xeno_dorsal
- icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
-
-/datum/sprite_accessory/xeno_dorsal/standard
- name = "Standard"
- icon_state = "standard"
-
-/datum/sprite_accessory/xeno_dorsal/royal
- name = "Royal"
- icon_state = "royal"
-
-/datum/sprite_accessory/xeno_dorsal/down
- name = "Dorsal Down"
- icon_state = "down"
-
-//Xeno Tail
-/datum/sprite_accessory/xeno_tail
- icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
-
-/datum/sprite_accessory/xeno_tail/none
- name = "None"
-
-/datum/sprite_accessory/xeno_tail/standard
- name = "Xenomorph Tail"
- icon_state = "xeno"
-
-//Xeno Caste Heads
-/datum/sprite_accessory/xeno_head
- icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
-
-/datum/sprite_accessory/xeno_head/standard
- name = "Standard"
- icon_state = "standard"
-
-/datum/sprite_accessory/xeno_head/royal
- name = "royal"
- icon_state = "royal"
-
-/datum/sprite_accessory/xeno_head/hollywood
- name = "hollywood"
- icon_state = "hollywood"
-
-/datum/sprite_accessory/xeno_head/warrior
- name = "warrior"
- icon_state = "warrior"
-
-// IPCs
-/datum/sprite_accessory/screen
- icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
- color_src = null
-
-/datum/sprite_accessory/screen/blank
- name = "Blank"
- icon_state = "blank"
-
-/datum/sprite_accessory/screen/pink
- name = "Pink"
- icon_state = "pink"
-
-/datum/sprite_accessory/screen/green
- name = "Green"
- icon_state = "green"
-
-/datum/sprite_accessory/screen/red
- name = "Red"
- icon_state = "red"
-
-/datum/sprite_accessory/screen/blue
- name = "Blue"
- icon_state = "blue"
-
-/datum/sprite_accessory/screen/yellow
- name = "Yellow"
- icon_state = "yellow"
-
-/datum/sprite_accessory/screen/shower
- name = "Shower"
- icon_state = "shower"
-
-/datum/sprite_accessory/screen/nature
- name = "Nature"
- icon_state = "nature"
-
-/datum/sprite_accessory/screen/eight
- name = "Eight"
- icon_state = "eight"
-
-/datum/sprite_accessory/screen/goggles
- name = "Goggles"
- icon_state = "goggles"
-
-/datum/sprite_accessory/screen/heart
- name = "Heart"
- icon_state = "heart"
-
-/datum/sprite_accessory/screen/monoeye
- name = "Mono eye"
- icon_state = "monoeye"
-
-/datum/sprite_accessory/screen/breakout
- name = "Breakout"
- icon_state = "breakout"
-
-/datum/sprite_accessory/screen/purple
- name = "Purple"
- icon_state = "purple"
-
-/datum/sprite_accessory/screen/scroll
- name = "Scroll"
- icon_state = "scroll"
-
-/datum/sprite_accessory/screen/console
- name = "Console"
- icon_state = "console"
-
-/datum/sprite_accessory/screen/rgb
- name = "RGB"
- icon_state = "rgb"
-
-/datum/sprite_accessory/screen/golglider
- name = "Gol Glider"
- icon_state = "golglider"
-
-/datum/sprite_accessory/screen/rainbow
- name = "Rainbow"
- icon_state = "rainbow"
-
-/datum/sprite_accessory/screen/sunburst
- name = "Sunburst"
- icon_state = "sunburst"
-
-/datum/sprite_accessory/screen/static
- name = "Static"
- icon_state = "static"
-
-//Oracle Station sprites
-
-/datum/sprite_accessory/screen/bsod
- name = "BSOD"
- icon_state = "bsod"
-
-/datum/sprite_accessory/screen/redtext
- name = "Red Text"
- icon_state = "retext"
-
-/datum/sprite_accessory/screen/sinewave
- name = "Sine wave"
- icon_state = "sinewave"
-
-/datum/sprite_accessory/screen/squarewave
- name = "Square wave"
- icon_state = "squarwave"
-
-/datum/sprite_accessory/screen/ecgwave
- name = "ECG wave"
- icon_state = "ecgwave"
-
-/datum/sprite_accessory/screen/eyes
- name = "Eyes"
- icon_state = "eyes"
-
-/datum/sprite_accessory/screen/textdrop
- name = "Text drop"
- icon_state = "textdrop"
-
-/datum/sprite_accessory/screen/stars
- name = "Stars"
- icon_state = "stars"
-
-// IPC Antennas
-
-/datum/sprite_accessory/antenna
- icon = 'modular_citadel/icons/mob/ipc_antennas.dmi'
- color_src = MUTCOLORS2
-
-/datum/sprite_accessory/antenna/none
- name = "None"
- icon_state = "None"
-
-/datum/sprite_accessory/antenna/antennae
- name = "Angled Antennae"
- icon_state = "antennae"
-
-/datum/sprite_accessory/antenna/tvantennae
- name = "TV Antennae"
- icon_state = "tvantennae"
-
-/datum/sprite_accessory/antenna/cyberhead
- name = "Cyberhead"
- icon_state = "cyberhead"
-
-/datum/sprite_accessory/antenna/antlers
- name = "Antlers"
- icon_state = "antlers"
-
-/datum/sprite_accessory/antenna/crowned
- name = "Crowned"
- icon_state = "crowned"
-
-// *** Snooooow flaaaaake ***
-
-/datum/sprite_accessory/horns/guilmon
- name = "Guilmon"
- icon_state = "guilmon"
- icon = 'modular_citadel/icons/mob/mam_ears.dmi'
-
-/datum/sprite_accessory/snout/guilmon
- name = "Guilmon"
- icon_state = "guilmon"
- color_src = MATRIXED
-
-/datum/sprite_accessory/mam_tails/shark/datashark
- name = "DataShark"
- icon_state = "datashark"
- ckeys_allowed = list("rubyflamewing")
-
-/datum/sprite_accessory/mam_tails_animated/shark/datashark
- name = "DataShark"
- icon_state = "datashark"
-
-/datum/sprite_accessory/mam_body_markings/shark/datashark
- name = "DataShark"
- icon_state = "datashark"
- ckeys_allowed = list("rubyflamewing")
-
-//Sabresune
-/datum/sprite_accessory/mam_ears/sabresune
- name = "sabresune"
- icon_state = "sabresune"
- ckeys_allowed = list("poojawa")
- extra = TRUE
-
-/datum/sprite_accessory/mam_tails/sabresune
- name = "sabresune"
- icon_state = "sabresune"
- ckeys_allowed = list("poojawa")
-
-
-/datum/sprite_accessory/mam_tails_animated/sabresune
- name = "sabresune"
- icon_state = "sabresune"
-
-/datum/sprite_accessory/mam_body_markings/sabresune
- name = "Sabresune"
- icon_state = "sabresune"
- ckeys_allowed = list("poojawa")
-
-
-//Lunasune
-/datum/sprite_accessory/mam_ears/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- ckeys_allowed = list("invader4352")
-
-/datum/sprite_accessory/mam_tails/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- ckeys_allowed = list("invader4352")
-
-/datum/sprite_accessory/mam_tails_animated/lunasune
- name = "lunasune"
- icon_state = "lunasune"
-
-/*************** VIRGO PORTED HAIRS ****************************/
-#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = #_name + " (Virgo)"
-//VIRGO PORTED HAIRS
-VHAIR("Short Hair Rosa", hair_rosa_s)
-VHAIR("Short Hair 80s", hair_80s_s)
-VHAIR("Long Bedhead", hair_long_bedhead_s)
-VHAIR("Dave", hair_dave_s)
-VHAIR("Country", hair_country_s)
-VHAIR("Shy", hair_shy_s)
-VHAIR("Unshaven Mohawk", hair_unshaven_mohawk_s)
-VHAIR("Manbun", hair_manbun_s)
-VHAIR("Longer Bedhead", hair_longer_bedhead_s)
-VHAIR("Ponytail", hair_ponytail_s)
-VHAIR("Ziegler", hair_ziegler_s)
-VHAIR("Emo Fringe", hair_emofringe_s)
-VHAIR("Very Short Over Eye Alt", hair_veryshortovereyealternate_s)
-VHAIR("Shorthime", hair_shorthime_s)
-VHAIR("High Tight", hair_hightight_s)
-VHAIR("Thinning Front", hair_thinningfront_s)
-VHAIR("Big Afro", hair_bigafro_s)
-VHAIR("Afro", hair_afro_s)
-VHAIR("High Braid", hair_hbraid_s)
-VHAIR("Braid", hair_braid_s)
-VHAIR("Sargeant", hair_sargeant_s)
-VHAIR("Gelled", hair_gelled_s)
-VHAIR("Kagami", hair_kagami_s)
-VHAIR("ShortTail", hair_stail_s)
-VHAIR("Gentle", hair_gentle_s)
-VHAIR("Grande", hair_grande_s)
-VHAIR("Bobcurl", hair_bobcurl_s)
-VHAIR("Pompadeur", hair_pompadour_s)
-VHAIR("Plait", hair_plait_s)
-VHAIR("Long", hair_long_s)
-VHAIR("Rattail", hair_rattail_s)
-VHAIR("Tajspiky", hair_tajspiky_s)
-VHAIR("Messy", hair_messy_s)
-VHAIR("Bangs", hair_bangs_s)
-VHAIR("TBraid", hair_tbraid_s)
-VHAIR("Toriyama2", hair_toriyama2_s)
-VHAIR("CIA", hair_cia_s)
-VHAIR("Mulder", hair_mulder_s)
-VHAIR("Scully", hair_scully_s)
-VHAIR("Nitori", hair_nitori_s)
-VHAIR("Joestar", hair_joestar_s)
-VHAIR("Ponytail4", hair_ponytail4_s)
-VHAIR("Ponytail5", hair_ponytail5_s)
-VHAIR("Beehive2", hair_beehive2_s)
-VHAIR("Short Braid", hair_shortbraid_s)
-VHAIR("Reverse Mohawk", hair_reversemohawk_s)
-VHAIR("SHort Bangs", hair_shortbangs_s)
-VHAIR("Half Shaved", hair_halfshaved_s)
-VHAIR("Longer Alt 2", hair_longeralt2_s)
-VHAIR("Bun", hair_bun_s)
-VHAIR("Curly", hair_curly_s)
-VHAIR("Victory", hair_victory_s)
-VHAIR("Ponytail6", hair_ponytail6_s)
-VHAIR("Undercut3", hair_undercut3_s)
-VHAIR("Bobcut Alt", hair_bobcultalt_s)
-VHAIR("Fingerwave", hair_fingerwave_s)
-VHAIR("Oxton", hair_oxton_s)
-VHAIR("Poofy2", hair_poofy2_s)
-VHAIR("Fringe Tail", hair_fringetail_s)
-VHAIR("Bun3", hair_bun3_s)
-VHAIR("Wisp", hair_wisp_s)
-VHAIR("Undercut2", hair_undercut2_s)
-VHAIR("TBob", hair_tbob_s)
-VHAIR("Spiky Ponytail", hair_spikyponytail_s)
-VHAIR("Rowbun", hair_rowbun_s)
-VHAIR("Rowdualtail", hair_rowdualtail_s)
-VHAIR("Rowbraid", hair_rowbraid_s)
-VHAIR("Shaved Mohawk", hair_shavedmohawk_s)
-VHAIR("Topknot", hair_topknot_s)
-VHAIR("Ronin", hair_ronin_s)
-VHAIR("Bowlcut2", hair_bowlcut2_s)
-VHAIR("Thinning Rear", hair_thinningrear_s)
-VHAIR("Thinning", hair_thinning_s)
-VHAIR("Jade", hair_jade_s)
-VHAIR("Bedhead", hair_bedhead_s)
-VHAIR("Dreadlocks", hair_dreads_s)
-VHAIR("Very Long", hair_vlong_s)
-VHAIR("Jensen", hair_jensen_s)
-VHAIR("Halfbang", hair_halfbang_s)
-VHAIR("Kusangi", hair_kusangi_s)
-VHAIR("Ponytail", hair_ponytail_s)
-VHAIR("Ponytail3", hair_ponytail3_s)
-VHAIR("Halfbang Alt", hair_halfbang_alt_s)
-VHAIR("Bedhead V2", hair_bedheadv2_s)
-VHAIR("Long Fringe", hair_longfringe_s)
-VHAIR("Flair", hair_flair_s)
-VHAIR("Bedhead V3", hair_bedheadv3_s)
-VHAIR("Himecut", hair_himecut_s)
-VHAIR("Curls", hair_curls_s)
-VHAIR("Very Long Fringe", hair_vlongfringe_s)
-VHAIR("Longest", hair_longest_s)
-VHAIR("Father", hair_father_s)
-VHAIR("Emo Long", hair_emolong_s)
-VHAIR("Short Hair 3", hair_shorthair3_s)
-VHAIR("Double Bun", hair_doublebun_s)
-VHAIR("Sleeze", hair_sleeze_s)
-VHAIR("Twintail", hair_twintail_s)
-VHAIR("Emo 2", hair_emo2_s)
-VHAIR("Low Fade", hair_lowfade_s)
-VHAIR("Med Fade", hair_medfade_s)
-VHAIR("High Fade", hair_highfade_s)
-VHAIR("Bald Fade", hair_baldfade_s)
-VHAIR("No Fade", hair_nofade_s)
-VHAIR("Trim Flat", hair_trimflat_s)
-VHAIR("Shaved", hair_shaved_s)
-VHAIR("Trimmed", hair_trimmed_s)
-VHAIR("Tight Bun", hair_tightbun_s)
-VHAIR("Short Hair 4", hair_d_s)
-VHAIR("Short Hair 5", hair_e_s)
-VHAIR("Short Hair 6", hair_f_s)
-VHAIR("Skinhead", hair_skinhead_s)
-VHAIR("Afro2", hair_afro2_s)
-VHAIR("Bobcut", hair_bobcut_s)
-VHAIR("Emo", hair_emo_s)
-VHAIR("Long Over Eye", hair_longovereye_s)
-VHAIR("Feather", hair_feather_s)
-VHAIR("Hitop", hair_hitop_s)
-VHAIR("Short Over Eye", hair_shortoverye_s)
-VHAIR("Straight", hair_straight_s)
-VHAIR("Buzzcut", hair_buzzcut_s)
-VHAIR("Combover", hair_combover_s)
-VHAIR("Crewcut", hair_crewcut_s)
-VHAIR("Devillock", hair_devilock_s)
-VHAIR("Clean", hair_clean_s)
-VHAIR("Shaggy", hair_shaggy_s)
-VHAIR("Updo", hair_updo_s)
-VHAIR("Mohawk", hair_mohawk_s)
-VHAIR("Odango", hair_odango_s)
-VHAIR("Ombre", hair_ombre_s)
-VHAIR("Parted", hair_parted_s)
-VHAIR("Quiff", hair_quiff_s)
-VHAIR("Volaju", hair_volaju_s)
-VHAIR("Bun2", hair_bun2_s)
-VHAIR("Rows1", hair_rows1_s)
-VHAIR("Rows2", hair_rows2_s)
-VHAIR("Dandy Pompadour", hair_dandypompadour_s)
-VHAIR("Poofy", hair_poofy_s)
-VHAIR("Toriyama", hair_toriyama_s)
-VHAIR("Drillruru", hair_drillruru_s)
-VHAIR("Bowlcut", hair_bowlcut_s)
-VHAIR("Coffee House", hair_coffeehouse_s)
-VHAIR("Family Man", hair_thefamilyman_s)
-VHAIR("Shaved Part", hair_shavedpart_s)
-VHAIR("Modern", hair_modern_s)
-VHAIR("One Shoulder", hair_oneshoulder_s)
-VHAIR("Very Short Over Eye", hair_veryshortovereye_s)
-VHAIR("Unkept", hair_unkept_s)
-VHAIR("Wife", hair_wife_s)
-VHAIR("Nia", hair_nia_s)
-VHAIR("Undercut", hair_undercut_s)
-VHAIR("Bobcut Alt", hair_bobcutalt_s)
-VHAIR("Short Hair 4 alt", hair_shorthair4_s)
-VHAIR("Tressshoulder", hair_tressshoulder_s)
- //END
-#undef VHAIR
-
-#define VFACE(_name, new_state) /datum/sprite_accessory/facial_hair/##new_state/icon_state=#new_state;;/datum/sprite_accessory/facial_hair/##new_state/name= #_name + " (Virgo)"
-VFACE("Watson", facial_watson_s)
-VFACE("Chaplin", facial_chaplin_s)
-VFACE("Fullbeard", facial_fullbeard_s)
-VFACE("Vandyke", facial_vandyke_s)
-VFACE("Elvis", facial_elvis_s)
-VFACE("Abe", facial_abe_s)
-VFACE("Chin", facial_chin_s)
-VFACE("GT", facial_gt_s)
-VFACE("Hip", facial_hip_s)
-VFACE("Hogan", facial_hogan_s)
-VFACE("Selleck", facial_selleck_s)
-VFACE("Neckbeard", facial_neckbeard_s)
-VFACE("Longbeard", facial_longbeard_s)
-VFACE("Dwarf", facial_dwarf_s)
-VFACE("Sideburn", facial_sideburn_s)
-VFACE("Mutton", facial_mutton_s)
-VFACE("Moustache", facial_moustache_s)
-VFACE("Pencilstache", facial_pencilstache_s)
-VFACE("Goatee", facial_goatee_s)
-VFACE("Smallstache", facial_smallstache_s)
-VFACE("Volaju", facial_volaju_s)
-VFACE("3 O\'clock", facial_3oclock_s)
-VFACE("5 O\'clock", facial_5oclock_s)
-VFACE("7 O\'clock", facial_7oclock_s)
-VFACE("5 O\'clock Moustache", facial_5oclockmoustache_s)
-VFACE("7 O\'clock", facial_7oclockmoustache_s)
-VFACE("Walrus", facial_walrus_s)
-VFACE("Muttonmus", facial_muttonmus_s)
-VFACE("Wise", facial_wise_s)
-VFACE("Martial Artist", facial_martialartist_s)
-VFACE("Dorsalfnil", facial_dorsalfnil_s)
-VFACE("Hornadorns", facial_hornadorns_s)
-VFACE("Spike", facial_spike_s)
-VFACE("Chinhorns", facial_chinhorns_s)
-VFACE("Cropped Fullbeard", facial_croppedfullbeard_s)
-VFACE("Chinless Beard", facial_chinlessbeard_s)
-VFACE("Moonshiner", facial_moonshiner_s)
-VFACE("Tribearder", facial_tribearder_s)
-#undef VFACE
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/life.dm b/modular_citadel/code/modules/mob/living/carbon/human/life.dm
deleted file mode 100644
index e728d70c97..0000000000
--- a/modular_citadel/code/modules/mob/living/carbon/human/life.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-/mob/living/carbon/human/Life()
- //citadel code
- if(stat != DEAD)
- handle_arousal()
- . = ..()
-
-/mob/living/carbon/human/calculate_affecting_pressure(pressure)
- if(ismob(loc))
- return ONE_ATMOSPHERE
- if(istype(loc, /obj/item/dogborg/sleeper))
- return ONE_ATMOSPHERE
- . = ..()
-
-/mob/living/carbon/human/update_health_hud(shown_health_amount)
- . = ..()
- if(!client || !hud_used)
- return
- if(hud_used.staminas)
- hud_used.staminas.icon_state = staminahudamount()
- if(hud_used.staminabuffer)
- hud_used.staminabuffer.icon_state = staminabufferhudamount()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
deleted file mode 100644
index 1c7456a8d8..0000000000
--- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm
+++ /dev/null
@@ -1,166 +0,0 @@
-/datum/species
- var/should_draw_citadel = FALSE
-
-/datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
- if(!istype(M))
- return TRUE
- CHECK_DNA_AND_SPECIES(M)
- CHECK_DNA_AND_SPECIES(H)
-
- if(!istype(M)) //sanity check for drones.
- return TRUE
- if(M.mind)
- attacker_style = M.mind.martial_art
- if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
- log_combat(M, H, "attempted to touch")
- H.visible_message("[M] attempted to touch [H]! ")
- return TRUE
- switch(M.a_intent)
- if(INTENT_HELP)
- if(M == H)
- althelp(M, H, attacker_style)
- return TRUE
- return FALSE
- if(INTENT_DISARM)
- altdisarm(M, H, attacker_style)
- return TRUE
- return FALSE
-
-/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
- if(user == target && istype(user))
- if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
- to_chat(user, "You're too exhausted for that. ")
- return
- if(!user.resting)
- to_chat(user, "You can only force yourself up if you're on the ground. ")
- return
- user.visible_message("[user] forces [p_them()]self up to [p_their()] feet! ", "You force yourself up to your feet! ")
- user.resting = 0
- user.update_canmove()
- user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting
- playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
-/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
- if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
- to_chat(user, "You're too exhausted. ")
- return FALSE
- if(target.check_block())
- target.visible_message("[target] blocks [user]'s shoving attempt! ")
- return FALSE
- if(attacker_style && attacker_style.disarm_act(user,target))
- return TRUE
- if(user.resting)
- return FALSE
- else
- if(user == target)
- return
- user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
- user.adjustStaminaLossBuffered(4)
- playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
-
- if(target.w_uniform)
- target.w_uniform.add_fingerprint(user)
- SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
-
- if(!target.resting)
- target.adjustStaminaLoss(5)
-
-
- var/turf/target_oldturf = target.loc
- var/shove_dir = get_dir(user.loc, target_oldturf)
- var/turf/target_shove_turf = get_step(target.loc, shove_dir)
- var/mob/living/carbon/human/target_collateral_human
- var/obj/structure/table/target_table
- var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
-
- //Thank you based whoneedsspace
- target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
- if(target_collateral_human)
- shove_blocked = TRUE
- else
- target.Move(target_shove_turf, shove_dir)
- if(get_turf(target) == target_oldturf)
- if(target_shove_turf.density)
- shove_blocked = TRUE
- else
- var/thoushallnotpass = FALSE
- for(var/obj/O in target_shove_turf)
- if(istype(O, /obj/structure/table))
- target_table = O
- else if(!O.CanPass(src, target_shove_turf))
- shove_blocked = TRUE
- thoushallnotpass = TRUE
- if(thoushallnotpass)
- target_table = null
-
- if(target.is_shove_knockdown_blocked())
- return
-
- if(shove_blocked || target_table)
- var/directional_blocked = FALSE
- if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
- var/target_turf = get_turf(target)
- for(var/obj/O in target_turf)
- if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
- directional_blocked = TRUE
- break
- if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
- for(var/obj/O in target_shove_turf)
- if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
- directional_blocked = TRUE
- break
- var/targetatrest = target.resting
- if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest)
- target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
- user.visible_message("[user.name] shoves [target.name], knocking them down! ",
- "You shove [target.name], knocking them down! ", null, COMBAT_MESSAGE_RANGE)
- log_combat(user, target, "shoved", "knocking them down")
- else if(target_table)
- if(!targetatrest)
- target.Knockdown(SHOVE_KNOCKDOWN_TABLE)
- user.visible_message("[user.name] shoves [target.name] onto \the [target_table]! ",
- "You shove [target.name] onto \the [target_table]! ", null, COMBAT_MESSAGE_RANGE)
- target.forceMove(target_shove_turf)
- log_combat(user, target, "shoved", "onto [target_table]")
- else if(target_collateral_human && !targetatrest)
- target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
- if(!target_collateral_human.resting)
- target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
- user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]! ",
- "You shove [target.name] into [target_collateral_human.name]! ", null, COMBAT_MESSAGE_RANGE)
- log_combat(user, target, "shoved", "into [target_collateral_human.name]")
-
- else
- user.visible_message("[user.name] shoves [target.name]! ",
- "You shove [target.name]! ", null, COMBAT_MESSAGE_RANGE)
- var/target_held_item = target.get_active_held_item()
- var/knocked_item = FALSE
- if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
- target_held_item = null
- if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID))
- target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
- if(target_held_item)
- target.visible_message("[target.name]'s grip on \the [target_held_item] loosens! ",
- "Your grip on \the [target_held_item] loosens! ", null, COMBAT_MESSAGE_RANGE)
- addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
- else if(target_held_item)
- target.dropItemToGround(target_held_item)
- knocked_item = TRUE
- target.visible_message("[target.name] drops \the [target_held_item]!! ",
- "You drop \the [target_held_item]!! ", null, COMBAT_MESSAGE_RANGE)
- var/append_message = ""
- if(target_held_item)
- if(knocked_item)
- append_message = "causing them to drop [target_held_item]"
- else
- append_message = "loosening their grip on [target_held_item]"
- log_combat(user, target, "shoved", append_message)
-
-
-////////////////////
-/////BODYPARTS/////
-////////////////////
-
-
-/obj/item/bodypart
- var/should_draw_citadel = FALSE
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
deleted file mode 100644
index 71cf02f572..0000000000
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ /dev/null
@@ -1,236 +0,0 @@
-/datum/species/mammal
- name = "Mammal"
- id = "mammal"
- default_color = "4B4B4B"
- should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "legs")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
- attack_verb = "claw"
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal
- liked_food = MEAT | FRIED
- disliked_food = TOXIC
-
-//Curiosity killed the cat's wagging tail.
-/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/mammal/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/mammal/can_wag_tail(mob/living/carbon/human/H)
- return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H)
- return ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H)
- if("mam_tail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_tail"
- mutant_bodyparts |= "mam_waggingtail"
- H.update_body()
-
-/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H)
- if("mam_waggingtail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_waggingtail"
- mutant_bodyparts |= "mam_tail"
- H.update_body()
-
-/datum/species/mammal/qualifies_for_rank(rank, list/features)
- return TRUE
-
-
-//AVIAN//
-/datum/species/avian
- name = "Avian"
- id = "avian"
- say_mod = "chirps"
- default_color = "BCAC9B"
- should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_snouts", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Beak", "mam_body_markings" = "Hawk", "wings" = "None", "taur" = "None", "mam_tail" = "Hawk")
- attack_verb = "peck"
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- liked_food = MEAT | FRUIT
- disliked_food = TOXIC
-
-/datum/species/avian/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/avian/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/avian/can_wag_tail(mob/living/carbon/human/H)
- return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/avian/is_wagging_tail(mob/living/carbon/human/H)
- return ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/avian/start_wagging_tail(mob/living/carbon/human/H)
- if("mam_tail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_tail"
- mutant_bodyparts |= "mam_waggingtail"
- H.update_body()
-
-/datum/species/avian/stop_wagging_tail(mob/living/carbon/human/H)
- if("mam_waggingtail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_waggingtail"
- mutant_bodyparts |= "mam_tail"
- H.update_body()
-
-/datum/species/avian/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//AQUATIC//
-/datum/species/aquatic
- name = "Aquatic"
- id = "aquatic"
- default_color = "BCAC9B"
- should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_ears","mam_body_markings", "taur", "legs", "mam_snouts")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_ears" = "None", "mam_body_markings" = "Shark", "mam_snouts" = "Round", "taur" = "None", "legs" = "Normal Legs")
- attack_verb = "bite"
- attack_sound = 'sound/weapons/bite.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- liked_food = MEAT
- disliked_food = TOXIC
- meat = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic
-
-/datum/species/aquatic/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/aquatic/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/aquatic/can_wag_tail(mob/living/carbon/human/H)
- return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/aquatic/is_wagging_tail(mob/living/carbon/human/H)
- return ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/aquatic/start_wagging_tail(mob/living/carbon/human/H)
- if("mam_tail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_tail"
- mutant_bodyparts |= "mam_waggingtail"
- H.update_body()
-
-/datum/species/aquatic/stop_wagging_tail(mob/living/carbon/human/H)
- if("mam_waggingtail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_waggingtail"
- mutant_bodyparts |= "mam_tail"
- H.update_body()
-
-/datum/species/aquatic/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//INSECT//
-/datum/species/insect
- name = "Insect"
- id = "insect"
- default_color = "BCAC9B"
- should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
- mutant_bodyparts = list("mam_ears", "mam_body_markings", "mam_tail", "taur", "moth_wings", "mam_snouts")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "mam_snouts" = "Bug", "mam_body_markings" = "Moth", "taur" = "None")
- attack_verb = "flutter" //wat?
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- liked_food = MEAT | FRUIT
- disliked_food = TOXIC
- exotic_bloodtype = "BUG"
-
-/datum/species/insect/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/insect/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/insect/can_wag_tail(mob/living/carbon/human/H)
- return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/insect/is_wagging_tail(mob/living/carbon/human/H)
- return ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/insect/start_wagging_tail(mob/living/carbon/human/H)
- if("mam_tail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_tail"
- mutant_bodyparts |= "mam_waggingtail"
- H.update_body()
-
-/datum/species/insect/stop_wagging_tail(mob/living/carbon/human/H)
- if("mam_waggingtail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_waggingtail"
- mutant_bodyparts |= "mam_tail"
- H.update_body()
-
-/datum/species/insect/qualifies_for_rank(rank, list/features)
- return TRUE
-
-//Alien//
-/datum/species/xeno
- // A cloning mistake, crossing human and xenomorph DNA
- name = "Xeno Hybrid"
- id = "xeno"
- say_mod = "hisses"
- default_color = "00FF00"
- should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur", "legs")
- default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade Legs")
- attack_verb = "slash"
- attack_sound = 'sound/weapons/slash.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
- skinned_type = /obj/item/stack/sheet/animalhide/xeno
- exotic_bloodtype = "X*"
- damage_overlay_type = "xeno"
- liked_food = MEAT
-
-/datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
- if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
- species_traits += DIGITIGRADE
- if(DIGITIGRADE in species_traits)
- C.Digitigrade_Leg_Swap(FALSE)
- return ..()
-
-/datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
- if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Normal Legs")
- species_traits -= DIGITIGRADE
- if(DIGITIGRADE in species_traits)
- C.Digitigrade_Leg_Swap(TRUE)
-
-//Praise the Omnissiah, A challange worthy of my skills - HS
-
-//EXOTIC//
-//These races will likely include lots of downsides and upsides. Keep them relatively balanced.//
-
-//misc
-/mob/living/carbon/human/dummy
- no_vore = TRUE
-
-/mob/living/carbon/human/vore
- devourable = TRUE
- digestable = TRUE
- feeding = TRUE
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
deleted file mode 100644
index 311df5fce5..0000000000
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ /dev/null
@@ -1,257 +0,0 @@
-/datum/species/jelly/slime
- name = "Xenobiological Slimeperson"
-
-//##########SLIMEPEOPLE##########
-
-/datum/species/jelly/roundstartslime
- name = "Slimeperson"
- id = "slimeperson"
- limbs_id = "slime"
- default_color = "00FFFF"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
- inherent_traits = list(TRAIT_TOXINLOVER)
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur")
- default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
- say_mod = "says"
- hair_color = "mutcolor"
- hair_alpha = 160 //a notch brighter so it blends better.
- coldmod = 3
- heatmod = 1
- burnmod = 1
-
-/datum/species/jelly/roundstartslime/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/jelly/roundstartslime/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/jelly/roundstartslime/can_wag_tail(mob/living/carbon/human/H)
- return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/jelly/roundstartslime/is_wagging_tail(mob/living/carbon/human/H)
- return ("mam_waggingtail" in mutant_bodyparts)
-
-/datum/species/jelly/roundstartslime/start_wagging_tail(mob/living/carbon/human/H)
- if("mam_tail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_tail"
- mutant_bodyparts |= "mam_waggingtail"
- H.update_body()
-
-/datum/species/jelly/roundstartslime/stop_wagging_tail(mob/living/carbon/human/H)
- if("mam_waggingtail" in mutant_bodyparts)
- mutant_bodyparts -= "mam_waggingtail"
- mutant_bodyparts |= "mam_tail"
- H.update_body()
-
-
-/datum/action/innate/slime_change
- name = "Alter Form"
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "alter_form" //placeholder
- icon_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/slime_change/Activate()
- var/mob/living/carbon/human/H = owner
- if(!isjellyperson(H))
- return
- else
- H.visible_message("[owner] gains a look of \
- concentration while standing perfectly still.\
- Their body seems to shift and starts getting more goo-like. ",
- "You focus intently on altering your body while \
- standing perfectly still... ")
- change_form()
-
-/datum/action/innate/slime_change/proc/change_form()
- var/mob/living/carbon/human/H = owner
- var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
- if(select_alteration == "Hair Style")
- if(H.gender == MALE)
- var/new_style = input(owner, "Select a facial hair style", "Hair Alterations") as null|anything in GLOB.facial_hair_styles_list
- if(new_style)
- H.facial_hair_style = new_style
- else
- H.facial_hair_style = "Shaved"
- //handle normal hair
- var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list
- if(new_style)
- H.hair_style = new_style
- H.update_hair()
- else if (select_alteration == "Genitals")
- var/list/organs = list()
- var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add sexual organ", "remove sexual organ", "cancel")
- switch(operation)
- if("add sexual organ")
- var/new_organ = input("Select sexual organ:", "Organ Manipulation") in list("Penis", "Testicles", "Breasts", "Vagina", "Womb", "Cancel")
- if(new_organ == "Penis")
- H.give_penis()
- else if(new_organ == "Testicles")
- H.give_balls()
- else if(new_organ == "Breasts")
- H.give_breasts()
- else if(new_organ == "Vagina")
- H.give_vagina()
- else if(new_organ == "Womb")
- H.give_womb()
- else
- return
- if("remove sexual organ")
- for(var/obj/item/organ/genital/X in H.internal_organs)
- var/obj/item/organ/I = X
- organs["[I.name] ([I.type])"] = I
- var/obj/item/organ = input("Select sexual organ:", "Organ Manipulation", null) in organs
- organ = organs[organ]
- if(!organ)
- return
- var/obj/item/organ/genital/O
- if(isorgan(organ))
- O = organ
- O.Remove(H)
- organ.forceMove(get_turf(H))
- qdel(organ)
- H.update_genitals()
-
- else if (select_alteration == "Ears")
- var/list/snowflake_ears_list = list("Normal" = null)
- for(var/path in GLOB.mam_ears_list)
- var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
- snowflake_ears_list[S.name] = path
- var/new_ears
- new_ears = input(owner, "Choose your character's ears:", "Ear Alteration") as null|anything in snowflake_ears_list
- if(new_ears)
- H.dna.features["mam_ears"] = new_ears
- H.update_body()
-
- else if (select_alteration == "Snout")
- var/list/snowflake_snouts_list = list("Normal" = null)
- for(var/path in GLOB.mam_snouts_list)
- var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
- snowflake_snouts_list[S.name] = path
- var/new_snout
- new_snout = input(owner, "Choose your character's face:", "Face Alteration") as null|anything in snowflake_snouts_list
- if(new_snout)
- H.dna.features["mam_snouts"] = new_snout
- H.update_body()
-
- else if (select_alteration == "Markings")
- var/list/snowflake_markings_list = list()
- for(var/path in GLOB.mam_body_markings_list)
- var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
- snowflake_markings_list[S.name] = path
- var/new_mam_body_markings
- new_mam_body_markings = input(H, "Choose your character's body markings:", "Marking Alteration") as null|anything in snowflake_markings_list
- if(new_mam_body_markings)
- H.dna.features["mam_body_markings"] = new_mam_body_markings
- if(new_mam_body_markings == "None")
- H.dna.features["mam_body_markings"] = "Plain"
- for(var/X in H.bodyparts) //propagates the markings changes
- var/obj/item/bodypart/BP = X
- BP.update_limb(FALSE, H)
- H.update_body()
-
- else if (select_alteration == "Tail")
- var/list/snowflake_tails_list = list("Normal" = null)
- for(var/path in GLOB.mam_tails_list)
- var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
- snowflake_tails_list[S.name] = path
- var/new_tail
- new_tail = input(owner, "Choose your character's Tail(s):", "Tail Alteration") as null|anything in snowflake_tails_list
- if(new_tail)
- H.dna.features["mam_tail"] = new_tail
- if(new_tail != "None")
- H.dna.features["taur"] = "None"
- H.update_body()
-
- else if (select_alteration == "Taur body")
- var/list/snowflake_taur_list = list("Normal" = null)
- for(var/path in GLOB.taur_list)
- var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
- snowflake_taur_list[S.name] = path
- var/new_taur
- new_taur = input(owner, "Choose your character's tauric body:", "Tauric Alteration") as null|anything in snowflake_taur_list
- if(new_taur)
- H.dna.features["taur"] = new_taur
- if(new_taur != "None")
- H.dna.features["mam_tail"] = "None"
- H.update_body()
-
- else if (select_alteration == "Penis")
- for(var/obj/item/organ/genital/penis/X in H.internal_organs)
- qdel(X)
- var/new_shape
- new_shape = input(owner, "Choose your character's dong", "Genital Alteration") as null|anything in GLOB.cock_shapes_list
- if(new_shape)
- H.dna.features["cock_shape"] = new_shape
- H.update_genitals()
- H.give_balls()
- H.give_penis()
- H.apply_overlay()
-
-
- else if (select_alteration == "Vagina")
- for(var/obj/item/organ/genital/vagina/X in H.internal_organs)
- qdel(X)
- var/new_shape
- new_shape = input(owner, "Choose your character's pussy", "Genital Alteration") as null|anything in GLOB.vagina_shapes_list
- if(new_shape)
- H.dna.features["vag_shape"] = new_shape
- H.update_genitals()
- H.give_womb()
- H.give_vagina()
- H.apply_overlay()
-
- else if (select_alteration == "Penis Length")
- for(var/obj/item/organ/genital/penis/X in H.internal_organs)
- qdel(X)
- var/new_length
- new_length = input(owner, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Genital Alteration") as num|null
- if(new_length)
- H.dna.features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
- H.update_genitals()
- H.apply_overlay()
- H.give_balls()
- H.give_penis()
-
- else if (select_alteration == "Breast Size")
- for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
- qdel(X)
- var/new_size
- new_size = input(owner, "Breast Size", "Genital Alteration") as null|anything in GLOB.breasts_size_list
- if(new_size)
- H.dna.features["breasts_size"] = new_size
- H.update_genitals()
- H.apply_overlay()
- H.give_breasts()
-
- else if (select_alteration == "Breast Shape")
- for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
- qdel(X)
- var/new_shape
- new_shape = input(owner, "Breast Shape", "Genital Alteration") as null|anything in GLOB.breasts_shapes_list
- if(new_shape)
- H.dna.features["breasts_shape"] = new_shape
- H.update_genitals()
- H.apply_overlay()
- H.give_breasts()
-
- else
- return
diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi
index 569667a82d..a23716562e 100644
Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ
diff --git a/modular_citadel/icons/mob/mam_markings.dmi b/modular_citadel/icons/mob/mam_markings.dmi
index 8327be6eaf..dce56de556 100644
Binary files a/modular_citadel/icons/mob/mam_markings.dmi and b/modular_citadel/icons/mob/mam_markings.dmi differ
diff --git a/modular_citadel/icons/mob/markings_notmammals.dmi b/modular_citadel/icons/mob/markings_notmammals.dmi
index 59b10e93aa..d9577698d1 100644
Binary files a/modular_citadel/icons/mob/markings_notmammals.dmi and b/modular_citadel/icons/mob/markings_notmammals.dmi differ
diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi
index 1e12d2bf1a..8c0856429b 100644
Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and b/modular_citadel/icons/mob/mutant_bodyparts.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 75bb754ca6..92d836cfc6 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1796,17 +1796,39 @@
#include "code\modules\jobs\access.dm"
#include "code\modules\jobs\job_exp.dm"
#include "code\modules\jobs\jobs.dm"
+#include "code\modules\jobs\job_types\_job.dm"
+#include "code\modules\jobs\job_types\ai.dm"
#include "code\modules\jobs\job_types\assistant.dm"
+#include "code\modules\jobs\job_types\atmospheric_technician.dm"
+#include "code\modules\jobs\job_types\bartender.dm"
+#include "code\modules\jobs\job_types\botanist.dm"
#include "code\modules\jobs\job_types\captain.dm"
-#include "code\modules\jobs\job_types\cargo_service.dm"
-#include "code\modules\jobs\job_types\civilian.dm"
-#include "code\modules\jobs\job_types\civilian_chaplain.dm"
-#include "code\modules\jobs\job_types\engineering.dm"
-#include "code\modules\jobs\job_types\job.dm"
-#include "code\modules\jobs\job_types\medical.dm"
-#include "code\modules\jobs\job_types\science.dm"
-#include "code\modules\jobs\job_types\security.dm"
-#include "code\modules\jobs\job_types\silicon.dm"
+#include "code\modules\jobs\job_types\cargo_technician.dm"
+#include "code\modules\jobs\job_types\chaplain.dm"
+#include "code\modules\jobs\job_types\chemist.dm"
+#include "code\modules\jobs\job_types\chief_engineer.dm"
+#include "code\modules\jobs\job_types\chief_medical_officer.dm"
+#include "code\modules\jobs\job_types\clown.dm"
+#include "code\modules\jobs\job_types\cook.dm"
+#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\geneticist.dm"
+#include "code\modules\jobs\job_types\head_of_personnel.dm"
+#include "code\modules\jobs\job_types\head_of_security.dm"
+#include "code\modules\jobs\job_types\janitor.dm"
+#include "code\modules\jobs\job_types\lawyer.dm"
+#include "code\modules\jobs\job_types\medical_doctor.dm"
+#include "code\modules\jobs\job_types\mime.dm"
+#include "code\modules\jobs\job_types\quartermaster.dm"
+#include "code\modules\jobs\job_types\research_director.dm"
+#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\shaft_miner.dm"
+#include "code\modules\jobs\job_types\station_engineer.dm"
+#include "code\modules\jobs\job_types\virologist.dm"
+#include "code\modules\jobs\job_types\warden.dm"
#include "code\modules\jobs\map_changes\map_changes.dm"
#include "code\modules\keybindings\bindings_admin.dm"
#include "code\modules\keybindings\bindings_atom.dm"
@@ -1917,15 +1939,17 @@
#include "code\modules\mob\dead\new_player\poll.dm"
#include "code\modules\mob\dead\new_player\preferences_setup.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\_sprite_accessories.dm"
+#include "code\modules\mob\dead\new_player\sprite_accessories\alienpeople.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\body_markings.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\caps.dm"
+#include "code\modules\mob\dead\new_player\sprite_accessories\Citadel_Snowflake.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\ears.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\frills.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\hair_face.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\hair_head.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\horns.dm"
-#include "code\modules\mob\dead\new_player\sprite_accessories\legs.dm"
-#include "code\modules\mob\dead\new_player\sprite_accessories\moth_wings.dm"
+#include "code\modules\mob\dead\new_player\sprite_accessories\ipc_synths.dm"
+#include "code\modules\mob\dead\new_player\sprite_accessories\legs_and_taurs.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\pines.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\snouts.dm"
#include "code\modules\mob\dead\new_player\sprite_accessories\socks.dm"
@@ -2032,15 +2056,17 @@
#include "code\modules\mob\living\carbon\human\species_types\abductors.dm"
#include "code\modules\mob\living\carbon\human\species_types\android.dm"
#include "code\modules\mob\living\carbon\human\species_types\angel.dm"
+#include "code\modules\mob\living\carbon\human\species_types\bugmen.dm"
#include "code\modules\mob\living\carbon\human\species_types\corporate.dm"
#include "code\modules\mob\living\carbon\human\species_types\dullahan.dm"
#include "code\modules\mob\living\carbon\human\species_types\felinid.dm"
#include "code\modules\mob\living\carbon\human\species_types\flypeople.dm"
+#include "code\modules\mob\living\carbon\human\species_types\furrypeople.dm"
#include "code\modules\mob\living\carbon\human\species_types\golems.dm"
#include "code\modules\mob\living\carbon\human\species_types\humans.dm"
+#include "code\modules\mob\living\carbon\human\species_types\ipc.dm"
#include "code\modules\mob\living\carbon\human\species_types\jellypeople.dm"
#include "code\modules\mob\living\carbon\human\species_types\lizardpeople.dm"
-#include "code\modules\mob\living\carbon\human\species_types\mothmen.dm"
#include "code\modules\mob\living\carbon\human\species_types\mushpeople.dm"
#include "code\modules\mob\living\carbon\human\species_types\plasmamen.dm"
#include "code\modules\mob\living\carbon\human\species_types\podpeople.dm"
@@ -2914,7 +2940,6 @@
#include "modular_citadel\code\game\objects\items\boombox.dm"
#include "modular_citadel\code\game\objects\items\holy_weapons.dm"
#include "modular_citadel\code\game\objects\items\honk.dm"
-#include "modular_citadel\code\game\objects\items\meat.dm"
#include "modular_citadel\code\game\objects\items\stunsword.dm"
#include "modular_citadel\code\game\objects\items\vending_items.dm"
#include "modular_citadel\code\game\objects\items\circuitboards\machine_circuitboards.dm"
@@ -3011,7 +3036,6 @@
#include "modular_citadel\code\modules\mining\mining_ruins.dm"
#include "modular_citadel\code\modules\mob\cit_emotes.dm"
#include "modular_citadel\code\modules\mob\mob.dm"
-#include "modular_citadel\code\modules\mob\dead\new_player\sprite_accessories.dm"
#include "modular_citadel\code\modules\mob\living\damage_procs.dm"
#include "modular_citadel\code\modules\mob\living\living.dm"
#include "modular_citadel\code\modules\mob\living\carbon\carbon.dm"
@@ -3021,11 +3045,6 @@
#include "modular_citadel\code\modules\mob\living\carbon\human\human.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_movement.dm"
-#include "modular_citadel\code\modules\mob\living\carbon\human\life.dm"
-#include "modular_citadel\code\modules\mob\living\carbon\human\species.dm"
-#include "modular_citadel\code\modules\mob\living\carbon\human\species_types\furrypeople.dm"
-#include "modular_citadel\code\modules\mob\living\carbon\human\species_types\ipc.dm"
-#include "modular_citadel\code\modules\mob\living\carbon\human\species_types\jellypeople.dm"
#include "modular_citadel\code\modules\mob\living\silicon\ai\vox_sounds.dm"
#include "modular_citadel\code\modules\mob\living\silicon\robot\dogborg_equipment.dm"
#include "modular_citadel\code\modules\mob\living\silicon\robot\robot.dm"