diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 65d5f4befb..87925f80e1 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -394,6 +394,8 @@ SUBSYSTEM_DEF(job)
H.mind.assigned_role = rank
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)
if(ismob(new_mob))
H = new_mob
@@ -411,8 +413,12 @@ SUBSYSTEM_DEF(job)
to_chat(M, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.")
if(job && H)
+ if(job.dresscodecompliant)// CIT CHANGE - dress code compliance
+ equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
job.after_spawn(H, M)
- handle_roundstart_items(H, M.ckey, H.mind.assigned_role, H.mind.special_role) //CIT CHANGE - makes donators spawn with their items
+ equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works
+
+ //handle_roundstart_items(H, M.ckey, H.mind.assigned_role, H.mind.special_role) //CIT CHANGE - makes donators spawn with their items. This can safely be commented out when all of the donator items are migrated to the loadout system
return H
diff --git a/code/game/world.dm b/code/game/world.dm
index bbf614e90f..22829dd963 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -40,6 +40,8 @@ GLOBAL_PROTECT(security_mode)
if("no-init" in params)
return
+ cit_initialize()
+
Master.Initialize(10, FALSE)
/world/proc/SetupExternalRSC()
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 2eb8198a03..94d7e32818 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1,4 +1,11 @@
-
+ /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
+ | THIS FILE CONTAINS A SHITTON OF |
+ | CHANGES SPECIFIC TO CITADEL. IF |
+ | YOU'RE FIXING A MERGE CONFLICT |
+ | HERE, PLEASE ASK FOR REVIEW FROM |
+ | ANOTHER MAINTAINER TO ENSURE YOU |
+ | DON'T INTRODUCE REGRESSIONS. |
+ \* */
GLOBAL_LIST_EMPTY(preferences_datums)
@@ -220,6 +227,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Character Settings"
dat += "Character Appearance"
+ dat += "Loadout"
dat += "Game Preferences"
if(!path)
@@ -536,6 +544,56 @@ GLOBAL_LIST_EMPTY(preferences_datums)
*/
dat += ""
+ if(3)
+ if(!gear_tab)
+ gear_tab = GLOB.loadout_items[1]
+ dat += "
"
+ dat += "| [gear_points] loadout points remaining. \[Clear Loadout\] |
"
+ dat += "| You can only choose one item per category, unless it's an item that spawns in your backpack or hands. |
"
+ dat += "| "
+ var/firstcat = TRUE
+ for(var/i in GLOB.loadout_items)
+ if(firstcat)
+ firstcat = FALSE
+ else
+ dat += " |"
+ if(i == gear_tab)
+ dat += " [i] "
+ else
+ dat += " [i] "
+ dat += " |
"
+ dat += "
|
"
+ dat += "| [gear_tab] |
"
+ dat += "
|
"
+ dat += "| Name | "
+ dat += "Cost | "
+ dat += "Restrictions | "
+ dat += "Description |
"
+ for(var/j in GLOB.loadout_items[gear_tab])
+ var/datum/gear/gear = GLOB.loadout_items[gear_tab][j]
+ var/donoritem
+ if(gear.ckeywhitelist && gear.ckeywhitelist.len)
+ donoritem = TRUE
+ if(!(user.ckey in gear.ckeywhitelist))
+ continue
+ var/class_link = ""
+ if(gear.type in chosen_gear)
+ class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'"
+ else if(gear_points <= 0)
+ class_link = "style='white-space:normal;' class='linkOff'"
+ else if(donoritem)
+ class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ else
+ class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ dat += "| [j] | "
+ dat += "[gear.cost] | "
+ if(islist(gear.restricted_roles))
+ if(gear.restricted_roles.len)
+ dat += ""
+ dat += gear.restricted_roles.Join(";")
+ dat += ""
+ dat += " | [gear.description] |
"
+ dat += "
"
dat += "
"
if(!IsGuestKey(user.key))
@@ -1618,6 +1676,34 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if (href_list["tab"])
current_tab = text2num(href_list["tab"])
+ if(href_list["preference"] == "gear")
+ if(href_list["clear_loadout"])
+ LAZYCLEARLIST(chosen_gear)
+ gear_points = initial(gear_points)
+ save_preferences()
+ if(href_list["select_category"])
+ for(var/i in GLOB.loadout_items)
+ if(i == href_list["select_category"])
+ gear_tab = i
+ if(href_list["toggle_gear_path"])
+ var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])]
+ if(!G)
+ return
+ var/toggle = text2num(href_list["toggle_gear"])
+ if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
+ LAZYREMOVE(chosen_gear, G.type)
+ gear_points += initial(G.cost)
+ else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
+ if(!is_loadout_slot_available(G.category))
+ to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!")
+ return
+ if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist))
+ to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.")
+ return
+ if(gear_points >= initial(G.cost))
+ LAZYADD(chosen_gear, G.type)
+ gear_points -= initial(G.cost)
+
ShowChoices(user)
return 1
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index f79ec86dd6..8e69c9aaec 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -469,14 +469,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
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))
- //Citadel
- features["flavor_text"] = sanitize_text(features["flavor_text"], initial(features["flavor_text"]))
- if(!features["mcolor2"] || features["mcolor"] == "#000")
- features["mcolor2"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- if(!features["mcolor3"] || features["mcolor"] == "#000")
- features["mcolor3"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
- features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
+ cit_character_pref_load(S)
+
return 1
/datum/preferences/proc/save_character()
@@ -539,47 +533,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["job_engsec_med"] , job_engsec_med)
WRITE_FILE(S["job_engsec_low"] , job_engsec_low)
- //Citadel
- WRITE_FILE(S["feature_genitals_use_skintone"], features["genitals_use_skintone"])
- WRITE_FILE(S["feature_exhibitionist"], features["exhibitionist"])
- WRITE_FILE(S["feature_mcolor2"], features["mcolor2"])
- WRITE_FILE(S["feature_mcolor3"], features["mcolor3"])
- WRITE_FILE(S["feature_mam_body_markings"], features["mam_body_markings"])
- WRITE_FILE(S["feature_mam_tail"], features["mam_tail"])
- WRITE_FILE(S["feature_mam_ears"], features["mam_ears"])
- WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"])
- WRITE_FILE(S["feature_taur"], features["taur"])
- //Xeno features
- WRITE_FILE(S["feature_xeno_tail"], features["xenotail"])
- WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"])
- WRITE_FILE(S["feature_xeno_head"], features["xenohead"])
- //cock features
- WRITE_FILE(S["feature_has_cock"], features["has_cock"])
- WRITE_FILE(S["feature_cock_shape"], features["cock_shape"])
- WRITE_FILE(S["feature_cock_color"], features["cock_color"])
- WRITE_FILE(S["feature_cock_length"], features["cock_length"])
- WRITE_FILE(S["feature_cock_girth"], features["cock_girth"])
- WRITE_FILE(S["feature_has_sheath"], features["sheath_color"])
- //balls features
- WRITE_FILE(S["feature_has_balls"], features["has_balls"])
- WRITE_FILE(S["feature_balls_color"], features["balls_color"])
- WRITE_FILE(S["feature_balls_size"], features["balls_size"])
- WRITE_FILE(S["feature_balls_sack_size"], features["balls_sack_size"])
- WRITE_FILE(S["feature_balls_fluid"], features["balls_fluid"])
- //breasts features
- WRITE_FILE(S["feature_has_breasts"], features["has_breasts"])
- WRITE_FILE(S["feature_breasts_size"], features["breasts_size"])
- WRITE_FILE(S["feature_breasts_shape"], features["breasts_shape"])
- WRITE_FILE(S["feature_breasts_color"], features["breasts_color"])
- WRITE_FILE(S["feature_breasts_fluid"], features["breasts_fluid"])
- //vagina features
- WRITE_FILE(S["feature_has_vag"], features["has_vag"])
- WRITE_FILE(S["feature_vag_shape"], features["vag_shape"])
- WRITE_FILE(S["feature_vag_color"], features["vag_color"])
- //womb features
- WRITE_FILE(S["feature_has_womb"], features["has_womb"])
- //flavor text
- WRITE_FILE(S["feature_flavor_text"], features["flavor_text"])
+ cit_character_pref_save(S)
return 1
diff --git a/modular_citadel/code/__HELPERS/lists.dm b/modular_citadel/code/__HELPERS/lists.dm
new file mode 100644
index 0000000000..b249dfc554
--- /dev/null
+++ b/modular_citadel/code/__HELPERS/lists.dm
@@ -0,0 +1,9 @@
+/proc/is_type_in_ref_list(path, list/L)
+ if(!ispath(path))//not a path
+ return
+ for(var/i in L)
+ var/datum/D = i
+ if(!istype(D))//not an usable reference
+ continue
+ if(istype(D, path))
+ return TRUE
\ No newline at end of file
diff --git a/modular_citadel/code/__HELPERS/mobs.dm b/modular_citadel/code/__HELPERS/mobs.dm
new file mode 100644
index 0000000000..a6fe446b5d
--- /dev/null
+++ b/modular_citadel/code/__HELPERS/mobs.dm
@@ -0,0 +1,28 @@
+/proc/slot_to_string(slot)
+ switch(slot)
+ if(slot_back)
+ return "Backpack"
+ if(slot_wear_mask)
+ return "Mask"
+ if(slot_hands)
+ return "Hands"
+ if(slot_belt)
+ return "Belt"
+ if(slot_ears)
+ return "Ears"
+ if(slot_glasses)
+ return "Glasses"
+ if(slot_gloves)
+ return "Gloves"
+ if(slot_neck)
+ return "Neck"
+ if(slot_head)
+ return "Head"
+ if(slot_shoes)
+ return "Shoes"
+ if(slot_wear_suit)
+ return "Suit"
+ if(slot_w_uniform)
+ return "Uniform"
+ if(slot_in_backpack)
+ return "In backpack"
diff --git a/modular_citadel/code/controllers/subsystem/job.dm b/modular_citadel/code/controllers/subsystem/job.dm
new file mode 100644
index 0000000000..234c606e00
--- /dev/null
+++ b/modular_citadel/code/controllers/subsystem/job.dm
@@ -0,0 +1,27 @@
+/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff)
+ var/mob/the_mob = N
+ if(!the_mob)
+ the_mob = M // cause this doesn't get assigned if player is a latejoiner
+ if(the_mob.client && the_mob.client.prefs && (the_mob.client.prefs.chosen_gear && the_mob.client.prefs.chosen_gear.len))
+ if(!ishuman(M))//no silicons allowed
+ return
+ for(var/i in the_mob.client.prefs.chosen_gear)
+ var/datum/gear/G = i
+ G = GLOB.loadout_items[slot_to_string(initial(G.category))][initial(G.name)]
+ if(!G)
+ continue
+ var/permitted = TRUE
+ if(G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
+ permitted = FALSE
+ if(G.ckeywhitelist && G.ckeywhitelist.len && !(the_mob.client.ckey in G.ckeywhitelist))
+ permitted = FALSE
+ if(!equipbackpackstuff && G.category == slot_in_backpack)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
+ permitted = FALSE
+ if(equipbackpackstuff && G.category != slot_in_backpack)//ditto
+ permitted = FALSE
+ if(!permitted)
+ continue
+ var/obj/item/I = new G.path
+ if(!M.equip_to_slot_if_possible(I, G.category, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
+ if(!M.equip_to_slot_if_possible(I, slot_in_backpack, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // Otherwise, try to put it in the backpack
+ I.forceMove(get_turf(M)) // If everything fails, just put it on the floor under the mob.
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
new file mode 100644
index 0000000000..416c3f07c4
--- /dev/null
+++ b/modular_citadel/code/init.dm
@@ -0,0 +1,4 @@
+//init file stolen from hippie
+
+/proc/cit_initialize()
+ initialize_global_loadout_items()
\ No newline at end of file
diff --git a/modular_citadel/code/modules/client/loadout/_donator.dm b/modular_citadel/code/modules/client/loadout/_donator.dm
new file mode 100644
index 0000000000..d663d572cd
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/_donator.dm
@@ -0,0 +1,169 @@
+//This is the file that handles donator loadout items.
+
+/datum/gear/pingcoderfailsafe
+ name = "IF YOU SEE THIS, PING A CODER RIGHT NOW!"
+ category = slot_in_backpack
+ path = /obj/item/bikehorn/golden
+ ckeywhitelist = list("This entry should never appear with this variable set.") //If it does, then that means somebody fucked up the whitelist system pretty hard
+
+/datum/gear/donortestingbikehorn
+ name = "Donor item testing bikehorn"
+ category = slot_in_backpack
+ path = /obj/item/bikehorn
+ ckeywhitelist = list("jayehh","deathride58")
+
+/datum/gear/kevhorn
+ name = "Airhorn"
+ category = slot_in_backpack
+ path = /obj/item/bikehorn/airhorn
+ ckeywhitelist = list("kevinz000")
+
+/datum/gear/cebusoap
+ name = "Cebutris' soap"
+ category = slot_in_backpack
+ path = /obj/item/custom/ceb_soap
+ ckeywhitelist = list("cebutris")
+
+/datum/gear/kiaracloak
+ name = "Kiara's cloak"
+ category = slot_neck
+ path = /obj/item/clothing/neck/cloak/inferno
+ ckeywhitelist = list("inferno707")
+
+/datum/gear/kiaracollar
+ name = "Kiara's collar"
+ category = slot_neck
+ path = /obj/item/clothing/neck/petcollar/inferno
+ ckeywhitelist = list("inferno707")
+
+/datum/gear/kiaramedal
+ name = "Insignia of Steele"
+ category = slot_in_backpack
+ path = /obj/item/clothing/accessory/medal/steele
+ ckeywhitelist = list("inferno707")
+
+/datum/gear/sexymimemask
+ name = "The hollow heart"
+ category = slot_wear_mask
+ path = /obj/item/clothing/mask/sexymime
+ ckeywhitelist = list("inferno707")
+
+/datum/gear/engravedzippo
+ name = "Engraved zippo"
+ category = slot_hands
+ path = /obj/item/lighter/gold
+ ckeywhitelist = list("dirtyoldharry")
+
+/datum/gear/geisha
+ name = "Geisha suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/geisha
+ ckeywhitelist = list("atiefling")
+
+/datum/gear/specialscarf
+ name = "Special scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/zomb
+ ckeywhitelist = list("zombierobin")
+
+/datum/gear/redmadcoat
+ name = "The Mad's labcoat"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/toggle/labcoat/mad/red
+ ckeywhitelist = list("zombierobin")
+
+/datum/gear/santahat
+ name = "Santa hat"
+ category = slot_head
+ path = /obj/item/clothing/head/santa/fluff
+ ckeywhitelist = list("illotafv")
+
+/datum/gear/reindeerhat
+ name = "Reindeer hat"
+ category = slot_head
+ path = /obj/item/clothing/head/hardhat/reindeer/fluff
+ ckeywhitelist = list("illotafv")
+
+/datum/gear/treeplushie
+ name = "Christmas tree plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/tree
+ ckeywhitelist = list("illotafv")
+
+/datum/gear/santaoutfit
+ name = "Santa costume"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/space/santa/fluff
+ ckeywhitelist = list("illotafv")
+
+/datum/gear/treecloak
+ name = "Christmas tree cloak"
+ category = slot_neck
+ path = /obj/item/clothing/neck/cloak/festive
+ ckeywhitelist = list("illotafv")
+
+/datum/gear/carrotplush
+ name = "Carrot plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/carrot
+ ckeywhitelist = list("improvedname")
+
+/datum/gear/carrotcloak
+ name = "Carrot cloak"
+ category = slot_neck
+ path = /obj/item/clothing/neck/cloak/carrot
+ ckeywhitelist = list("improvedname")
+
+/datum/gear/albortorosamask
+ name = "Alborto Rosa mask"
+ category = slot_wear_mask
+ path = /obj/item/clothing/mask/luchador/zigfie
+ ckeywhitelist = list("zigfie")
+
+/datum/gear/mankini
+ name = "Mankini"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/mankini
+ ckeywhitelist = list("zigfie")
+
+/datum/gear/pinkshoes
+ name = "Pink shoes"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/sneakers/pink
+ ckeywhitelist = list("zigfie")
+
+/datum/gear/reecesgreatcoat
+ name = "Reece's Great Coat"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/trenchcoat/green
+ ckeywhitelist = list("geemiesif")
+
+/datum/gear/russianflask
+ name = "Russian flask"
+ category = slot_in_backpack
+ path = /obj/item/reagent_containers/food/drinks/flask/russian
+ ckeywhitelist = list("slomka")
+
+/datum/gear/stalkermask
+ name = "S.T.A.L.K.E.R. mask"
+ category = slot_wear_mask
+ path = /obj/item/clothing/mask/gas/stalker
+ ckeywhitelist = list("slomka")
+
+/datum/gear/stripedcollar
+ name = "Striped collar"
+ category = slot_neck
+ path = /obj/item/clothing/neck/petcollar/stripe
+ ckeywhitelist = list("jademanique")
+
+/datum/gear/performersoutfit
+ name = "Bluish performer's outfit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/singery/custom
+ ckeywhitelist = list("killer402402")
+
+/datum/gear/vermillion
+ name = "Vermillion clothing"
+ category = slot_w_uniform
+ path = /obj/item/clothing/suit/vermillion
+ ckeywhitelist = list("fractious")
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
new file mode 100644
index 0000000000..2779d6f124
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -0,0 +1,24 @@
+/datum/gear/plushcarp
+ name = "Space carp plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/carpplushie
+
+/datum/gear/plushliz
+ name = "Lizard plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/lizardplushie
+
+/datum/gear/plushsnek
+ name = "Snake plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/snakeplushie
+
+/datum/gear/plushslime
+ name = "Slime plushie"
+ category = slot_in_backpack
+ path = /obj/item/toy/plush/slimeplushie
+
+/datum/gear/dildo
+ name = "Customizable dildo"
+ category = slot_in_backpack
+ path = /obj/item/dildo/custom
diff --git a/modular_citadel/code/modules/client/loadout/glasses.dm b/modular_citadel/code/modules/client/loadout/glasses.dm
new file mode 100644
index 0000000000..68ba745311
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/glasses.dm
@@ -0,0 +1,39 @@
+/datum/gear/cold
+ name = "Cold goggles"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/cold
+
+/datum/gear/eyepatch
+ name = "Eyepatch"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/eyepatch
+
+/datum/gear/heat
+ name = "Heat goggles"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/heat
+
+/datum/gear/hipster
+ name = "Hipster glasses"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/regular/hipster
+
+/datum/gear/jamjar
+ name = "Jamjar glasses"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/regular/jamjar
+
+/datum/gear/monocle
+ name = "Monocle"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/monocle
+
+/datum/gear/orange
+ name = "Orange glasses"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/orange
+
+/datum/gear/prescription
+ name = "Prescription glasses"
+ category = slot_glasses
+ path = /obj/item/clothing/glasses/regular
diff --git a/modular_citadel/code/modules/client/loadout/hands.dm b/modular_citadel/code/modules/client/loadout/hands.dm
new file mode 100644
index 0000000000..cc5e6b8e71
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/hands.dm
@@ -0,0 +1,49 @@
+/datum/gear/cane
+ name = "Cane"
+ category = slot_hands
+ path = /obj/item/cane
+
+/datum/gear/cigarettes
+ name = "Cigarette pack"
+ category = slot_hands
+ path = /obj/item/storage/fancy/cigarettes
+
+/datum/gear/dice
+ name = "Dice bag"
+ category = slot_hands
+ path = /obj/item/storage/pill_bottle/dice
+
+/datum/gear/eightball
+ name = "Magic eightball"
+ category = slot_hands
+ path = /obj/item/toy/eightball
+
+/datum/gear/matches
+ name = "Matchbox"
+ category = slot_hands
+ path = /obj/item/storage/box/matches
+
+/datum/gear/cheaplighter
+ name = "Cheap lighter"
+ category = slot_hands
+ path = /obj/item/lighter/greyscale
+
+/datum/gear/cards
+ name = "Playing cards"
+ category = slot_hands
+ path = /obj/item/toy/cards/deck
+
+/datum/gear/skub
+ name = "Skub"
+ category = slot_hands
+ path = /obj/item/skub
+
+/datum/gear/carpplushie
+ name = "Space carp plushie"
+ category = slot_hands
+ path = /obj/item/toy/plush/carpplushie
+
+/datum/gear/wallet
+ name = "Wallet"
+ category = slot_hands
+ path = /obj/item/storage/wallet
diff --git a/modular_citadel/code/modules/client/loadout/head.dm b/modular_citadel/code/modules/client/loadout/head.dm
new file mode 100644
index 0000000000..66701903d5
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/head.dm
@@ -0,0 +1,39 @@
+/datum/gear/baseball
+ name = "Ballcap"
+ category = slot_head
+ path = /obj/item/clothing/head/soft/mime
+
+/datum/gear/beanie
+ name = "Beanie"
+ category = slot_head
+ path = /obj/item/clothing/head/beanie
+
+/datum/gear/beret
+ name = "Black beret"
+ category = slot_head
+ path = /obj/item/clothing/head/beret/black
+
+/datum/gear/flatcap
+ name = "Flat cap"
+ category = slot_head
+ path = /obj/item/clothing/head/flatcap
+
+/datum/gear/pirate
+ name = "Pirate hat"
+ category = slot_head
+ path = /obj/item/clothing/head/pirate
+
+/datum/gear/rice_hat
+ name = "Rice hat"
+ category = slot_head
+ path = /obj/item/clothing/head/rice_hat
+
+/datum/gear/ushanka
+ name = "Ushanka"
+ category = slot_head
+ path = /obj/item/clothing/head/ushanka
+
+/datum/gear/slime
+ name = "Slime hat"
+ category = slot_head
+ path = /obj/item/clothing/head/collectable/slime
diff --git a/modular_citadel/code/modules/client/loadout/loadout.dm b/modular_citadel/code/modules/client/loadout/loadout.dm
new file mode 100644
index 0000000000..86efc6dc5b
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/loadout.dm
@@ -0,0 +1,31 @@
+// Loadout system. All items are children of /datum/gear. To make a new item, you usually just define a new item like /datum/gear/example
+// then set required vars like name(string), category(slot define, take them from code/__DEFINES/inventory.dm (the lowertext ones) (be sure that there is an entry in
+// slot_to_string(slot) proc in hippiestation/code/_HELPERS/mobs.dm to show the category name in preferences menu) and path (the actual item path).
+// description defaults to the path initial desc, cost defaults to 1 point but if you think your item requires more points, the framework allows that
+// and lastly, restricted_roles list allows you to let someone spawn with certain items only if the job they spawned with is on the list.
+
+GLOBAL_LIST_EMPTY(loadout_items)
+
+/proc/initialize_global_loadout_items()
+ LAZYINITLIST(GLOB.loadout_items)
+ for(var/item in subtypesof(/datum/gear))
+ var/datum/gear/I = new item
+ if(!GLOB.loadout_items[slot_to_string(I.category)])
+ LAZYINITLIST(GLOB.loadout_items[slot_to_string(I.category)])
+ LAZYSET(GLOB.loadout_items[slot_to_string(I.category)], I.name, I)
+
+
+/datum/gear
+ var/name
+ var/category
+ var/description
+ var/path //item-to-spawn path
+ var/cost = 1 //normally, each loadout costs a single point.
+ var/list/restricted_roles
+ var/list/ckeywhitelist
+
+/datum/gear/New()
+ ..()
+ if(!description && path)
+ var/obj/O = path
+ description = initial(O.desc)
diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm
new file mode 100644
index 0000000000..839502d99c
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/mask.dm
@@ -0,0 +1,4 @@
+/datum/gear/balaclava
+ name = "Balaclava"
+ category = slot_wear_mask
+ path = /obj/item/clothing/mask/balaclava
diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm
new file mode 100644
index 0000000000..067d5926eb
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/neck.dm
@@ -0,0 +1,90 @@
+/datum/gear/bluetie
+ name = "Blue tie"
+ category = slot_neck
+ path = /obj/item/clothing/neck/tie/blue
+
+/datum/gear/redtie
+ name = "Red tie"
+ category = slot_neck
+ path = /obj/item/clothing/neck/tie/red
+
+/datum/gear/blacktie
+ name = "Black tie"
+ category = slot_neck
+ path = /obj/item/clothing/neck/tie/black
+
+/datum/gear/collar
+ name = "Collar"
+ category = slot_neck
+ path = /obj/item/clothing/neck/petcollar
+
+/datum/gear/stethoscope
+ name = "Stethoscope"
+ category = slot_neck
+ path = /obj/item/clothing/neck/stethoscope
+ restricted_roles = list("Medical Doctor", "Chief Medical Officer")
+
+/datum/gear/scarf
+ name = "White scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf
+
+/datum/gear/blackscarf
+ name = "Black scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/black
+
+/datum/gear/redscarf
+ name = "Red scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/red
+
+/datum/gear/greenscarf
+ name = "Green scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/green
+
+/datum/gear/darkbluescarf
+ name = "Dark blue scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/darkblue
+
+/datum/gear/purplescarf
+ name = "Purple scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/purple
+
+/datum/gear/yellowscarf
+ name = "Yellow scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/yellow
+
+/datum/gear/orangescarf
+ name = "Orange scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/orange
+
+/datum/gear/cyanscarf
+ name = "Cyan scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/scarf/cyan
+
+/datum/gear/stripedredscarf
+ name = "Striped red scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/stripedredscarf
+
+/datum/gear/stripedbluescarf
+ name = "Striped blue scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/stripedbluescarf
+
+/datum/gear/stripedgreenscarf
+ name = "Striped green scarf"
+ category = slot_neck
+ path = /obj/item/clothing/neck/stripedgreenscarf
+
+/datum/gear/headphones
+ name = "Headphones"
+ category = slot_neck
+ path = /obj/item/clothing/ears/headphones
diff --git a/modular_citadel/code/modules/client/loadout/shoes.dm b/modular_citadel/code/modules/client/loadout/shoes.dm
new file mode 100644
index 0000000000..0d233c3a5e
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/shoes.dm
@@ -0,0 +1,39 @@
+/datum/gear/laceup
+ name = "Laceup shoes"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/laceup
+
+/datum/gear/workboots
+ name = "Work boots"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/workboots
+
+/datum/gear/jackboots
+ name = "Jackboots"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/jackboots
+
+/datum/gear/winterboots
+ name = "Winter boots"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/winterboots
+
+/datum/gear/sandals
+ name = "Sandals"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/sandal
+
+/datum/gear/blackshoes
+ name = "Black shoes"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/sneakers/black
+
+/datum/gear/brownshoes
+ name = "Brown shoes"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/sneakers/brown
+
+/datum/gear/whiteshoes
+ name = "White shoes"
+ category = slot_shoes
+ path = /obj/item/clothing/shoes/sneakers/white
diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm
new file mode 100644
index 0000000000..9e0a3272ab
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/suit.dm
@@ -0,0 +1,59 @@
+/datum/gear/poncho
+ name = "Poncho"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/poncho
+
+/datum/gear/ponchogreen
+ name = "Green poncho"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/poncho/green
+
+/datum/gear/ponchored
+ name = "Red poncho"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/poncho/red
+
+/datum/gear/jacketbomber
+ name = "Bomber jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket
+
+/datum/gear/jacketleather
+ name = "Leather jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/leather
+
+/datum/gear/overcoatleather
+ name = "Leather overcoat"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/leather/overcoat
+
+/datum/gear/jacketpuffer
+ name = "Puffer jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/puffer
+
+/datum/gear/vestpuffer
+ name = "Puffer vest"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/puffer/vest
+
+/datum/gear/jacketlettermanbrown
+ name = "Brown letterman jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/letterman
+
+/datum/gear/jacketlettermanred
+ name = "Red letterman jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/letterman_red
+
+/datum/gear/jacketlettermanNT
+ name = "Nanotrasen letterman jacket"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/jacket/letterman_nanotrasen
+
+/datum/gear/coat
+ name = "Winter coat"
+ category = slot_wear_suit
+ path = /obj/item/clothing/suit/hooded/wintercoat
diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm
new file mode 100644
index 0000000000..c500c1acc8
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/uniform.dm
@@ -0,0 +1,79 @@
+/datum/gear/suitblack
+ name = "Black suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket
+
+/datum/gear/suitgreen
+ name = "Green suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/green
+
+/datum/gear/suitred
+ name = "Red suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/red
+
+/datum/gear/suitcharcoal
+ name = "Charcoal suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/charcoal
+
+/datum/gear/suitnavy
+ name = "Navy suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/navy
+
+/datum/gear/suitburgundy
+ name = "Burgundy suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/burgundy
+
+/datum/gear/suittan
+ name = "Tan suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/tan
+
+/datum/gear/suitwhite
+ name = "White suit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/suit_jacket/white
+
+/datum/gear/assistantformal
+ name = "Assistant's formal uniform"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/assistantformal
+
+/datum/gear/maidcostume
+ name = "Maid costume"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/maid
+
+/datum/gear/mailmanuniform
+ name = "Mailman's jumpsuit"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/rank/mailman
+
+/datum/gear/skirtblack
+ name = "Black skirt"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/skirt/black
+
+/datum/gear/skirtblue
+ name = "Blue skirt"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/skirt/blue
+
+/datum/gear/skirtred
+ name = "Red skirt"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/skirt/red
+
+/datum/gear/skirtpurple
+ name = "Purple skirt"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/skirt/purple
+
+/datum/gear/kilt
+ name = "Kilt"
+ category = slot_w_uniform
+ path = /obj/item/clothing/under/kilt
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
new file mode 100644
index 0000000000..333854ef99
--- /dev/null
+++ b/modular_citadel/code/modules/client/preferences.dm
@@ -0,0 +1,31 @@
+#define DEFAULT_SLOT_AMT 2
+#define HANDS_SLOT_AMT 2
+#define BACKPACK_SLOT_AMT 4
+
+/datum/preferences
+ var/gear_points = 10
+ var/list/gear_categories
+ var/list/chosen_gear
+ var/gear_tab
+
+/datum/preferences/New(client/C)
+ ..()
+ LAZYINITLIST(chosen_gear)
+
+/datum/preferences/proc/is_loadout_slot_available(slot)
+ var/list/L
+ LAZYINITLIST(L)
+ for(var/i in chosen_gear)
+ var/datum/gear/G = i
+ var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1
+ LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots)
+ switch(slot)
+ if(slot_in_backpack)
+ if(L[slot_to_string(slot_in_backpack)] < BACKPACK_SLOT_AMT)
+ return TRUE
+ if(slot_hands)
+ if(L[slot_to_string(slot_hands)] < HANDS_SLOT_AMT)
+ return TRUE
+ else
+ if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT)
+ return TRUE
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
new file mode 100644
index 0000000000..4d0f950f7f
--- /dev/null
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -0,0 +1,72 @@
+/datum/preferences/proc/cit_character_pref_load(savefile/S)
+ //Citadel
+ features["flavor_text"] = sanitize_text(features["flavor_text"], initial(features["flavor_text"]))
+ if(!features["mcolor2"] || features["mcolor"] == "#000")
+ features["mcolor2"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
+ if(!features["mcolor3"] || features["mcolor"] == "#000")
+ features["mcolor3"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
+ features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
+ features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
+
+ //gear loadout
+ var/text_to_load
+ S["loadout"] >> text_to_load
+ var/list/saved_loadout_paths = splittext(text_to_load, "|")
+ LAZYCLEARLIST(chosen_gear)
+ gear_points = initial(gear_points)
+ for(var/i in saved_loadout_paths)
+ var/datum/gear/path = text2path(i)
+ if(path)
+ LAZYADD(chosen_gear, path)
+ gear_points -= initial(path.cost)
+
+/datum/preferences/proc/cit_character_pref_save(savefile/S)
+ //Citadel
+ WRITE_FILE(S["feature_genitals_use_skintone"], features["genitals_use_skintone"])
+ WRITE_FILE(S["feature_exhibitionist"], features["exhibitionist"])
+ WRITE_FILE(S["feature_mcolor2"], features["mcolor2"])
+ WRITE_FILE(S["feature_mcolor3"], features["mcolor3"])
+ WRITE_FILE(S["feature_mam_body_markings"], features["mam_body_markings"])
+ WRITE_FILE(S["feature_mam_tail"], features["mam_tail"])
+ WRITE_FILE(S["feature_mam_ears"], features["mam_ears"])
+ WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"])
+ WRITE_FILE(S["feature_taur"], features["taur"])
+ //Xeno features
+ WRITE_FILE(S["feature_xeno_tail"], features["xenotail"])
+ WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"])
+ WRITE_FILE(S["feature_xeno_head"], features["xenohead"])
+ //cock features
+ WRITE_FILE(S["feature_has_cock"], features["has_cock"])
+ WRITE_FILE(S["feature_cock_shape"], features["cock_shape"])
+ WRITE_FILE(S["feature_cock_color"], features["cock_color"])
+ WRITE_FILE(S["feature_cock_length"], features["cock_length"])
+ WRITE_FILE(S["feature_cock_girth"], features["cock_girth"])
+ WRITE_FILE(S["feature_has_sheath"], features["sheath_color"])
+ //balls features
+ WRITE_FILE(S["feature_has_balls"], features["has_balls"])
+ WRITE_FILE(S["feature_balls_color"], features["balls_color"])
+ WRITE_FILE(S["feature_balls_size"], features["balls_size"])
+ WRITE_FILE(S["feature_balls_sack_size"], features["balls_sack_size"])
+ WRITE_FILE(S["feature_balls_fluid"], features["balls_fluid"])
+ //breasts features
+ WRITE_FILE(S["feature_has_breasts"], features["has_breasts"])
+ WRITE_FILE(S["feature_breasts_size"], features["breasts_size"])
+ WRITE_FILE(S["feature_breasts_shape"], features["breasts_shape"])
+ WRITE_FILE(S["feature_breasts_color"], features["breasts_color"])
+ WRITE_FILE(S["feature_breasts_fluid"], features["breasts_fluid"])
+ //vagina features
+ WRITE_FILE(S["feature_has_vag"], features["has_vag"])
+ WRITE_FILE(S["feature_vag_shape"], features["vag_shape"])
+ WRITE_FILE(S["feature_vag_color"], features["vag_color"])
+ //womb features
+ WRITE_FILE(S["feature_has_womb"], features["has_womb"])
+ //flavor text
+ WRITE_FILE(S["feature_flavor_text"], features["flavor_text"])
+
+ //gear loadout
+ if(islist(chosen_gear))
+ if(chosen_gear.len)
+ var/text_to_save = chosen_gear.Join("|")
+ S["loadout"] << text_to_save
+ else
+ S["loadout"] << "" //empty string to reset the value
diff --git a/modular_citadel/dresscode_values.dm b/modular_citadel/dresscode_values.dm
new file mode 100644
index 0000000000..24cd5c5ac9
--- /dev/null
+++ b/modular_citadel/dresscode_values.dm
@@ -0,0 +1,8 @@
+//This file controls whether or not a job complies with dresscodes.
+//If a job complies with dresscodes, loadout items will not be equipped instead of the job's outfit, instead placing the items into the player's backpack.
+
+/datum/job
+ var/dresscodecompliant = TRUE
+
+/datum/job/assistant
+ dresscodecompliant = FALSE
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index d42e96f228..ba12e6300c 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2485,8 +2485,13 @@
#include "modular_citadel\cit_turfs.dm"
#include "modular_citadel\citadel_ghostrole_spawners.dm"
#include "modular_citadel\cydonian_armor.dm"
+#include "modular_citadel\dresscode_values.dm"
#include "modular_citadel\polychromic_clothes.dm"
#include "modular_citadel\simplemob_vore_values.dm"
+#include "modular_citadel\code\init.dm"
+#include "modular_citadel\code\__HELPERS\lists.dm"
+#include "modular_citadel\code\__HELPERS\mobs.dm"
+#include "modular_citadel\code\controllers\subsystem\job.dm"
#include "modular_citadel\code\datums\uplink_items_cit.dm"
#include "modular_citadel\code\datums\mutations\hulk.dm"
#include "modular_citadel\code\game\gamemodes\miniantags\bot_swarm\swarmer_event.dm"
@@ -2495,6 +2500,19 @@
#include "modular_citadel\code\game\objects\items\devices\PDA\PDA.dm"
#include "modular_citadel\code\game\objects\items\devices\radio\shockcollar.dm"
#include "modular_citadel\code\game\objects\items\melee\eutactic_blades.dm"
+#include "modular_citadel\code\modules\client\preferences.dm"
+#include "modular_citadel\code\modules\client\preferences_savefile.dm"
+#include "modular_citadel\code\modules\client\loadout\_donator.dm"
+#include "modular_citadel\code\modules\client\loadout\backpack.dm"
+#include "modular_citadel\code\modules\client\loadout\glasses.dm"
+#include "modular_citadel\code\modules\client\loadout\hands.dm"
+#include "modular_citadel\code\modules\client\loadout\head.dm"
+#include "modular_citadel\code\modules\client\loadout\loadout.dm"
+#include "modular_citadel\code\modules\client\loadout\mask.dm"
+#include "modular_citadel\code\modules\client\loadout\neck.dm"
+#include "modular_citadel\code\modules\client\loadout\shoes.dm"
+#include "modular_citadel\code\modules\client\loadout\suit.dm"
+#include "modular_citadel\code\modules\client\loadout\uniform.dm"
#include "modular_citadel\code\modules\crafting\recipes.dm"
#include "modular_citadel\code\modules\mining\mine_items.dm"
#include "modular_citadel\code\modules\mob\living\banana_spider.dm"