From d9707a228ea4f025f70d8fadc19939574c86a49a Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 22 Jun 2024 23:09:03 +0200 Subject: [PATCH 1/3] [MIRROR] Adds Character Loadout Tab to preferences (with just a small handful of items to start) (#28126) * Adds Character Loadout Tab to preferences (with just a small handful of items to start) * step one rip out all the old nasties * fixes, current bugs: donator lock, ckey lock, one item in case * opps * sanity checks, fixed, donator implementation, ckey locking. fixes. * wew * final fixes * Update loadout_categories.dm * Update loadout_items.dm * Update loadout_items.dm * Update declarations.dm --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> Co-authored-by: SpaceLoveSs13 <68121607+SpaceLoveSs13@users.noreply.github.com> --- code/__DEFINES/preferences.dm | 14 + code/__DEFINES/traits/declarations.dm | 13 + code/__DEFINES/~skyrat_defines/loadout.dm | 9 + code/__DEFINES/~skyrat_defines/loadouts.dm | 33 -- code/_globalvars/traits/_traits.dm | 1 + code/controllers/subsystem/job.dm | 2 +- .../subsystem/processing/quirks.dm | 2 +- code/controllers/subsystem/ticker.dm | 7 - .../datums/quirks/neutral_quirks/pride_pin.dm | 19 - code/game/gamemodes/objective.dm | 5 +- code/game/gamemodes/objective_items.dm | 16 +- code/game/objects/items/plushes.dm | 5 + code/modules/admin/verbs/mapping.dm | 9 +- code/modules/antagonists/spy/spy_bounty.dm | 14 +- .../antagonists/traitor/objectives/steal.dm | 4 + code/modules/client/client_procs.dm | 1 - code/modules/client/preferences.dm | 20 +- .../modules/client/preferences/_preference.dm | 9 +- .../migrations/quirk_loadout_migration.dm | 27 + code/modules/client/preferences/pride_pin.dm | 16 - code/modules/client/preferences_savefile.dm | 9 +- code/modules/clothing/head/hat.dm | 2 + code/modules/clothing/head/jobs.dm | 4 +- code/modules/clothing/neck/_neck.dm | 2 + .../clothing/under/accessories/badges.dm | 25 +- code/modules/jobs/job_types/_job.dm | 19 +- .../jobs/job_types/assistant/assistant.dm | 4 +- .../modules/loadout/categories/accessories.dm | 94 ++++ code/modules/loadout/categories/glasses.dm | 57 ++ code/modules/loadout/categories/heads.dm | 142 +++++ code/modules/loadout/categories/inhands.dm | 33 ++ code/modules/loadout/categories/neck.dm | 40 ++ code/modules/loadout/categories/pocket.dm | 204 +++++++ code/modules/loadout/loadout_categories.dm | 86 +++ code/modules/loadout/loadout_helpers.dm | 142 +++++ code/modules/loadout/loadout_items.dm | 406 ++++++++++++++ code/modules/loadout/loadout_menu.dm | 129 +++++ code/modules/loadout/loadout_preference.dm | 68 +++ .../modules/mob/dead/new_player/new_player.dm | 8 - .../mob/dead/new_player/preferences_setup.dm | 10 +- .../living/carbon/human/human_update_icons.dm | 24 +- code/modules/unit_tests/_unit_tests.dm | 1 - ...eenshot_antag_icons_driftingcontractor.png | Bin 635 -> 0 bytes ...screenshot_antag_icons_sentientdisease.png | Bin 389 -> 0 bytes ...manoids__datum_species_monkey_holodeck.png | Bin 823 -> 0 bytes ...nshot_humanoids__datum_species_teshari.png | Bin 1058 -> 1058 bytes ...creenshot_humanoids__datum_species_vox.png | Bin 1251 -> 1221 bytes ..._humanoids__datum_species_vox_primalis.png | Bin 1248 -> 1249 bytes .../unit_tests/~skyrat/loadout_dupes.dm | 14 - icons/obj/fluff/previews.dmi | Bin 7799 -> 8491 bytes .../code/modules/client/preferences.dm | 2 - .../modules/client/preferences_savefile.dm | 11 - .../modules/loadout/categories/accessories.dm | 56 ++ .../code/modules/loadout/categories/belts.dm} | 28 +- .../loadout/categories}/donator_personal.dm | 0 .../code/modules/loadout/categories/ears.dm | 21 + .../modules/loadout/categories/glasses.dm} | 47 +- .../modules/loadout/categories/gloves.dm} | 38 +- .../code/modules/loadout/categories/heads.dm} | 92 +--- .../modules/loadout/categories/inhands.dm} | 32 -- .../code/modules/loadout/categories/mask.dm} | 31 +- .../code/modules/loadout/categories/neck.dm} | 33 -- .../modules/loadout/categories/pocket.dm} | 2 +- .../code/modules/loadout/categories/shoes.dm} | 31 +- .../code/modules/loadout/categories/suit.dm} | 30 +- .../code/modules/loadout/categories/toys.dm} | 15 +- .../modules/loadout/categories/uniform.dm} | 510 +++++++++--------- .../modules/better_vox/code/vox_species.dm | 10 +- .../customization/__HELPERS/global_lists.dm | 31 -- .../modules/clothing/under/accessories.dm | 19 - .../living/carbon/human/custom_bodytype.dm | 8 +- .../mob/living/carbon/human/species/vox.dm | 12 +- .../mob/living/carbon/human/worn_overlays.dm | 6 +- .../modules/events/code/event_spawner.dm | 4 - .../loadouts/loadout_items/_loadout_datum.dm | 135 ----- .../loadout_items/loadout_datum_accessory.dm | 104 ---- .../loadout_items/loadout_datum_ears.dm | 30 -- .../loadouts/loadout_items/under/donator.dm | 14 - .../loadouts/loadout_ui/loadout_manager.dm | 342 ------------ .../loadout_ui/loadout_outfit_helpers.dm | 168 ------ modular_skyrat/modules/loadouts/readme.md | 12 - .../modules/teshari/code/_teshari.dm | 14 +- .../modules/teshari/code/teshari_bodytype.dm | 4 +- tgstation.dme | 50 +- .../CharacterPreferenceWindow.tsx | 17 + .../interfaces/PreferencesMenu/MainPage.tsx | 15 - .../tgui/interfaces/PreferencesMenu/data.ts | 6 + .../PreferencesMenu/loadout/ItemDisplay.tsx | 147 +++++ .../PreferencesMenu/loadout/ModifyPanel.tsx | 219 ++++++++ .../PreferencesMenu/loadout/base.ts | 46 ++ .../PreferencesMenu/loadout/index.tsx | 337 ++++++++++++ .../character_preferences/pride_pin.tsx | 7 - 92 files changed, 2822 insertions(+), 1663 deletions(-) create mode 100644 code/__DEFINES/~skyrat_defines/loadout.dm delete mode 100644 code/__DEFINES/~skyrat_defines/loadouts.dm delete mode 100644 code/datums/quirks/neutral_quirks/pride_pin.dm create mode 100644 code/modules/client/preferences/migrations/quirk_loadout_migration.dm delete mode 100644 code/modules/client/preferences/pride_pin.dm create mode 100644 code/modules/loadout/categories/accessories.dm create mode 100644 code/modules/loadout/categories/glasses.dm create mode 100644 code/modules/loadout/categories/heads.dm create mode 100644 code/modules/loadout/categories/inhands.dm create mode 100644 code/modules/loadout/categories/neck.dm create mode 100644 code/modules/loadout/categories/pocket.dm create mode 100644 code/modules/loadout/loadout_categories.dm create mode 100644 code/modules/loadout/loadout_helpers.dm create mode 100644 code/modules/loadout/loadout_items.dm create mode 100644 code/modules/loadout/loadout_menu.dm create mode 100644 code/modules/loadout/loadout_preference.dm delete mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png delete mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png delete mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png delete mode 100644 code/modules/unit_tests/~skyrat/loadout_dupes.dm create mode 100644 modular_skyrat/master_files/code/modules/loadout/categories/accessories.dm rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_belts.dm => master_files/code/modules/loadout/categories/belts.dm} (67%) rename modular_skyrat/{modules/loadouts/loadout_items/donator/personal => master_files/code/modules/loadout/categories}/donator_personal.dm (100%) create mode 100644 modular_skyrat/master_files/code/modules/loadout/categories/ears.dm rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_glasses.dm => master_files/code/modules/loadout/categories/glasses.dm} (86%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_gloves.dm => master_files/code/modules/loadout/categories/gloves.dm} (75%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_heads.dm => master_files/code/modules/loadout/categories/heads.dm} (87%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_inhands.dm => master_files/code/modules/loadout/categories/inhands.dm} (63%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_masks.dm => master_files/code/modules/loadout/categories/mask.dm} (84%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_neck.dm => master_files/code/modules/loadout/categories/neck.dm} (86%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_pocket.dm => master_files/code/modules/loadout/categories/pocket.dm} (99%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_shoes.dm => master_files/code/modules/loadout/categories/shoes.dm} (89%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_suit.dm => master_files/code/modules/loadout/categories/suit.dm} (96%) rename modular_skyrat/{modules/loadouts/loadout_items/loadout_datum_toys.dm => master_files/code/modules/loadout/categories/toys.dm} (96%) rename modular_skyrat/{modules/loadouts/loadout_items/under/loadout_datum_under.dm => master_files/code/modules/loadout/categories/uniform.dm} (64%) delete mode 100644 modular_skyrat/modules/loadouts/loadout_items/_loadout_datum.dm delete mode 100644 modular_skyrat/modules/loadouts/loadout_items/loadout_datum_accessory.dm delete mode 100644 modular_skyrat/modules/loadouts/loadout_items/loadout_datum_ears.dm delete mode 100644 modular_skyrat/modules/loadouts/loadout_items/under/donator.dm delete mode 100644 modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm delete mode 100644 modular_skyrat/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm delete mode 100644 modular_skyrat/modules/loadouts/readme.md create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ModifyPanel.tsx create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/loadout/index.tsx delete mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 42672bed044eb..6fc12601d7f7a 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -143,3 +143,17 @@ /// The key used for sprite accessories that should never actually be applied to the player. #define SPRITE_ACCESSORY_NONE "None" + +// Loadout +/// Used to make something not recolorable even if it's capable +#define DONT_GREYSCALE -1 +// Loadout item info keys +// Changing these will break existing loadouts +/// Tracks GAGS color information +#define INFO_GREYSCALE "greyscale" +/// Used to set custom names +#define INFO_NAMED "name" +/// Used for specific alt-reskins, like the pride pin +#define INFO_RESKIN "reskin" +/// Handles which layer the item will be on, for accessories +#define INFO_LAYER "layer" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 62556c7c9f921..4dda0ba34f990 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1153,4 +1153,17 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Does this item bypass ranged armor checks? #define TRAIT_BYPASS_RANGED_ARMOR "bypass_ranged_armor" +/// Traits given by settler, each with their own specific effects for cases where someone would have that trait, but not the other settler effects + +#define TRAIT_EXPERT_FISHER "expert_fisher" // fishing is easier +#define TRAIT_ROUGHRIDER "roughrider" // you can improve speed on mounted animals with a good mood +#define TRAIT_STUBBY_BODY "stubby_body" // you have a stubby body that lessens your agility +#define TRAIT_BEAST_EMPATHY "beast_empathy" // you're good with animals, such as with taming them +#define TRAIT_STURDY_FRAME "sturdy_frame" // you suffer much lesser effects from equipment that slows you down + +/// This item cannot be selected for or used by a theft objective (Spies, Traitors, etc.) +#define TRAIT_ITEM_OBJECTIVE_BLOCKED "item_objective_blocked" +/// This trait lets you attach limbs to any player without surgery. +#define TRAIT_EASY_ATTACH "easy_attach" + // END TRAIT DEFINES diff --git a/code/__DEFINES/~skyrat_defines/loadout.dm b/code/__DEFINES/~skyrat_defines/loadout.dm new file mode 100644 index 0000000000000..9ef84f7911a9e --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/loadout.dm @@ -0,0 +1,9 @@ +/// Defines for extra info blurbs, for loadout items. +#define TOOLTIP_NO_ARMOR "ARMORLESS" +#define TOOLTIP_NO_DAMAGE "CEREMONIAL" +#define TOOLTIP_RANDOM_COLOR "RANDOM COLOR" +#define TOOLTIP_GREYSCALE "GREYSCALED" + +#define LOADOUT_OVERRIDE_JOB "Delete job items" +#define LOADOUT_OVERRIDE_BACKPACK "Move job to backpack" +#define LOADOUT_OVERRIDE_CASE "Place all in case" diff --git a/code/__DEFINES/~skyrat_defines/loadouts.dm b/code/__DEFINES/~skyrat_defines/loadouts.dm deleted file mode 100644 index 5bb359f8f77e5..0000000000000 --- a/code/__DEFINES/~skyrat_defines/loadouts.dm +++ /dev/null @@ -1,33 +0,0 @@ -/// Defines for what loadout slot a corresponding item belongs to. -#define LOADOUT_ITEM_BELT "belt" -#define LOADOUT_ITEM_EARS "ears" -#define LOADOUT_ITEM_GLASSES "glasses" -#define LOADOUT_ITEM_GLOVES "gloves" -#define LOADOUT_ITEM_HEAD "head" -#define LOADOUT_ITEM_MASK "mask" -#define LOADOUT_ITEM_NECK "neck" -#define LOADOUT_ITEM_SHOES "shoes" -#define LOADOUT_ITEM_SUIT "suit" -#define LOADOUT_ITEM_UNIFORM "under" -#define LOADOUT_ITEM_ACCESSORY "accessory" -#define LOADOUT_ITEM_INHAND "inhand_items" -#define LOADOUT_ITEM_MISC "pocket_items" -#define LOADOUT_ITEM_TOYS "toys" - -#define INFO_GREYSCALE "greyscale" -#define INFO_NAMED "name" -#define INFO_DESCRIBED "description" - -/// Max amonut of misc / backpack items that are allowed. -#define MAX_ALLOWED_MISC_ITEMS 3 - -/// Defines for extra info blurbs, for loadout items. -#define TOOLTIP_NO_ARMOR "ARMORLESS - This item has no armor and is entirely cosmetic." -#define TOOLTIP_NO_DAMAGE "CEREMONIAL - This item has very low force and is cosmetic." -#define TOOLTIP_RANDOM_COLOR "RANDOM COLOR -This item has a random color and will change every round." -#define TOOLTIP_GREYSCALE "GREYSCALED - This item can be customized via the greyscale modification UI." -#define TOOLTIP_RENAMABLE "RENAMABLE - This item can be given a custom name." - -#define LOADOUT_OVERRIDE_JOB "Delete job items" -#define LOADOUT_OVERRIDE_BACKPACK "Move job to backpack" -#define LOADOUT_OVERRIDE_CASE "Place all in case" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 81c399865262c..6f4bbf8aa8b4b 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -526,6 +526,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_HAUNTED" = TRAIT_HAUNTED, "TRAIT_HONKSPAMMING" = TRAIT_HONKSPAMMING, "TRAIT_INNATELY_FANTASTICAL_ITEM" = TRAIT_INNATELY_FANTASTICAL_ITEM, + "TRAIT_ITEM_OBJECTIVE_BLOCKED" = TRAIT_ITEM_OBJECTIVE_BLOCKED, "TRAIT_NEEDS_TWO_HANDS" = TRAIT_NEEDS_TWO_HANDS, "TRAIT_NO_BARCODES" = TRAIT_NO_BARCODES, "TRAIT_NO_STORAGE_INSERT" = TRAIT_NO_STORAGE_INSERT, diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 8f50cc02b1244..c0cd22f529355 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -568,7 +568,7 @@ SUBSYSTEM_DEF(job) SEND_SIGNAL(equipping, COMSIG_JOB_RECEIVED, job) equipping.mind?.set_assigned_role_with_greeting(job, player_client, alt_title) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - ORIGINAL: equipping.mind?.set_assigned_role_with_greeting(job, player_client) - equipping.on_job_equipping(job, player_client?.prefs, player_client) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - ORIGINAL: equipping.on_job_equipping(job) + equipping.on_job_equipping(job, player_client) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - ORIGINAL: equipping.on_job_equipping(job) job.announce_job(equipping, alt_title) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - ORIGINAL: job.announce_job(equipping) if(player_client?.holder) diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 3813a3592c1f3..9b258a82b4f0d 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -10,7 +10,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/no_taste, /datum/quirk/vegetarian, /datum/quirk/deviant_tastes, /datum/quirk/gamer), list(/datum/quirk/pineapple_liker, /datum/quirk/pineapple_hater, /datum/quirk/gamer), list(/datum/quirk/alcohol_tolerance, /datum/quirk/light_drinker), - list(/datum/quirk/item_quirk/clown_enjoyer, /datum/quirk/item_quirk/mime_fan, /datum/quirk/item_quirk/pride_pin), + list(/datum/quirk/item_quirk/clown_enjoyer, /datum/quirk/item_quirk/mime_fan), list(/datum/quirk/bad_touch, /datum/quirk/friendly), list(/datum/quirk/extrovert, /datum/quirk/introvert), list(/datum/quirk/prosthetic_limb, /datum/quirk/quadruple_amputee, /datum/quirk/transhumanist, /datum/quirk/body_purist), diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 2e2fd930ba123..2885a087df829 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -457,13 +457,6 @@ SUBSYSTEM_DEF(ticker) new_player_mob.client.prefs.hardcore_random_setup(new_player_living) SSquirks.AssignQuirks(new_player_living, new_player_mob.client) - //SKYRAT EDIT ADDITION - if(ishuman(new_player_living)) - for(var/datum/loadout_item/item as anything in loadout_list_to_datums(new_player_mob.client?.prefs?.loadout_list)) - if (item.restricted_roles && length(item.restricted_roles) && !(player_assigned_role.title in item.restricted_roles)) - continue - item.post_equip_item(new_player_mob.client?.prefs, new_player_living) - //SKYRAT EDIT END CHECK_TICK if(captainless) diff --git a/code/datums/quirks/neutral_quirks/pride_pin.dm b/code/datums/quirks/neutral_quirks/pride_pin.dm deleted file mode 100644 index 488c0a2bccb58..0000000000000 --- a/code/datums/quirks/neutral_quirks/pride_pin.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/quirk/item_quirk/pride_pin - name = "Pride Pin" - desc = "Show off your pride with this changing pride pin!" - icon = FA_ICON_RAINBOW - value = 0 - gain_text = span_notice("You feel fruity.") - lose_text = span_danger("You feel only slightly less fruity than before.") - medical_record_text = "Patient appears to be fruity." - -/datum/quirk/item_quirk/pride_pin/add_unique(client/client_source) - var/obj/item/clothing/accessory/pride/pin = new(get_turf(quirk_holder)) - - var/pride_choice = client_source?.prefs?.read_preference(/datum/preference/choiced/pride_pin) || assoc_to_keys(GLOB.pride_pin_reskins)[1] - var/pride_reskin = GLOB.pride_pin_reskins[pride_choice] - - pin.current_skin = pride_choice - pin.icon_state = pride_reskin - - give_item_to_holder(pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index a67e48f041c4e..21b2da3b9c70d 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(objectives) //SKYRAT EDIT ADDITION var/name = "generic objective" //Name for admin prompts var/explanation_text = "Nothing" //What that person is supposed to do. ///if this objective doesn't print failure or success in the roundend report - var/no_failure = FALSE + var/no_failure = FALSE ///name used in printing this objective (Objective #1) var/objective_name = "Objective" var/team_explanation_text //For when there are multiple owners. @@ -699,6 +699,9 @@ GLOBAL_LIST_EMPTY(possible_items) var/list/all_items = M.current.get_all_contents() //this should get things in cheesewheels, books, etc. for(var/obj/I in all_items) //Check for items + if(HAS_TRAIT(I, TRAIT_ITEM_OBJECTIVE_BLOCKED)) + continue + if(istype(I, steal_target)) if(!targetinfo) //If there's no targetinfo, then that means it was a custom objective. At this point, we know you have the item, so return 1. return TRUE diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 3dddc560e6a8d..2e82e549cd5b4 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -5,7 +5,7 @@ //Contains the target item datums for Steal objectives. /datum/objective_item /// How the item is described in the objective - var/name = "A silly bike horn! Honk!" + var/name = "a silly bike horn! Honk!" /// Typepath of item var/targetitem = /obj/item/bikehorn /// Valid containers that the target item can be in. @@ -570,7 +570,7 @@ // A number of special early-game steal objectives intended to be used with the steal-and-destroy objective. // They're basically items of utility or emotional value that may be found on many players or lying around the station. /datum/objective_item/steal/traitor/insuls - name = "insulated gloves" + name = "some insulated gloves" targetitem = /obj/item/clothing/gloves/color/yellow excludefromjob = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER, JOB_ATMOSPHERIC_TECHNICIAN, JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) item_owner = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) @@ -582,7 +582,7 @@ return add_item_to_steal(src, /obj/item/clothing/gloves/color/yellow) /datum/objective_item/steal/traitor/moth_plush - name = "cute moth plush toy" + name = "a cute moth plush toy" targetitem = /obj/item/toy/plush/moth excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) exists_on_map = TRUE @@ -593,7 +593,7 @@ return add_item_to_steal(src, /obj/item/toy/plush/moth) /datum/objective_item/steal/traitor/lizard_plush - name = "cute lizard plush toy" + name = "a cute lizard plush toy" targetitem = /obj/item/toy/plush/lizard_plushie exists_on_map = TRUE difficulty = 1 @@ -637,7 +637,7 @@ return add_item_to_steal(src, /obj/item/book/manual/wiki/security_space_law) /datum/objective_item/steal/traitor/rpd - name = "rapid pipe dispenser" + name = "a rapid pipe dispenser" targetitem = /obj/item/pipe_dispenser excludefromjob = list( JOB_ATMOSPHERIC_TECHNICIAN, @@ -683,7 +683,7 @@ objective_type = OBJECTIVE_ITEM_TYPE_SPY /datum/objective_item/steal/spy/lamarr - name = "The Research Director's pet headcrab" + name = "the Research Director's pet headcrab" targetitem = /obj/item/clothing/mask/facehugger/lamarr excludefromjob = list(JOB_RESEARCH_DIRECTOR) exists_on_map = TRUE @@ -813,7 +813,7 @@ return add_item_to_steal(src, /obj/item/stamp/head) /datum/objective_item/steal/spy/sunglasses - name = "sunglasses" + name = "some sunglasses" targetitem = /obj/item/clothing/glasses/sunglasses excludefromjob = list( JOB_CAPTAIN, @@ -832,7 +832,7 @@ You can also obtain a pair from dissassembling hudglasses." /datum/objective_item/steal/spy/ce_modsuit - name = "the cheif engineer's advanced MOD control unit" + name = "the chief engineer's advanced MOD control unit" targetitem = /obj/item/mod/control/pre_equipped/advanced excludefromjob = list(JOB_CHIEF_ENGINEER) exists_on_map = TRUE diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 3d3c975102f26..c56e1eb7cdc15 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -532,6 +532,11 @@ desc = "An adorable stuffed toy that resembles a green lizardperson. This one fills you with nostalgia and soul." greyscale_colors = "#66ff33#000000" +/obj/item/toy/plush/lizard_plushie/greyscale + desc = "An adorable stuffed toy that resembles a lizardperson. This one has been custom made." + greyscale_colors = "#d3d3d3#000000" + flags_1 = IS_PLAYER_COLORABLE_1 + /obj/item/toy/plush/lizard_plushie/space name = "space lizard plushie" desc = "An adorable stuffed toy that resembles a very determined spacefaring lizardperson. To infinity and beyond, little guy." diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 69dd533e0975a..809413e27963f 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -210,10 +210,11 @@ ADMIN_VERB(create_mapping_job_icons, R_DEBUG, "Generate job landmarks icons", "G for(var/obj/item/I in D) qdel(I) randomize_human(D) - // SKYRAT EDIT CHANGE START - ORIGINAL: D.dress_up_as_job(JB, TRUE) - if(JB.outfit) - D.equipOutfit(JB.outfit, TRUE) - // SKYRAT EDIT CHANGE END + D.dress_up_as_job( + equipping = JB, + visual_only = TRUE, + consistent = TRUE, + ) var/icon/I = icon(getFlatIcon(D), frame = 1) job_key_to_icon[JB.title] = I // SKYRAT EDIT CHANGE - ORIGINAL: final.Insert(I, JB.title) qdel(D) diff --git a/code/modules/antagonists/spy/spy_bounty.dm b/code/modules/antagonists/spy/spy_bounty.dm index 0a9422e07b807..28984ce2272bd 100644 --- a/code/modules/antagonists/spy/spy_bounty.dm +++ b/code/modules/antagonists/spy/spy_bounty.dm @@ -219,6 +219,8 @@ continue if(!is_station_level(thing_turf.z) && !is_mining_level(thing_turf.z)) continue + if(HAS_TRAIT(existing_thing, TRAIT_ITEM_OBJECTIVE_BLOCKED)) + continue all_valid_existing_things += existing_thing if(!length(all_valid_existing_things)) @@ -253,16 +255,14 @@ return FALSE desired_item = pick(valid_possible_items) - // We need to do some snowflake for items that do exist vs generic items - var/list/obj/item/existing_items = GLOB.steal_item_handler.objectives_by_path[desired_item.targetitem] - var/obj/item/the_item = length(existing_items) ? pick(existing_items) : desired_item.targetitem - var/the_item_name = istype(the_item) ? the_item.name : initial(the_item.name) - name = "[the_item_name] [difficulty == SPY_DIFFICULTY_HARD ? "Grand ":""]Theft" - help = "Steal any [the_item_name][desired_item.steal_hint ? ": [desired_item.steal_hint]" : "."]" + name = "[desired_item.name] [difficulty == SPY_DIFFICULTY_HARD ? "Grand ":""]Theft" + help = "Steal [desired_item.name][desired_item.steal_hint ? ": [desired_item.steal_hint]" : "."]" return TRUE /datum/spy_bounty/objective_item/is_stealable(atom/movable/stealing) - return istype(stealing, desired_item.targetitem) && desired_item.check_special_completion(stealing) + return istype(stealing, desired_item.targetitem) \ + && !HAS_TRAIT(stealing, TRAIT_ITEM_OBJECTIVE_BLOCKED) \ + && desired_item.check_special_completion(stealing) /datum/spy_bounty/objective_item/random_easy difficulty = SPY_DIFFICULTY_EASY diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index b8e62beefea0b..fdcd693fed889 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -29,6 +29,8 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /datum/objective_item_handler/proc/new_item_created(datum/source, obj/item/item) SIGNAL_HANDLER + if(HAS_TRAIT(item, TRAIT_ITEM_OBJECTIVE_BLOCKED)) + return if(!generated_items) item.add_stealing_item_objective() return @@ -224,6 +226,8 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /datum/traitor_objective/steal_item/proc/handle_special_case(obj/item/source, obj/item/target) SIGNAL_HANDLER + if(HAS_TRAIT(target, TRAIT_ITEM_OBJECTIVE_BLOCKED)) + return COMPONENT_FORCE_FAIL_PLACEMENT if(istype(target, target_item.targetitem)) if(!target_item.check_special_completion(target)) return COMPONENT_FORCE_FAIL_PLACEMENT diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 0942520e73c0a..7b8f81eb3c6b6 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -610,7 +610,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( QDEL_NULL(view_size) QDEL_NULL(void) QDEL_NULL(tooltips) - QDEL_NULL(open_loadout_ui) //SKYRAT EDIT ADDITION QDEL_NULL(loot_panel) QDEL_NULL(parallax_rock) QDEL_LIST(parallax_layers_cached) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index a242e27d21cf0..c38797e811633 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -263,7 +263,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) character_preview_view.dir = turn(character_preview_view.dir, -90) */ // ORIGINAL END - SKYRAT EDIT START: var/backwards = params["backwards"] - character_preview_view.dir = turn(character_preview_view.dir, backwards ? 90 : -90) + character_preview_view.setDir(turn(character_preview_view.dir, backwards ? 90 : -90)) // SKYRAT EDIT END return TRUE @@ -325,16 +325,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) character_preview_view.update_body() return TRUE - if ("open_loadout") - var/datum/loadout_manager/open_loadout_ui = parent.open_loadout_ui?.resolve() - if(open_loadout_ui) - open_loadout_ui.ui_interact(usr) - else - parent.open_loadout_ui = null - var/datum/loadout_manager/tgui = new(usr) - tgui.ui_interact(usr) - return TRUE - if ("open_food") GLOB.food_prefs_menu.ui_interact(usr) return TRUE @@ -454,6 +444,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/mob/living/carbon/human/dummy/body /// The preferences this refers to var/datum/preferences/preferences + /// Whether we show current job clothes or nude/loadout only + var/show_job_clothes = TRUE /atom/movable/screen/map_view/char_preview/Initialize(mapload, datum/preferences/preferences) . = ..() @@ -471,16 +463,14 @@ GLOBAL_LIST_EMPTY(preferences_datums) create_body() else body.wipe_state() - appearance = preferences.render_new_preview_appearance(body) + + appearance = preferences.render_new_preview_appearance(body, show_job_clothes) /atom/movable/screen/map_view/char_preview/proc/create_body() QDEL_NULL(body) body = new - // Without this, it doesn't show up in the menu - body.appearance_flags |= KEEP_TOGETHER // SKYRAT EDIT - Fix pixel scaling - ORIGINAL: body.appearance_flags &= ~KEEP_TOGETHER - /datum/preferences/proc/create_character_profiles() var/list/profiles = list() diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 1f71601ebf0e3..401b4a20bea45 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -18,11 +18,16 @@ /// support the "use gender" option. #define PREFERENCE_PRIORITY_BODY_TYPE 5 +/// Equpping items based on preferences. +/// Should happen after species and body type to make sure it looks right. +/// Mostly redundant, but a safety net for saving/loading. +#define PREFERENCE_PRIORITY_LOADOUT 6 + /// The priority at which names are decided, needed for proper randomization. -#define PREFERENCE_PRIORITY_NAMES 6 +#define PREFERENCE_PRIORITY_NAMES 7 /// Preferences that aren't names, but change the name changes set by PREFERENCE_PRIORITY_NAMES. -#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 7 +#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 8 /// The maximum preference priority, keep this updated, but don't use it for `priority`. #define MAX_PREFERENCE_PRIORITY PREFERENCE_PRIORITY_NAME_MODIFICATIONS diff --git a/code/modules/client/preferences/migrations/quirk_loadout_migration.dm b/code/modules/client/preferences/migrations/quirk_loadout_migration.dm new file mode 100644 index 0000000000000..52fcd993c5732 --- /dev/null +++ b/code/modules/client/preferences/migrations/quirk_loadout_migration.dm @@ -0,0 +1,27 @@ +/** + * Move quirk items into loadout items + * + * If this is accompanied with removal of a quirk, + * you don't need to worry about handling that here - + * quirk sanitization happens AFTER migration + */ +/datum/preferences/proc/migrate_quirk_to_loadout(quirk_to_migrate, new_typepath, list/data_to_migrate) + ASSERT(istext(quirk_to_migrate) && ispath(new_typepath, /obj/item)) + if(quirk_to_migrate in all_quirks) + add_loadout_item(new_typepath, data_to_migrate) + +/// Helper for slotting in a new loadout item +/datum/preferences/proc/add_loadout_item(typepath, list/data = list()) + PRIVATE_PROC(TRUE) + + var/list/loadout_list = read_preference(/datum/preference/loadout) || list() + loadout_list[typepath] = data + write_preference(GLOB.preference_entries[/datum/preference/loadout], loadout_list) + +/// Helper for removing a loadout item +/datum/preferences/proc/remove_loadout_item(typepath) + PRIVATE_PROC(TRUE) + + var/list/loadout_list = read_preference(/datum/preference/loadout) + if(loadout_list?.Remove(typepath)) + write_preference(GLOB.preference_entries[/datum/preference/loadout], loadout_list) diff --git a/code/modules/client/preferences/pride_pin.dm b/code/modules/client/preferences/pride_pin.dm deleted file mode 100644 index 326dad69979b4..0000000000000 --- a/code/modules/client/preferences/pride_pin.dm +++ /dev/null @@ -1,16 +0,0 @@ -/datum/preference/choiced/pride_pin - category = PREFERENCE_CATEGORY_SECONDARY_FEATURES - savefile_key = "pride_pin" - savefile_identifier = PREFERENCE_CHARACTER - -/datum/preference/choiced/pride_pin/init_possible_values() - return assoc_to_keys(GLOB.pride_pin_reskins) - -/datum/preference/choiced/pride_pin/is_accessible(datum/preferences/preferences) - if (!..(preferences)) - return FALSE - - return "Pride Pin" in preferences.all_quirks - -/datum/preference/choiced/pride_pin/apply_to_human(mob/living/carbon/human/target, value) - return diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index e9eb42c3551e9..698f420a9ef18 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 44 +#define SAVEFILE_VERSION_MAX 45 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -105,6 +105,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if (current_version < 43) migrate_legacy_sound_toggles(savefile) + if (current_version < 45) + migrate_quirk_to_loadout( + quirk_to_migrate = "Pride Pin", + new_typepath = /obj/item/clothing/accessory/pride, + data_to_migrate = list(INFO_RESKIN = save_data?["pride_pin"]), + ) + /// checks through keybindings for outdated unbound keys and updates them /datum/preferences/proc/check_keybindings() if(!parent) diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index eeb7f1653f357..15929ac5f0673 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -84,6 +84,8 @@ name = "flat cap" desc = "A working man's cap." icon_state = "beret_flat" + icon_preview = 'icons/obj/clothing/head/beret.dmi' + icon_state_preview = "beret_flat" greyscale_config = /datum/greyscale_config/beret greyscale_config_worn = /datum/greyscale_config/beret/worn greyscale_colors = "#8F7654" diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 97d31e1d4e6a3..53f08faaa1278 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -310,7 +310,7 @@ else balloon_alert(wearer, "can't put in hands!") break - + return . /obj/item/clothing/head/fedora/inspector_hat/attackby(obj/item/item, mob/user, params) @@ -385,6 +385,8 @@ name = "beret" desc = "A beret, a mime's favorite headwear." icon_state = "beret" + icon_preview = 'icons/obj/clothing/head/beret.dmi' + icon_state_preview = "beret" dog_fashion = /datum/dog_fashion/head/beret greyscale_config = /datum/greyscale_config/beret greyscale_config_worn = /datum/greyscale_config/beret/worn diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index d89b2169d287d..3ea26de01c554 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -398,6 +398,8 @@ /obj/item/clothing/neck/large_scarf name = "large scarf" icon_state = "large_scarf" + icon_preview = 'icons/obj/fluff/previews.dmi' + icon_state_preview = "scarf_large" w_class = WEIGHT_CLASS_TINY custom_price = PAYCHECK_CREW greyscale_colors = "#C6C6C6#EEEEEE" diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index 5b2bda984168b..0ea3922893a76 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -175,28 +175,23 @@ name = "Pre-Approved Cyborg Candidate dogtag" display = "This employee has been screened for negative mental traits to an acceptable level of accuracy, and is approved for the NT Cyborg program as an alternative to medical resuscitation." -/* MODULAR SKYRAT - OVERRIDDEN IN (\modular_skyrat\modules\customization\modules\clothing\under\accessories.dm) -/// Reskins for the pride pin accessory, mapped by display name to icon state -GLOBAL_LIST_INIT(pride_pin_reskins, list( - "Rainbow Pride" = "pride", - "Bisexual Pride" = "pride_bi", - "Pansexual Pride" = "pride_pan", - "Asexual Pride" = "pride_ace", - "Non-binary Pride" = "pride_enby", - "Transgender Pride" = "pride_trans", - "Intersex Pride" = "pride_intersex", - "Lesbian Pride" = "pride_lesbian", -)) -*/ - /obj/item/clothing/accessory/pride name = "pride pin" desc = "A Nanotrasen Diversity & Inclusion Center-sponsored holographic pin to show off your pride, reminding the crew of their unwavering commitment to equity, diversity, and inclusion!" icon_state = "pride" obj_flags = UNIQUE_RENAME | INFINITE_RESKIN + unique_reskin = list( + "Rainbow Pride" = "pride", + "Bisexual Pride" = "pride_bi", + "Pansexual Pride" = "pride_pan", + "Asexual Pride" = "pride_ace", + "Non-binary Pride" = "pride_enby", + "Transgender Pride" = "pride_trans", + "Intersex Pride" = "pride_intersex", + "Lesbian Pride" = "pride_lesbian", + ) /obj/item/clothing/accessory/pride/setup_reskinning() - unique_reskin = GLOB.pride_pin_reskins if(!check_setup_reskinning()) return diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 40ea10b900220..0b8c28d370f16 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -182,7 +182,7 @@ spawned_human.mind.adjust_experience(i, roundstart_experience[i], TRUE) /// Return the outfit to use -/datum/job/proc/get_outfit() +/datum/job/proc/get_outfit(consistent) return outfit /// Announce that this job as joined the round to all crew members. @@ -197,12 +197,12 @@ return TRUE -/mob/living/proc/on_job_equipping(datum/job/equipping) +/mob/living/proc/on_job_equipping(datum/job/equipping, client/player_client) return #define VERY_LATE_ARRIVAL_TOAST_PROB 20 -/mob/living/carbon/human/on_job_equipping(datum/job/equipping, datum/preferences/used_pref, client/player_client) //SKYRAT EDIT CHANGE - ORIGINAL: /mob/living/carbon/human/on_job_equipping(datum/job/equipping) +/mob/living/carbon/human/on_job_equipping(datum/job/equipping, client/player_client) if(equipping.paycheck_department) var/datum/bank_account/bank_account = new(real_name, equipping, dna.species.payday_modifier) bank_account.payday(STARTING_PAYCHECKS, TRUE) @@ -210,7 +210,12 @@ bank_account.replaceable = FALSE add_mob_memory(/datum/memory/key/account, remembered_id = account_id) - dress_up_as_job(equipping, FALSE, used_pref) //SKYRAT EDIT CHANGE - ORIGINAL: dress_up_as_job(equipping) + dress_up_as_job( + equipping = equipping, + visual_only = FALSE, + player_client = player_client, + consistent = FALSE, + ) if(EMERGENCY_PAST_POINT_OF_NO_RETURN && prob(VERY_LATE_ARRIVAL_TOAST_PROB)) //equipping.equip_to_slot_or_del(new /obj/item/food/griddle_toast(equipping), ITEM_SLOT_MASK) // SKYRAT EDIT REMOVAL - See below @@ -223,12 +228,12 @@ #undef VERY_LATE_ARRIVAL_TOAST_PROB -/mob/living/proc/dress_up_as_job(datum/job/equipping, visual_only = FALSE) +/mob/living/proc/dress_up_as_job(datum/job/equipping, visual_only = FALSE, client/player_client, consistent = FALSE) return -/mob/living/carbon/human/dress_up_as_job(datum/job/equipping, visual_only = FALSE, datum/preferences/used_pref) //SKYRAT EDIT CHANGE +/mob/living/carbon/human/dress_up_as_job(datum/job/equipping, visual_only = FALSE, client/player_client, consistent = FALSE) dna.species.pre_equip_species_outfit(equipping, src, visual_only) - equip_outfit_and_loadout(equipping.get_outfit(), used_pref, visual_only, equipping) //SKYRAT EDIT CHANGE + equip_outfit_and_loadout(equipping.get_outfit(consistent), player_client?.prefs, visual_only, equipping) // SKYRAT EDIT CHANGE - Add equipping param // Original: /datum/job/proc/announce_head(mob/living/carbon/human/H, channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. /datum/job/proc/announce_head(mob/living/carbon/human/H, channels, job_title) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES diff --git a/code/modules/jobs/job_types/assistant/assistant.dm b/code/modules/jobs/job_types/assistant/assistant.dm index 45c439c195723..4e25f6a35b40c 100644 --- a/code/modules/jobs/job_types/assistant/assistant.dm +++ b/code/modules/jobs/job_types/assistant/assistant.dm @@ -37,7 +37,9 @@ Assistant rpg_title = "Lout" config_tag = "ASSISTANT" -/datum/job/assistant/get_outfit() +/datum/job/assistant/get_outfit(consistent) + if(consistent) + return /datum/outfit/job/assistant/consistent if(!HAS_TRAIT(SSstation, STATION_TRAIT_ASSISTANT_GIMMICKS)) return ..() diff --git a/code/modules/loadout/categories/accessories.dm b/code/modules/loadout/categories/accessories.dm new file mode 100644 index 0000000000000..4a180bc3745f6 --- /dev/null +++ b/code/modules/loadout/categories/accessories.dm @@ -0,0 +1,94 @@ +/// Accessory Items (Moves overrided items to backpack) +/datum/loadout_category/accessories + category_name = "Accessory" + category_ui_icon = FA_ICON_VEST + type_to_generate = /datum/loadout_item/accessory + tab_order = /datum/loadout_category/head::tab_order + 3 + +/datum/loadout_item/accessory + abstract_type = /datum/loadout_item/accessory + /// Can we adjust this accessory to be above or below suits? + VAR_FINAL/can_be_layer_adjusted = FALSE + +/datum/loadout_item/accessory/New() + . = ..() + if(ispath(item_path, /obj/item/clothing/accessory)) + can_be_layer_adjusted = TRUE + +/datum/loadout_item/accessory/get_ui_buttons() + if(!can_be_layer_adjusted) + return ..() + + var/list/buttons = ..() + + UNTYPED_LIST_ADD(buttons, list( + "label" = "Layer", + "act_key" = "set_layer", + "active_key" = INFO_LAYER, + "active_text" = "Above Suit", + "inactive_text" = "Below Suit", + )) + + return buttons + +/datum/loadout_item/accessory/handle_loadout_action(datum/preference_middleware/loadout/manager, mob/user, action, params) + if(action == "set_layer") + return set_accessory_layer(manager, user) + + return ..() + +/datum/loadout_item/accessory/proc/set_accessory_layer(datum/preference_middleware/loadout/manager, mob/user) + if(!can_be_layer_adjusted) + return FALSE + + var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout) + if(!loadout?[item_path]) + return FALSE + + if(isnull(loadout[item_path][INFO_LAYER])) + loadout[item_path][INFO_LAYER] = FALSE + + loadout[item_path][INFO_LAYER] = !loadout[item_path][INFO_LAYER] + manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + return TRUE // Update UI + +/datum/loadout_item/accessory/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, loadout_placement_preference) // SKYRAT EDIT CHANGE - Added loadout_placement_preference + // SKYRAT EDIT CHANGE + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.accessory) + LAZYADD(outfit.backpack_contents, outfit.accessory) + // SKYRAT EDIT END + outfit.accessory = item_path + +/datum/loadout_item/accessory/on_equip_item( + obj/item/clothing/accessory/equipped_item, + datum/preferences/preference_source, + list/preference_list, + mob/living/carbon/human/equipper, + visuals_only = FALSE, +) + . = ..() + if(istype(equipped_item)) + equipped_item.above_suit = !!preference_list[item_path]?[INFO_LAYER] + . |= (ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) + +/datum/loadout_item/accessory/maid_apron + name = "Maid Apron" + item_path = /obj/item/clothing/accessory/maidapron + +/datum/loadout_item/accessory/waistcoat + name = "Waistcoat" + item_path = /obj/item/clothing/accessory/waistcoat + +/datum/loadout_item/accessory/pocket_protector + name = "Pocket Protector" + item_path = /obj/item/clothing/accessory/pocketprotector + +/datum/loadout_item/accessory/full_pocket_protector + name = "Pocket Protector (Filled)" + item_path = /obj/item/clothing/accessory/pocketprotector/full + additional_displayed_text = list("Contains pens") + +/datum/loadout_item/accessory/pride + name = "Pride Pin" + item_path = /obj/item/clothing/accessory/pride + can_be_reskinned = TRUE diff --git a/code/modules/loadout/categories/glasses.dm b/code/modules/loadout/categories/glasses.dm new file mode 100644 index 0000000000000..75c16e74d45a6 --- /dev/null +++ b/code/modules/loadout/categories/glasses.dm @@ -0,0 +1,57 @@ +/// Glasses Slot Items (Moves overrided items to backpack) +/datum/loadout_category/glasses + category_name = "Glasses" + category_ui_icon = FA_ICON_GLASSES + type_to_generate = /datum/loadout_item/glasses + tab_order = /datum/loadout_category/head::tab_order + 1 + +/datum/loadout_item/glasses + abstract_type = /datum/loadout_item/glasses + +/datum/loadout_item/glasses/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, loadout_placement_preference) // SKYRAT EDIT CHANGE - Added loadout_placement + // SKYRAT EDIT CHANGE + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.glasses) + LAZYADD(outfit.backpack_contents, outfit.glasses) + // SKYRAT EDIT END + outfit.glasses = item_path + +/datum/loadout_item/glasses/prescription_glasses + name = "Glasses" + item_path = /obj/item/clothing/glasses/regular + additional_displayed_text = list("Prescription") + +/datum/loadout_item/glasses/prescription_glasses/circle_glasses + name = "Circle Glasses" + item_path = /obj/item/clothing/glasses/regular/circle + +/datum/loadout_item/glasses/prescription_glasses/hipster_glasses + name = "Hipster Glasses" + item_path = /obj/item/clothing/glasses/regular/hipster + +/datum/loadout_item/glasses/prescription_glasses/jamjar_glasses + name = "Jamjar Glasses" + item_path = /obj/item/clothing/glasses/regular/jamjar + +/datum/loadout_item/glasses/black_blindfold + name = "Black Blindfold" + item_path = /obj/item/clothing/glasses/blindfold + +/datum/loadout_item/glasses/cold_glasses + name = "Cold Glasses" + item_path = /obj/item/clothing/glasses/cold + +/datum/loadout_item/glasses/heat_glasses + name = "Heat Glasses" + item_path = /obj/item/clothing/glasses/heat + +/datum/loadout_item/glasses/orange_glasses + name = "Orange Glasses" + item_path = /obj/item/clothing/glasses/orange + +/datum/loadout_item/glasses/red_glasses + name = "Red Glasses" + item_path = /obj/item/clothing/glasses/red + +/datum/loadout_item/glasses/eyepatch + name = "Eyepatch" + item_path = /obj/item/clothing/glasses/eyepatch diff --git a/code/modules/loadout/categories/heads.dm b/code/modules/loadout/categories/heads.dm new file mode 100644 index 0000000000000..5d491cc63c558 --- /dev/null +++ b/code/modules/loadout/categories/heads.dm @@ -0,0 +1,142 @@ +/// Head Slot Items (Deletes overrided items) +/datum/loadout_category/head + category_name = "Head" + category_ui_icon = FA_ICON_HAT_COWBOY + type_to_generate = /datum/loadout_item/head + tab_order = 1 + +/datum/loadout_item/head + abstract_type = /datum/loadout_item/head + +/datum/loadout_item/head/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, loadout_placement_preference) // SKYRAT EDIT CHANGE - Added loadout_placement_preference + if(equipper.dna?.species?.outfit_important_for_life) + if(!visuals_only) + to_chat(equipper, "Your loadout helmet was not equipped directly due to your species outfit.") + LAZYADD(outfit.backpack_contents, item_path) + else + // SKYRAT EDIT ADDITION + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.head) + LAZYADD(outfit.backpack_contents, outfit.head) + // SKYRAT EDIT END + outfit.head = item_path + +/datum/loadout_item/head/beanie + name = "Beanie (Colorable)" + item_path = /obj/item/clothing/head/beanie + +/datum/loadout_item/head/fancy_cap + name = "Fancy Hat (Colorable)" + item_path = /obj/item/clothing/head/costume/fancy + +/datum/loadout_item/head/red_beret + name = "Red Beret (Colorable)" + item_path = /obj/item/clothing/head/beret + +/datum/loadout_item/head/black_cap + name = "Cap (Black)" + item_path = /obj/item/clothing/head/soft/black + +/datum/loadout_item/head/blue_cap + name = "Cap (Blue)" + item_path = /obj/item/clothing/head/soft/blue + +/datum/loadout_item/head/delinquent_cap + name = "Cap (Delinquent)" + item_path = /obj/item/clothing/head/costume/delinquent + +/datum/loadout_item/head/green_cap + name = "Cap (Green)" + item_path = /obj/item/clothing/head/soft/green + +/datum/loadout_item/head/grey_cap + name = "Cap (Grey)" + item_path = /obj/item/clothing/head/soft/grey + +/datum/loadout_item/head/orange_cap + name = "Cap (Orange)" + item_path = /obj/item/clothing/head/soft/orange + +/datum/loadout_item/head/purple_cap + name = "Cap (Purple)" + item_path = /obj/item/clothing/head/soft/purple + +/datum/loadout_item/head/rainbow_cap + name = "Cap (Rainbow)" + item_path = /obj/item/clothing/head/soft/rainbow + +/datum/loadout_item/head/red_cap + name = "Cap (Red)" + item_path = /obj/item/clothing/head/soft/red + +/datum/loadout_item/head/white_cap + name = "Cap (White)" + item_path = /obj/item/clothing/head/soft + +/datum/loadout_item/head/yellow_cap + name = "Cap (Yellow)" + item_path = /obj/item/clothing/head/soft/yellow + +/datum/loadout_item/head/flatcap + name = "Cap (Flat)" + item_path = /obj/item/clothing/head/flatcap + +/datum/loadout_item/head/beige_fedora + name = "Fedora (Beige)" + item_path = /obj/item/clothing/head/fedora/beige + +/datum/loadout_item/head/black_fedora + name = "Fedora (Black)" + item_path = /obj/item/clothing/head/fedora + +/datum/loadout_item/head/white_fedora + name = "Fedora (White)" + item_path = /obj/item/clothing/head/fedora/white + +/datum/loadout_item/head/mail_cap + name = "Cap (Mail)" + item_path = /obj/item/clothing/head/costume/mailman + +/datum/loadout_item/head/kitty_ears + name = "Kitty Ears" + item_path = /obj/item/clothing/head/costume/kitty + +/datum/loadout_item/head/rabbit_ears + name = "Rabbit Ears" + item_path = /obj/item/clothing/head/costume/rabbitears + +/datum/loadout_item/head/bandana + name = "Bandana Thin" + item_path = /obj/item/clothing/head/costume/tmc + +/datum/loadout_item/head/rastafarian + name = "Cap (Rastafarian)" + item_path = /obj/item/clothing/head/rasta + +/datum/loadout_item/head/top_hat + name = "Top Hat" + item_path = /obj/item/clothing/head/hats/tophat + +/datum/loadout_item/head/bowler_hat + name = "Bowler Hat" + item_path = /obj/item/clothing/head/hats/bowler + +/datum/loadout_item/head/bear_pelt + name = "Bear Pelt" + item_path = /obj/item/clothing/head/costume/bearpelt + +/datum/loadout_item/head/ushanka + name ="Ushanka" + item_path = /obj/item/clothing/head/costume/ushanka + +/datum/loadout_item/head/plague_doctor + name = "Cap (Plague Doctor)" + item_path = /obj/item/clothing/head/bio_hood/plague + +/datum/loadout_item/head/rose + name = "Rose" + item_path = /obj/item/food/grown/rose + +/datum/loadout_item/head/wig + name = "Wig" + item_path = /obj/item/clothing/head/wig/natural + additional_displayed_text = list("Hair Color") diff --git a/code/modules/loadout/categories/inhands.dm b/code/modules/loadout/categories/inhands.dm new file mode 100644 index 0000000000000..8ddc15676ab32 --- /dev/null +++ b/code/modules/loadout/categories/inhands.dm @@ -0,0 +1,33 @@ +/// Inhand items (Moves overrided items to backpack) +/datum/loadout_category/inhands + category_name = "Inhand" + category_ui_icon = FA_ICON_BRIEFCASE + type_to_generate = /datum/loadout_item/inhand + tab_order = /datum/loadout_category/head::tab_order + 4 + +/datum/loadout_item/inhand + abstract_type = /datum/loadout_item/inhand + +/datum/loadout_item/inhand/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE) + if(outfit.l_hand && !outfit.r_hand) + outfit.r_hand = item_path + else + if(outfit.l_hand) + LAZYADD(outfit.backpack_contents, outfit.l_hand) + outfit.l_hand = item_path + +/datum/loadout_item/inhand/cane + name = "Cane" + item_path = /obj/item/cane + +/datum/loadout_item/inhand/cane_white + name = "White Cane" + item_path = /obj/item/cane/white + +/datum/loadout_item/inhand/briefcase + name = "Briefcase (Leather)" + item_path = /obj/item/storage/briefcase + +/datum/loadout_item/inhand/briefcase_secure + name = "Briefcase (Secure)" + item_path = /obj/item/storage/briefcase/secure diff --git a/code/modules/loadout/categories/neck.dm b/code/modules/loadout/categories/neck.dm new file mode 100644 index 0000000000000..04a42a19da10d --- /dev/null +++ b/code/modules/loadout/categories/neck.dm @@ -0,0 +1,40 @@ +/// Neck Slot Items (Deletes overrided items) +/datum/loadout_category/neck + category_name = "Neck" + category_ui_icon = FA_ICON_USER_TIE + type_to_generate = /datum/loadout_item/neck + tab_order = /datum/loadout_category/head::tab_order + 2 + +/datum/loadout_item/neck + abstract_type = /datum/loadout_item/neck + +/datum/loadout_item/neck/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, loadout_placement_preference) + // SKYRAT EDIT CHANGE + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.neck) + LAZYADD(outfit.backpack_contents, outfit.neck) + outfit.neck = item_path + // SKYRAT EDIT END + +/datum/loadout_item/neck/scarf_greyscale + name = "Scarf (Colorable)" + item_path = /obj/item/clothing/neck/scarf + +/datum/loadout_item/neck/greyscale_large + name = "Scarf (Large, Colorable)" + item_path = /obj/item/clothing/neck/large_scarf + +/datum/loadout_item/neck/greyscale_larger + name = "Scarf (Larger, Colorable)" + item_path = /obj/item/clothing/neck/infinity_scarf + +/datum/loadout_item/neck/necktie + name = "Necktie (Colorable)" + item_path = /obj/item/clothing/neck/tie + +/datum/loadout_item/neck/necktie_disco + name = "Necktie (Ugly)" + item_path = /obj/item/clothing/neck/tie/horrible + +/datum/loadout_item/neck/necktie_loose + name = "Necktie (Loose)" + item_path = /obj/item/clothing/neck/tie/detective diff --git a/code/modules/loadout/categories/pocket.dm b/code/modules/loadout/categories/pocket.dm new file mode 100644 index 0000000000000..8206192bb8100 --- /dev/null +++ b/code/modules/loadout/categories/pocket.dm @@ -0,0 +1,204 @@ +/// Pocket items (Moved to backpack) +/datum/loadout_category/pocket + category_name = "Other" + category_ui_icon = FA_ICON_QUESTION + type_to_generate = /datum/loadout_item/pocket_items + tab_order = /datum/loadout_category/head::tab_order + 5 + /// How many pocket items are allowed + VAR_PRIVATE/max_allowed = 2 + +/datum/loadout_category/pocket/New() + . = ..() + category_info = "([max_allowed] allowed)" + +/datum/loadout_category/pocket/handle_duplicate_entires( + datum/preference_middleware/loadout/manager, + datum/loadout_item/conflicting_item, + datum/loadout_item/added_item, + list/datum/loadout_item/all_loadout_items, +) + var/list/datum/loadout_item/pocket_items/other_pocket_items = list() + for(var/datum/loadout_item/pocket_items/other_pocket_item in all_loadout_items) + other_pocket_items += other_pocket_item + + if(length(other_pocket_items) >= max_allowed) + // We only need to deselect something if we're above the limit + // (And if we are we prioritize the first item found, FIFO) + manager.deselect_item(other_pocket_items[1]) + return TRUE + +/datum/loadout_item/pocket_items + abstract_type = /datum/loadout_item/pocket_items + +/datum/loadout_item/pocket_items/on_equip_item( + obj/item/equipped_item, + datum/preferences/preference_source, + list/preference_list, + mob/living/carbon/human/equipper, + visuals_only = FALSE, +) + // Backpack items aren't created if it's a visual equipping, so don't do any on equip stuff. It doesn't exist. + if(visuals_only) + return NONE + + return ..() + +/datum/loadout_item/pocket_items/lipstick_black + name = "Lipstick (Black)" + item_path = /obj/item/lipstick/black + additional_displayed_text = list("Black") + +/datum/loadout_item/pocket_items/lipstick_blue + name = "Lipstick (Blue)" + item_path = /obj/item/lipstick/blue + additional_displayed_text = list("Blue") + + +/datum/loadout_item/pocket_items/lipstick_green + name = "Lipstick (Green)" + item_path = /obj/item/lipstick/green + additional_displayed_text = list("Green") + + +/datum/loadout_item/pocket_items/lipstick_jade + name = "Lipstick (Jade)" + item_path = /obj/item/lipstick/jade + additional_displayed_text = list("Jade") + +/datum/loadout_item/pocket_items/lipstick_purple + name = "Lipstick (Purple)" + item_path = /obj/item/lipstick/purple + additional_displayed_text = list("Purple") + +/datum/loadout_item/pocket_items/lipstick_red + name = "Lipstick (Red)" + item_path = /obj/item/lipstick + additional_displayed_text = list("Red") + +/datum/loadout_item/pocket_items/lipstick_white + name = "Lipstick (White)" + item_path = /obj/item/lipstick/white + additional_displayed_text = list("White") +/* SKYRAT EDIT REMOVAL +/datum/loadout_item/pocket_items/plush + abstract_type = /datum/loadout_item/pocket_items/plush + can_be_named = TRUE + +/datum/loadout_item/pocket_items/plush/bee + name = "Plush (Bee)" + item_path = /obj/item/toy/plush/beeplushie + +/datum/loadout_item/pocket_items/plush/carp + name = "Plush (Carp)" + item_path = /obj/item/toy/plush/carpplushie + +/datum/loadout_item/pocket_items/plush/lizard_greyscale + name = "Plush (Lizard, Colorable)" + item_path = /obj/item/toy/plush/lizard_plushie/greyscale + +/datum/loadout_item/pocket_items/plush/lizard_random + name = "Plush (Lizard, Random)" + can_be_greyscale = DONT_GREYSCALE + item_path = /obj/item/toy/plush/lizard_plushie + additional_displayed_text = list("Random color") + +/datum/loadout_item/pocket_items/plush/moth + name = "Plush (Moth)" + item_path = /obj/item/toy/plush/moth + +/datum/loadout_item/pocket_items/plush/narsie + name = "Plush (Nar'sie)" + item_path = /obj/item/toy/plush/narplush + +/datum/loadout_item/pocket_items/plush/nukie + name = "Plush (Nukie)" + item_path = /obj/item/toy/plush/nukeplushie + +/datum/loadout_item/pocket_items/plush/peacekeeper + name = "Plush (Peacekeeper)" + item_path = /obj/item/toy/plush/pkplush + +/datum/loadout_item/pocket_items/plush/plasmaman + name = "Plush (Plasmaman)" + item_path = /obj/item/toy/plush/plasmamanplushie + +/datum/loadout_item/pocket_items/plush/ratvar + name = "Plush (Ratvar)" + item_path = /obj/item/toy/plush/ratplush + +/datum/loadout_item/pocket_items/plush/rouny + name = "Plush (Rouny)" + item_path = /obj/item/toy/plush/rouny + +/datum/loadout_item/pocket_items/plush/snake + name = "Plush (Snake)" + item_path = /obj/item/toy/plush/snakeplushie + +/datum/loadout_item/pocket_items/card_binder + name = "Card Binder" + item_path = /obj/item/storage/card_binder + +/datum/loadout_item/pocket_items/card_deck + name = "Playing Card Deck" + item_path = /obj/item/toy/cards/deck + +/datum/loadout_item/pocket_items/kotahi_deck + name = "Kotahi Deck" + item_path = /obj/item/toy/cards/deck/kotahi + +/datum/loadout_item/pocket_items/wizoff_deck + name = "Wizoff Deck" + item_path = /obj/item/toy/cards/deck/wizoff + +/datum/loadout_item/pocket_items/dice_bag + name = "Dice Bag" + item_path = /obj/item/storage/dice + +/datum/loadout_item/pocket_items/d1 + name = "D1" + item_path = /obj/item/dice/d1 + +/datum/loadout_item/pocket_items/d2 + name = "D2" + item_path = /obj/item/dice/d2 + +/datum/loadout_item/pocket_items/d4 + name = "D4" + item_path = /obj/item/dice/d4 + +/datum/loadout_item/pocket_items/d6 + name = "D6" + item_path = /obj/item/dice/d6 + +/datum/loadout_item/pocket_items/d6_ebony + name = "D6 (Ebony)" + item_path = /obj/item/dice/d6/ebony + +/datum/loadout_item/pocket_items/d6_space + name = "D6 (Space)" + item_path = /obj/item/dice/d6/space + +/datum/loadout_item/pocket_items/d8 + name = "D8" + item_path = /obj/item/dice/d8 + +/datum/loadout_item/pocket_items/d10 + name = "D10" + item_path = /obj/item/dice/d10 + +/datum/loadout_item/pocket_items/d12 + name = "D12" + item_path = /obj/item/dice/d12 + +/datum/loadout_item/pocket_items/d20 + name = "D20" + item_path = /obj/item/dice/d20 + +/datum/loadout_item/pocket_items/d100 + name = "D100" + item_path = /obj/item/dice/d100 + +/datum/loadout_item/pocket_items/d00 + name = "D00" + item_path = /obj/item/dice/d00 +*/ diff --git a/code/modules/loadout/loadout_categories.dm b/code/modules/loadout/loadout_categories.dm new file mode 100644 index 0000000000000..ae9aca7e9146f --- /dev/null +++ b/code/modules/loadout/loadout_categories.dm @@ -0,0 +1,86 @@ +/** + * # Loadout categories + * + * Loadout categories are singletons used to group loadout items together in the loadout screen. + */ +/datum/loadout_category + /// The name of the category, shown in the tabs + var/category_name + /// FontAwesome icon for the category + var/category_ui_icon + /// String to display on the top-right of a category tab + var/category_info + /// Order which they appear in the tabs, ties go alphabetically + var/tab_order = -1 + /// What type of loadout items should be generated for this category? + var/type_to_generate + /// List of all loadout items in this category + VAR_FINAL/list/datum/loadout_item/associated_items + +/datum/loadout_category/New() + . = ..() + associated_items = get_items() + for(var/datum/loadout_item/item as anything in associated_items) + if(GLOB.all_loadout_datums[item.item_path]) + stack_trace("Loadout datum collision - [item.item_path] is shared between multiple loadout datums.") + GLOB.all_loadout_datums[item.item_path] = item + +/datum/loadout_category/Destroy(force, ...) + if(!force) + stack_trace("QDEL called on loadout category [type]. This shouldn't ever happen. (Use FORCE if necessary.)") + return QDEL_HINT_LETMELIVE + + associated_items.Cut() + return ..() + +/// Return a list of all /datum/loadout_items in this category. +/datum/loadout_category/proc/get_items() as /list + var/list/all_items = list() + for(var/datum/loadout_item/found_type as anything in typesof(type_to_generate)) + if(found_type == initial(found_type.abstract_type)) + continue + + if(!initial(found_type.item_path)) // SKYRAT EDIT ADDITION + continue + + if(!ispath(initial(found_type.item_path), /obj/item)) + stack_trace("Loadout get_items(): Attempted to instantiate a loadout item ([found_type]) with an invalid or null typepath! (got path: [initial(found_type.item_path)])") + continue + + var/datum/loadout_item/spawned_type = new found_type(src) + all_items += spawned_type + + return all_items + +/// Returns a list of all /datum/loadout_items in this category, formatted for UI use. Only ran once. +/datum/loadout_category/proc/items_to_ui_data(client/user) as /list // SKYRAT EDIT CHANGE - Added user poaram + if(!length(associated_items)) + return list() + + var/list/formatted_list = list() + + for(var/datum/loadout_item/item as anything in associated_items) + // SKYRAT EDIT ADDITION + if(item.ckeywhitelist && !(user?.ckey in item.ckeywhitelist)) + continue + // SKYRAT EDIT END + var/list/item_data = item.to_ui_data() + UNTYPED_LIST_ADD(formatted_list, item_data) + + sortTim(formatted_list, /proc/cmp_assoc_list_name) // Alphabetizing + return formatted_list + +/** + * Handles what happens when two items of this category are selected at once + * + * Return TRUE if it's okay to continue with adding the incoming item, + * or return FALSE to stop the new item from being added + */ +/datum/loadout_category/proc/handle_duplicate_entires( + datum/preference_middleware/loadout/manager, + datum/loadout_item/conflicting_item, + datum/loadout_item/added_item, + list/datum/loadout_item/all_loadout_items, +) + manager.deselect_item(conflicting_item) + return TRUE diff --git a/code/modules/loadout/loadout_helpers.dm b/code/modules/loadout/loadout_helpers.dm new file mode 100644 index 0000000000000..c2f83fb3ca742 --- /dev/null +++ b/code/modules/loadout/loadout_helpers.dm @@ -0,0 +1,142 @@ +/** + * Equips this mob with a given outfit and loadout items as per the passed preferences. + * + * Loadout items override the pre-existing item in the corresponding slot of the job outfit. + * Some job items are preserved after being overridden - belt items, ear items, and glasses. + * The rest of the slots, the items are overridden completely and deleted. + * + * Species with special outfits are snowflaked to have loadout items placed in their bags instead of overriding the outfit. + * + * * outfit - the job outfit we're equipping + * * preference_source - the preferences to draw loadout items from. + * * visuals_only - whether we call special equipped procs, or if we just look like we equipped it + */ +/mob/living/carbon/human/proc/equip_outfit_and_loadout( + datum/outfit/outfit = /datum/outfit, + datum/preferences/preference_source, + visuals_only = FALSE, + datum/job/equipping, +) // SKYRAT EDIT CHANGE - Added equipping param + if(isnull(preference_source)) + return equipOutfit(outfit, visuals_only) + + var/datum/outfit/equipped_outfit + if(ispath(outfit, /datum/outfit)) + equipped_outfit = new outfit() + else if(istype(outfit, /datum/outfit)) + equipped_outfit = outfit + else + CRASH("Invalid outfit passed to equip_outfit_and_loadout ([outfit])") + + var/list/preference_list = preference_source.read_preference(/datum/preference/loadout) + var/list/loadout_datums = loadout_list_to_datums(preference_list) + var/obj/item/storage/briefcase/empty/travel_suitcase // SKYRAT EDIT ADDITIONi + var/loadout_placement_preference = preference_source.read_preference(/datum/preference/choiced/loadout_override_preference) + // Slap our things into the outfit given + for(var/datum/loadout_item/item as anything in loadout_datums) + // SKYRAT EDIT ADDITION + if(item.restricted_roles && equipping && !(equipping.title in item.restricted_roles)) + if(preference_source.parent) + to_chat(preference_source.parent, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job restrictions!")) + continue + + if(item.blacklisted_roles && equipping && (equipping.title in item.blacklisted_roles)) + if(preference_source.parent) + to_chat(preference_source.parent, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job blacklists!")) + continue + + if(item.restricted_species && !(dna.species.id in item.restricted_species)) + if(preference_source.parent) + to_chat(preference_source.parent, span_warning("You were unable to get a loadout item ([initial(item.item_path.name)]) due to species restrictions!")) + continue + + if(item.ckeywhitelist && !(preference_source?.parent?.ckey in item.ckeywhitelist)) // Sanity checking + if(preference_source.parent) + to_chat(preference_source.parent, span_warning("You were unable to get a loadout item ([initial(item.item_path.name)]) due to CKEY restrictions!")) + continue + + if(loadout_placement_preference == LOADOUT_OVERRIDE_CASE) + if(!travel_suitcase) + travel_suitcase = new(loc) + new item.item_path(travel_suitcase) + else // SKYRAT EDIT END + item.insert_path_into_outfit(equipped_outfit, src, visuals_only, loadout_placement_preference) + // Equip the outfit loadout items included + if(!equipped_outfit.equip(src, visuals_only)) + return FALSE + + // SKYRAT EDIT ADDITION + if(travel_suitcase) + put_in_hands(travel_suitcase) + // SKYRAT EDIT END + + // Handle any snowflake on_equips. + var/list/new_contents = get_all_gear() + var/update = NONE + for(var/datum/loadout_item/item as anything in loadout_datums) + var/obj/item/equipped = locate(item.item_path) in new_contents + if(isnull(equipped)) + continue + update |= item.on_equip_item( + equipped_item = equipped, + preference_source = preference_source, + preference_list = preference_list, + equipper = src, + visuals_only = visuals_only, + ) + + if(update) + update_clothing(update) + + return TRUE + +/** + * Takes a list of paths (such as a loadout list) + * and returns a list of their singleton loadout item datums + * + * loadout_list - the list being checked + * + * Returns a list of singleton datums + */ +/proc/loadout_list_to_datums(list/loadout_list) as /list + var/list/datums = list() + + if(!length(GLOB.all_loadout_datums)) + CRASH("No loadout datums in the global loadout list!") + + for(var/path in loadout_list) + var/actual_datum = GLOB.all_loadout_datums[path] + if(!istype(actual_datum, /datum/loadout_item)) + stack_trace("Could not find ([path]) loadout item in the global list of loadout datums!") + continue + + datums += actual_datum + + return datums + +// SKYRAT EDIT ADDITION +/* + * Removes all invalid paths from loadout lists. + * + * passed_list - the loadout list we're sanitizing. + * + * returns a list + */ +/proc/sanitize_loadout_list(list/passed_list) + RETURN_TYPE(/list) + + var/list/list_to_clean = LAZYLISTDUPLICATE(passed_list) + for(var/path in list_to_clean) + if(!ispath(path)) + stack_trace("invalid path found in loadout list! (Path: [path])") + LAZYREMOVE(list_to_clean, path) + + else if(!(path in GLOB.all_loadout_datums)) + stack_trace("invalid loadout slot found in loadout list! Path: [path]") + LAZYREMOVE(list_to_clean, path) + + return list_to_clean + +/obj/item/storage/briefcase/empty/PopulateContents() + return +// SKYRAT EDIT END diff --git a/code/modules/loadout/loadout_items.dm b/code/modules/loadout/loadout_items.dm new file mode 100644 index 0000000000000..e02d15e7a44f3 --- /dev/null +++ b/code/modules/loadout/loadout_items.dm @@ -0,0 +1,406 @@ +/// Global list of ALL loadout datums instantiated. +/// Loadout datums are created by loadout categories. +GLOBAL_LIST_EMPTY(all_loadout_datums) + +/// Global list of all loadout categories +/// Doesn't really NEED to be a global but we need to init this early for preferences, +/// as the categories instantiate all the loadout datums +GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) + +/// Inits the global list of loadout category singletons +/// Also inits loadout item singletons +/proc/init_loadout_categories() + var/list/loadout_categories = list() + for(var/category_type in subtypesof(/datum/loadout_category)) + loadout_categories += new category_type() + + sortTim(loadout_categories, /proc/cmp_loadout_categories) + return loadout_categories + +/proc/cmp_loadout_categories(datum/loadout_category/A, datum/loadout_category/B) + var/a_order = A::tab_order + var/b_order = B::tab_order + if(a_order == b_order) + return cmp_text_asc(A::category_name, B::category_name) + return cmp_numeric_asc(a_order, b_order) + +/** + * # Loadout item datum + * + * Singleton that holds all the information about each loadout items, and how to equip them. + */ +/datum/loadout_item + /// The category of the loadout item. Set automatically in New + VAR_FINAL/datum/loadout_category/category + /// Displayed name of the loadout item. + /// Defaults to the item's name if unset. + var/name + /// Whether this item has greyscale support. + /// Only works if the item is compatible with the GAGS system of coloring. + /// Set automatically to TRUE for all items that have the flag [IS_PLAYER_COLORABLE_1]. + /// If you really want it to not be colorable set this to [DONT_GREYSCALE] + var/can_be_greyscale = FALSE + /// Whether this item can be renamed. + /// I recommend you apply this sparingly becuase it certainly can go wrong (or get reset / overridden easily) + var/can_be_named = FALSE + /// Whether this item can be reskinned. + /// Only works if the item has a "unique reskin" list set. + var/can_be_reskinned = FALSE + /// The abstract parent of this loadout item, to determine which items to not instantiate + var/abstract_type = /datum/loadout_item + /// The actual item path of the loadout item. + var/obj/item/item_path + /// Lazylist of additional "information" text to display about this item. + var/list/additional_displayed_text + /// Icon file (DMI) for the UI to use for preview icons. + /// Set automatically if null + var/ui_icon + /// Icon state for the UI to use for preview icons. + /// Set automatically if null + var/ui_icon_state + /// Reskin options of this item if it can be reskinned. + VAR_FINAL/list/cached_reskin_options + + //SKYRAT EDIT ADDITION + /// If set, it's a list containing ckeys which only can get the item + var/list/ckeywhitelist + /// If set, is a list of job names of which can get the loadout item + var/list/restricted_roles + /// If set, is a list of job names of which can't get the loadout item + var/list/blacklisted_roles + /// If set, is a list of species which can get the loadout item + var/list/restricted_species + /// Whether the item is restricted to supporters + var/donator_only + /// Whether the item requires a specific season in order to be available + var/required_season = null + /// If the item won't appear when the ERP config is disabled + var/erp_item = FALSE + + +/datum/loadout_item/New(category) + src.category = category + + if(can_be_greyscale == DONT_GREYSCALE) + can_be_greyscale = FALSE + else if(item_path::flags_1 & IS_PLAYER_COLORABLE_1) + can_be_greyscale = TRUE + + if(isnull(name)) + name = item_path::name + + if(isnull(ui_icon) && isnull(ui_icon_state)) + ui_icon = item_path::icon_preview || item_path::icon + ui_icon_state = item_path::icon_state_preview || item_path::icon_state + + if(can_be_reskinned) + var/obj/item/dummy_item = new item_path() + if(!length(dummy_item.unique_reskin)) + can_be_reskinned = FALSE + stack_trace("Loadout item [item_path] has can_be_reskinned set to TRUE but has no unique reskins.") + else + cached_reskin_options = dummy_item.unique_reskin.Copy() + qdel(dummy_item) + + // SKYRAT EDIT ADDITION + // Let's sanitize in case somebody inserted the player's byond name instead of ckey in canonical form + if(ckeywhitelist) + for (var/i = 1, i <= length(ckeywhitelist), i++) + ckeywhitelist[i] = ckey(ckeywhitelist[i]) + // SKYRAT EDIT END + +/datum/loadout_item/Destroy(force, ...) + if(force) + stack_trace("QDEL called on loadout item [type]. This shouldn't ever happen. (Use FORCE if necessary.)") + return QDEL_HINT_LETMELIVE + + GLOB.all_loadout_datums -= item_path + return ..() + +/** + * Takes in an action from a loadout manager and applies it + * + * Useful for subtypes of loadout items with unique actions + * + * Return TRUE to force an update to the UI / character preview + */ +/datum/loadout_item/proc/handle_loadout_action(datum/preference_middleware/loadout/manager, mob/user, action, params) + SHOULD_CALL_PARENT(TRUE) + + switch(action) + if("select_color") + if(can_be_greyscale) + return set_item_color(manager, user) + + if("set_name") + if(can_be_named) + return set_name(manager, user) + + if("set_skin") + return set_skin(manager, user, params) + + return TRUE + +/// Opens up the GAGS editing menu. +/datum/loadout_item/proc/set_item_color(datum/preference_middleware/loadout/manager, mob/user) + if(manager.menu) + return FALSE + + var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout) + var/list/allowed_configs = list() + if(initial(item_path.greyscale_config)) + allowed_configs += "[initial(item_path.greyscale_config)]" + if(initial(item_path.greyscale_config_worn)) + allowed_configs += "[initial(item_path.greyscale_config_worn)]" + if(initial(item_path.greyscale_config_inhand_left)) + allowed_configs += "[initial(item_path.greyscale_config_inhand_left)]" + if(initial(item_path.greyscale_config_inhand_right)) + allowed_configs += "[initial(item_path.greyscale_config_inhand_right)]" + + var/datum/greyscale_modify_menu/menu = new( + manager, + user, + allowed_configs, + CALLBACK(src, PROC_REF(set_slot_greyscale), manager), + starting_icon_state = initial(item_path.icon_state), + starting_config = initial(item_path.greyscale_config), + starting_colors = loadout?[item_path]?[INFO_GREYSCALE] || initial(item_path.greyscale_colors), + ) + + manager.register_greyscale_menu(menu) + menu.ui_interact(user) + return TRUE + +/// Callback for GAGS menu to set this item's color. +/datum/loadout_item/proc/set_slot_greyscale(datum/preference_middleware/loadout/manager, datum/greyscale_modify_menu/open_menu) + if(!istype(open_menu)) + CRASH("set_slot_greyscale called without a greyscale menu!") + + var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout) + if(!loadout?[item_path]) + return FALSE + + var/list/colors = open_menu.split_colors + if(!colors) + return FALSE + + loadout[item_path][INFO_GREYSCALE] = colors.Join("") + manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + return TRUE // update UI + +/// Sets the name of the item. +/datum/loadout_item/proc/set_name(datum/preference_middleware/loadout/manager, mob/user) + var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout) + var/input_name = tgui_input_text( + user = user, + message = "What name do you want to give the [name]? Leave blank to clear.", + title = "[name] name", + default = loadout?[item_path]?[INFO_NAMED], // plop in existing name (if any) + max_length = MAX_NAME_LEN, + ) + if(QDELETED(src) || QDELETED(user) || QDELETED(manager) || QDELETED(manager.preferences)) + return FALSE + + loadout = manager.preferences.read_preference(/datum/preference/loadout) // Make sure no shenanigans happened + if(!loadout?[item_path]) + return FALSE + + if(input_name) + loadout[item_path][INFO_NAMED] = input_name + else if(input_name == "") + loadout[item_path] -= INFO_NAMED + + manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + return FALSE // no update needed + +/// Used for reskinning an item to an alt skin. +/datum/loadout_item/proc/set_skin(datum/preference_middleware/loadout/manager, mob/user, params) + if(!can_be_reskinned) + return FALSE + + var/reskin_to = params["skin"] + if(!cached_reskin_options[reskin_to]) + return FALSE + + var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout) + if(!loadout?[item_path]) + return FALSE + + loadout[item_path][INFO_RESKIN] = reskin_to + manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + return TRUE // always update UI + +/** + * Place our [item_path] into the passed [outfit]. + * + * By default, just adds the item into the outfit's backpack contents, if non-visual. + * + * Arguments: + * * outfit - The outfit we're equipping our items into. + * * equipper - If we're equipping out outfit onto a mob at the time, this is the mob it is equipped on. Can be null. + * * visual - If TRUE, then our outfit is only for visual use (for example, a preview). + */ +/datum/loadout_item/proc/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, loadout_placement_preference) // SKYRAT EDIT CHANGE - Added loadout_placement_preference + if(!visuals_only) + LAZYADD(outfit.backpack_contents, item_path) + +/** + * Called When the item is equipped on [equipper]. + * + * At this point the item is in the mob's contents + * + * Arguments: + * * preference_source - the datum/preferences our loadout item originated from - cannot be null + * * equipper - the mob we're equipping this item onto - cannot be null + * * visuals_only - whether or not this is only concerned with visual things (not backpack, not renaming, etc) + * * preference_list - what the raw loadout list looks like in the preferences + * + * Return a bitflag of slot flags to update + */ +/datum/loadout_item/proc/on_equip_item( + obj/item/equipped_item, + datum/preferences/preference_source, + list/preference_list, + mob/living/carbon/human/equipper, + visuals_only = FALSE, +) + ASSERT(!isnull(equipped_item)) + + if(!visuals_only) + ADD_TRAIT(equipped_item, TRAIT_ITEM_OBJECTIVE_BLOCKED, "Loadout") + + var/list/item_details = preference_list[item_path] + var/update_flag = NONE + + if(can_be_greyscale && item_details?[INFO_GREYSCALE]) + equipped_item.set_greyscale(item_details[INFO_GREYSCALE]) + update_flag |= equipped_item.slot_flags + + if(can_be_named && item_details?[INFO_NAMED] && !visuals_only) + equipped_item.name = trim(item_details[INFO_NAMED], PREVENT_CHARACTER_TRIM_LOSS(MAX_NAME_LEN)) + ADD_TRAIT(equipped_item, TRAIT_WAS_RENAMED, "Loadout") + + if(can_be_reskinned && item_details?[INFO_RESKIN]) + var/skin_chosen = item_details[INFO_RESKIN] + if(skin_chosen in equipped_item.unique_reskin) + equipped_item.current_skin = skin_chosen + equipped_item.icon_state = equipped_item.unique_reskin[skin_chosen] + if(istype(equipped_item, /obj/item/clothing/accessory)) + // Snowflake handing for accessories, because we need to update the thing it's attached to instead + if(isclothing(equipped_item.loc)) + var/obj/item/clothing/under/attached_to = equipped_item.loc + attached_to.update_accessory_overlay() + update_flag |= (ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) + else + update_flag |= equipped_item.slot_flags + + else + // Not valid, update the preference + item_details -= INFO_RESKIN + preference_source.write_preference(GLOB.preference_entries[/datum/preference/loadout], preference_list) + + return update_flag + +/** + * Returns a formatted list of data for this loadout item. + */ +/datum/loadout_item/proc/to_ui_data() as /list + SHOULD_CALL_PARENT(TRUE) + + var/list/formatted_item = list() + formatted_item["name"] = name + formatted_item["path"] = item_path + formatted_item["information"] = get_item_information() + formatted_item["buttons"] = get_ui_buttons() + formatted_item["reskins"] = get_reskin_options() + formatted_item["icon"] = ui_icon + formatted_item["icon_state"] = ui_icon_state + return formatted_item + +/** + * Returns a list of information to display about this item in the loadout UI. + * + * These should be short strings, sub 14 characters generally. + */ +/datum/loadout_item/proc/get_item_information() as /list + SHOULD_CALL_PARENT(TRUE) + + var/list/displayed_text = list() + + displayed_text += (additional_displayed_text || list()) + + if(can_be_greyscale) + displayed_text += "Recolorable" + + if(can_be_named) + displayed_text += "Renamable" + + if(can_be_reskinned) + displayed_text += "Reskinnable" + + // SKYRAT EDIT ADDITION + if(donator_only) + displayed_text += "Donator only" + + if(restricted_roles || blacklisted_roles) + displayed_text += "Role restricted" + + if(restricted_species) + displayed_text += "Species restricted" + // SKYRAT EDIT ADDITION + return displayed_text + +/** + * Returns a list of buttons that are shown in the loadout UI for customizing this item. + * + * Buttons contain + * - 'L'abel: The text displayed beside the button + * - act_key: The key that is sent to the loadout manager when the button is clicked, + * for use in handle_loadout_action + * - button_icon: The FontAwesome icon to display on the button + * - active_key: In the loadout UI, this key is checked in the user's loadout list for this item + * to determine if the button is 'active' (green) or not (blue). + * - active_text: Optional, if provided, the button appears to be a checkbox and this text is shown when 'active' + * - inactive_text: Optional, if provided, the button appears to be a checkbox and this text is shown when not 'active' + */ +/datum/loadout_item/proc/get_ui_buttons() as /list + SHOULD_CALL_PARENT(TRUE) + + var/list/button_list = list() + + if(can_be_greyscale) + UNTYPED_LIST_ADD(button_list, list( + "label" = "Recolor", + "act_key" = "select_color", + "button_icon" = FA_ICON_PALETTE, + "active_key" = INFO_GREYSCALE, + )) + + if(can_be_named) + UNTYPED_LIST_ADD(button_list, list( + "label" = "Rename", + "act_key" = "set_name", + "button_icon" = FA_ICON_PEN, + "active_key" = INFO_NAMED, + )) + + return button_list + +/** + * Returns a list of options this item can be reskinned into. + */ +/datum/loadout_item/proc/get_reskin_options() as /list + if(!can_be_reskinned) + return null + + var/list/reskins = list() + + for(var/skin in cached_reskin_options) + UNTYPED_LIST_ADD(reskins, list( + "name" = skin, + "tooltip" = skin, + "skin_icon_state" = cached_reskin_options[skin], + )) + + return reskins + diff --git a/code/modules/loadout/loadout_menu.dm b/code/modules/loadout/loadout_menu.dm new file mode 100644 index 0000000000000..f01d4215c69fe --- /dev/null +++ b/code/modules/loadout/loadout_menu.dm @@ -0,0 +1,129 @@ +/datum/preference_middleware/loadout + action_delegations = list( + "clear_all_items" = PROC_REF(action_clear_all), + "pass_to_loadout_item" = PROC_REF(action_pass_to_loadout_item), + "rotate_dummy" = PROC_REF(action_rotate_model_dir), + "select_item" = PROC_REF(action_select_item), + "toggle_job_clothes" = PROC_REF(action_toggle_job_outfit), + "close_greyscale_menu" = PROC_REF(force_close_greyscale_menu), + ) + /// Our currently open greyscaling menu. + VAR_FINAL/datum/greyscale_modify_menu/menu + +/datum/preference_middleware/loadout/Destroy(force, ...) + QDEL_NULL(menu) + return ..() + +/datum/preference_middleware/loadout/on_new_character(mob/user) + preferences.character_preview_view?.update_body() + +/datum/preference_middleware/loadout/proc/action_select_item(list/params, mob/user) + PRIVATE_PROC(TRUE) + var/path_to_use = text2path(params["path"]) + var/datum/loadout_item/interacted_item = GLOB.all_loadout_datums[path_to_use] + if(!istype(interacted_item)) + stack_trace("Failed to locate desired loadout item (path: [params["path"]]) in the global list of loadout datums!") + return TRUE // update + + if(params["deselect"]) + deselect_item(interacted_item) + else + select_item(interacted_item) + return TRUE + +/datum/preference_middleware/loadout/proc/action_clear_all(list/params, mob/user) + PRIVATE_PROC(TRUE) + preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], null) + return TRUE + +/datum/preference_middleware/loadout/proc/action_toggle_job_outfit(list/params, mob/user) + PRIVATE_PROC(TRUE) + preferences.character_preview_view.show_job_clothes = !preferences.character_preview_view.show_job_clothes + preferences.character_preview_view.update_body() + return TRUE + +/datum/preference_middleware/loadout/proc/action_rotate_model_dir(list/params, mob/user) + PRIVATE_PROC(TRUE) + switch(params["dir"]) + if("left") + preferences.character_preview_view.setDir(turn(preferences.character_preview_view.dir, -90)) + if("right") + preferences.character_preview_view.setDir(turn(preferences.character_preview_view.dir, 90)) + +/datum/preference_middleware/loadout/proc/action_pass_to_loadout_item(list/params, mob/user) + PRIVATE_PROC(TRUE) + var/path_to_use = text2path(params["path"]) + var/datum/loadout_item/interacted_item = GLOB.all_loadout_datums[path_to_use] + if(!istype(interacted_item)) // no you cannot href exploit to spawn with a pulse rifle + stack_trace("Failed to locate desired loadout item (path: [params["path"]]) in the global list of loadout datums!") + return TRUE // update + + if(interacted_item.handle_loadout_action(src, user, params["subaction"], params)) + preferences.character_preview_view.update_body() + return TRUE + + return FALSE + +/// Select [path] item to [category_slot] slot. +/datum/preference_middleware/loadout/proc/select_item(datum/loadout_item/selected_item) + var/list/loadout = preferences.read_preference(/datum/preference/loadout) + var/list/datum/loadout_item/loadout_datums = loadout_list_to_datums(loadout) + for(var/datum/loadout_item/item as anything in loadout_datums) + if(item.category != selected_item.category) + continue + if(!item.category.handle_duplicate_entires(src, item, selected_item, loadout_datums)) + return + // SKYRAT EDIT ADDITION + if(item.ckeywhitelist && !(preferences?.parent?.ckey in item.ckeywhitelist)) + to_chat(preferences.parent, span_warning("You cannot select this item!")) + return + + if(item.donator_only && !GLOB.donator_list[preferences?.parent?.ckey]) + to_chat(preferences.parent, span_warning("That item is for donators only.")) + return + // SKYRAT EDIT END + + LAZYSET(loadout, selected_item.item_path, list()) + preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + +/// Deselect [deselected_item]. +/datum/preference_middleware/loadout/proc/deselect_item(datum/loadout_item/deselected_item) + var/list/loadout = preferences.read_preference(/datum/preference/loadout) + LAZYREMOVE(loadout, deselected_item.item_path) + preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) + +/datum/preference_middleware/loadout/proc/register_greyscale_menu(datum/greyscale_modify_menu/open_menu) + src.menu = open_menu + RegisterSignal(menu, COMSIG_QDELETING, PROC_REF(cleanup_greyscale_menu)) + +/datum/preference_middleware/loadout/proc/cleanup_greyscale_menu() + SIGNAL_HANDLER + menu = null + +/datum/preference_middleware/loadout/proc/force_close_greyscale_menu() + menu?.ui_close() + +/datum/preference_middleware/loadout/get_ui_data(mob/user) + var/list/data = list() + data["job_clothes"] = preferences.character_preview_view.show_job_clothes + return data + +/datum/preference_middleware/loadout/get_ui_static_data(mob/user) + var/list/data = list() + data["loadout_preview_view"] = preferences.character_preview_view.assigned_map + return data + +/datum/preference_middleware/loadout/get_constant_data() + var/list/data = list() + var/list/loadout_tabs = list() + for(var/datum/loadout_category/category as anything in GLOB.all_loadout_categories) + var/list/cat_data = list( + "name" = category.category_name, + "category_icon" = category.category_ui_icon, + "category_info" = category.category_info, + "contents" = category.items_to_ui_data(preferences?.parent), + ) // SKYRAT EDIT CHANGE - items_to_ui_data(preferences?.parent) + UNTYPED_LIST_ADD(loadout_tabs, cat_data) + + data["loadout_tabs"] = loadout_tabs + return data diff --git a/code/modules/loadout/loadout_preference.dm b/code/modules/loadout/loadout_preference.dm new file mode 100644 index 0000000000000..739226f5da78a --- /dev/null +++ b/code/modules/loadout/loadout_preference.dm @@ -0,0 +1,68 @@ +/datum/preference/loadout + savefile_key = "loadout_list" + savefile_identifier = PREFERENCE_CHARACTER + priority = PREFERENCE_PRIORITY_LOADOUT + can_randomize = FALSE + // Loadout preference is an assoc list [item_path] = [loadout item information list] + // + // it may look something like + // - list(/obj/item/glasses = list()) + // or + // - list(/obj/item/plush/lizard = list("name" = "Tests-The-Loadout", "color" = "#FF0000")) + +// Loadouts are applied with job equip code. +/datum/preference/loadout/apply_to_human(mob/living/carbon/human/target, value) + return + +// Sanitize on load to ensure no invalid paths from older saves get in +/datum/preference/loadout/deserialize(input, datum/preferences/preferences) + return sanitize_loadout_list(input, preferences.parent?.mob, preferences.parent) // SKYRAT EDIT CHANGE parent + +// Default value is null - the loadout list is a lazylist +/datum/preference/loadout/create_default_value(datum/preferences/preferences) + return null + +/datum/preference/loadout/is_valid(value) + return isnull(value) || islist(value) + +/** + * Removes all invalid paths from loadout lists. + * This is a general sanitization for preference loading. + * + * Returns a list, or null if empty + */ +/datum/preference/loadout/proc/sanitize_loadout_list(list/passed_list, mob/optional_loadout_owner, client/owner_client) as /list // SKYRAT EDIT CHANGE - client/owner_client + var/list/sanitized_list + for(var/path in passed_list) + // Loading from json has each path in the list as a string that we need to convert back to typepath + var/obj/item/real_path = istext(path) ? text2path(path) : path + if(!ispath(real_path, /obj/item)) + if(optional_loadout_owner) + to_chat(optional_loadout_owner, span_boldnotice("The following invalid item path was found \ + in your character loadout: [real_path || "null"]. \ + It has been removed, renamed, or is otherwise missing - \ + You may want to check your loadout settings.")) + continue + + else if(!istype(GLOB.all_loadout_datums[real_path], /datum/loadout_item)) + if(optional_loadout_owner) + to_chat(optional_loadout_owner, span_boldnotice("The following invalid loadout item was found \ + in your character loadout: [real_path || "null"]. \ + It has been removed, renamed, or is otherwise missing - \ + You may want to check your loadout settings.")) + continue + + // SKYRAT EDIT ADDITION + else if(owner_client) + var/datum/loadout_item/loadout_item = GLOB.all_loadout_datums[real_path] + if(loadout_item?.ckeywhitelist && !(owner_client?.ckey in loadout_item.ckeywhitelist)) + continue + if(loadout_item?.donator_only && !GLOB.donator_list[owner_client?.ckey]) + continue + // SKYRAT EDIT END + + // Set into sanitize list using converted path key + var/list/data = passed_list[path] + LAZYSET(sanitized_list, real_path, LAZYLISTDUPLICATE(data)) + + return sanitized_list diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 71c8a57e7a570..955b16a772a59 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -287,14 +287,6 @@ humanc.put_in_hands(new /obj/item/crowbar/large/emergency(get_turf(humanc))) //if hands full then just drops on the floor log_manifest(character.mind.key, character.mind, character, latejoin = TRUE) - // SKYRAT EDIT ADDITION START - if(humanc) - for(var/datum/loadout_item/item as anything in loadout_list_to_datums(humanc?.client?.prefs?.loadout_list)) - if (item.restricted_roles && length(item.restricted_roles) && !(job.title in item.restricted_roles)) - continue - item.post_equip_item(humanc.client?.prefs, humanc) - // SKYRAT EDIT END - /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) diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index e15218a9fef24..cd5111c235c66 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -108,9 +108,13 @@ // Set up the dummy for its photoshoot apply_prefs_to(mannequin, TRUE) - if(preview_job) - mannequin.job = preview_job.title - mannequin.dress_up_as_job(preview_job, TRUE) + mannequin.job = preview_job.title + mannequin.dress_up_as_job( + equipping = show_job_clothes ? preview_job : no_job, + visual_only = TRUE, + player_client = parent, + consistent = TRUE, + ) // Apply visual quirks // Yes we do it every time because it needs to be done after job gear diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 522fa6636016a..cdb685e6e563f 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -118,13 +118,13 @@ There are several things that need to be remembered: var/mutant_styles = NONE // SKYRAT EDIT ADDITON - mutant styles to pass down to build_worn_icon. //BEGIN SPECIES HANDLING if((bodyshape & BODYSHAPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) - icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_UNIFORM, w_uniform, src) // SKYRAT EDIT CHANGE - ORIGINAL: icon_file = MONKEY_UNIFORM_FILE + icon_file = dna.species.generate_custom_worn_icon(OFFSET_UNIFORM, w_uniform, src) // SKYRAT EDIT CHANGE - ORIGINAL: icon_file = MONKEY_UNIFORM_FILE else if((bodyshape & BODYSHAPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) icon_file = uniform.worn_icon_digi || DIGITIGRADE_UNIFORM_FILE // SKYRAT EDIT CHANGE - ORIGINAL: icon_file = DIGITIGRADE_UNIFORM_FILE digi = TRUE // SKYRAT EDIT ADDITION - Digi female gender shaping // SKYRAT EDIT ADDITION - birbs else if(bodyshape & BODYSHAPE_CUSTOM) - icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_UNIFORM, w_uniform, src) // Might have to refactor how this works eventually, maybe. + icon_file = dna.species.generate_custom_worn_icon(OFFSET_UNIFORM, w_uniform, src) // Might have to refactor how this works eventually, maybe. // SKYRAT EDIT END //Female sprites have lower priority than digitigrade sprites if(!dna.species.no_gender_shaping && dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(female_sprite_flags & NO_FEMALE_UNIFORM)) // SKYRAT EDIT CHANGE - ORIGINAL: else if(dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh @@ -231,7 +231,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_GLOVES, gloves, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_GLOVES, gloves, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -277,7 +277,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_GLASSES, glasses, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_GLASSES, glasses, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -319,7 +319,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_EARS, ears, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_EARS, ears, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -356,7 +356,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_NECK, wear_neck, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_NECK, wear_neck, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -410,7 +410,7 @@ There are several things that need to be remembered: icon_file = worn_item.worn_icon_digi || DIGITIGRADE_SHOES_FILE // SKYRAT EDIT CHANGE mutant_override = TRUE // SKYRAT EDIT ADDITION if(!mutant_override && bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_SHOES, shoes, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_SHOES, shoes, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -484,7 +484,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION - This needs to be refactored. var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_HEAD, head, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_HEAD, head, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -528,7 +528,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_BELT, belt, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_BELT, belt, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -572,7 +572,7 @@ There are several things that need to be remembered: mutant_override = TRUE if(!mutant_override && bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_SUIT, wear_suit, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_SUIT, wear_suit, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -644,7 +644,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_MASK, wear_mask, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_FACEMASK, wear_mask, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE @@ -686,7 +686,7 @@ There are several things that need to be remembered: // SKYRAT EDIT ADDITION var/mutant_override = FALSE if(bodyshape & BODYSHAPE_CUSTOM) - var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_MISC, back, src) + var/species_icon_file = dna.species.generate_custom_worn_icon(OFFSET_HELD, back, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index bd46aeea334bd..121c259b10f8c 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -286,7 +286,6 @@ #include "worn_icons.dm" // SKYRAT EDIT START #include "~skyrat\automapper.dm" -#include "~skyrat\loadout_dupes.dm" #include "~skyrat\opposing_force.dm" // SKYRAT EDIT END // END_INCLUDE diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png deleted file mode 100644 index d75bf8fffecca36ce16bb7b36b4687633cd2352d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmV->0)+jEP)nsW03IGP@QMI5G(z;9CypQ<@@{UxJUUcVVJkF193m?i7a2G}QeI`3=>Px#0d!JM zQvg8b*k%9#0AzYpSad{Xb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1+qiF9SHYy^qv$`-IqNjqo_DYB^ zAfy+I)i*dh+beCaQY`lxv2KqW>$R zAc5(4jYaV)Hq12uc*7iJB6G-%AORw7W~aF*OF5xh05s17B_s+Fu-0C-MOd5%2_V)@ zd({!y3v6lt5TS&&6hKj(jP{Hg0zekKw z6gp92=e^?1AstQu^sf72zSj^K#!f563ww{8y`o3HdG)UVjOU(z5))_t3^)8W@D6!! V46j{iqSycc002ovPDHLkV1go&2tWV; diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png deleted file mode 100644 index e7e1cbd661fcb609b7d24bf84ba5fbc003c8882f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmV;00eb$4P)fFDZ*Bkpc$`yKaB_9`^iy#0 z_2eo`Eh^5;&r`5fFwryM;w;ZhDainGEX}w$Gg33tGfE(w;*!LYR3KAHiHkEOv#1!z zH00t;D@x2wg|L+sT>V_YCISGS$rvAshC*oo006y7L_t(Ijjhu$4#OY}1yDx}9l1ay zuF=gm3+c@`N{_(EVDW2`wCWO@p%y}V1CW>x(R{_0>IBw(cnG>678hwFTAB+Cz=e#7 zJ=_kw{sxvAM4ULFW20pA{6fzgRF#D*S^mUOBnGS2E20zPX{EOe4wLTAbrGzDBzAidT_7RSM_AvT5+G*juub-!Ri3Q_rxR}{( j{d~b{VlqgRv7D+m(szW4NCKsN00000NkvXXu0mjfD!H94 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png deleted file mode 100644 index 28f6b0b1dccbf14433af8746cd73fc8fb28c0342..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 823 zcmV-71IYY|P)BmPlNuT!R$60sdxH)R z4j>>P$H&KbGXP;>VUXjrkpKVy0d!JMQvg8b*k%9#0A+eqSad{Xb7OL8aCB*JZU6vy zoKseCa&`CgQ*iP1KApDvssY_yH%`^O2Nh(tjznIOv?k2I{lEuI>cOaUNZ zV_p5u+K(U$wds;R;~kN8ryOSyLfc5thx`$L4)ay{+3@pn)>&tb>O(&Gg!h0j=$MB2 zK?1-9`CusUHQV_?1g;Vg%!X;4A5b?52qS@Uen7{KmeG`^X(2Lkys^butXFC)663+k zUFE~M@zzedbM}JmpamwcD1Z;&ret{cCXiYSD+=)4BF>aQ31qP@>3$V}Z4n}p2-r`d z2}A^d&EJkYfB?n#Ng(1T#P2)6zZjl#FNg@=mcTdCL%GA5r29>PYflKKw>q&`G4SB) zG0BP3i}^dhX6YCRG~7GM2zx%*oLb-v6+bj(q9)C diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox.png index e61083c8943865fdab0c3e3ceefcdcbf7003fa97..dbee83aaba7aaf0a97e5a1c73550ec428974c457 100644 GIT binary patch delta 991 zcmV<510ek43B?JJBmt9=B`7d8I6;hpP#PK`R$60sdxK+RW1XFyb8~Y_N=lTJls`W| zii(PAYHB%ZK~d2k@bJ)V;y&Ah%a?OZ`wwE0EVk; zomcN`sEe_#T6Y0(Z9wM=YOZ5IZ`!p}_siAYpS#uaUb*$vPYn8MiRk4jpsQxx`Z{?- zh1zu!&}&q<_V@5wR}amD*S!Ng_q4D|Q&`{t^zAQKlNU z$u)p==XHM<(7jy(Li%Sw(1EH(H8P-bUU!uQpfez}QCV+z|KMl@0Cp>GPO}c|)4>|& zbvN3DXWML^o;Hf#Hs8{pUtXR!TeaQrNl@QzyuR56b+vnb-tG2kzvGi{=s(CNMu4xT zgTcx7&sm^7MrY}(c(i{W14e$VBtd25b`wn1fBAnkAWoCpIGN99hr^|CILzkrBtFXH z$A1Fae{wvg+2Vq5SY+w(I6WbK5aKvZ^DMgrWLci3aXcB1C$^&3x7U-3XHlMC0`feX z#p(o^6dvxucyw+&wawe<9CHB}K2C22E@<)r0^)VibzNaj?^2HMC*xgofPlVR7>KqY z@qvGWCk_=BPKLd&0ccwTz}ikAn9kY(;QQMs18orMa})u*LSWFSM;T}akTt_E$N*ay zOANR!0ylq*1;$#m=y1GJ=-k$_S2>>KxcMvNddnFIqpHuq_Rc7t5w2A(OW!)nHIx8c zMeEvLjce!;%C)ZNA)yWvYMvc>I4NmXRSth^=sGfg!x<2k&^sqZ!yftv#9I^Ii>QCs z!DRyQXdgWwyaW$`%T#>#HK3ay5OF*JVHp4>$omBSmry||o(ZTUNzK^<9QDoAzp?2_ z?Ct}g?Y9%U+V<@vz&HO1!giPurW|-U*h}*MJVVGfG=CXzo)JFVKd%E~KLRM~`~V98 N002ovPDHLkV1gQB(JBA{ delta 1021 zcmVQN|JqGD^ayL_Ies)86?~G1 zHdaz0epv(*6MTkvHo?Ov#z#28DR}+|tD_0S%+VFaw*-Hk7EL4m!Pf{TxQ@EfGk`O3hCn_2gpjLZj>rB0FMCRa|=E$wAQ!Xi|f|jx zIE9akYE`>Fxxfz9tIETbQlQ-5@RWdtYOfEo09%n|04GUnnQAH)DxK>~U`=7@7j z7<2a$6LKwdJ{*%%0deEF@o*Q%0)HR>D)1&iUWtkqH6a{@RBdei1Lv z^yCNp7sbRC;Je$wkmTm)%rhQ?1NyEW$3I;IMtMXcFBzqsd6(*b`Mn^Fqkr=-n$Kt3 z?J?MHXY+X!?)dA+hXKcbwA;nW;>fUFB=K%HeM9;*gkc<~NpdVmk~EIPaH?KX!0X%V zUWBtCO^*d>8q7kmM+`2}Q(qKKi$uTe4>d=E;m7_>V@liLgdEo|ix#@BlY0NoE%JS@ zC8j`&$tMP^Z(5DeN?<=w@P88rq{SrNHYWzz6tsFLu(o3iy0dl=U~J-h=iuu@yl<2DXGpgVxY5zX}gC%2``!MF#4W81^}u@ zfghuQ4E#C4`3u-VuAU6oN8pCD6By{LssF~R2X?v-g1X;KaIxv@Nr4;w6Nb%jN0>^W r%fSnWUk-N&K8E4X3mOi0gs<@*4+e4jGuI|+00000NkvXXu0mjfu$SL? diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox_primalis.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox_primalis.png index cfbd40f8db7b87ab599cdab5c60729367d079ae8..73dff7a6448784d36f06def690e6fb71da2627be 100644 GIT binary patch delta 1020 zcmVHlQztbzK};kdk3c&b8X;C%V`*z}cYA}Trln+cN|cn8KR-V@IzVb_ zYLR*;1R&7(osp%1f2K)9K~z|Ut(SpvqaYB5kp(nOD=OzTr01n=n)dzQ@czZLml0NP zI!8uH{MpZCMRudqO{;FsrM9IjO*oO3^_z2%Ph^ZC67EsK)Hx{GL1s4eR4G5yH-3}jtk9KF9X5Tc{2>OmR@o^^s?)RqNf7fPj1>Nn4+wNY_AG8Gl z_EMO&v+1KBBtm6PW9-U0Kn#tmBzumtg}oRfr41Y~@;Ygi?`-GMms_t|Zs-O3p$*>o zfWB-$v_H7DgFpzw7{bpG#vzpTb{Jqk;67!29L8}BH~=c@JqT!RFX##Im;i+l(A&Q4 zdmL>^PXl0le;89=1`ItMKqw?VV*W?OAr?l&Fot;s9D^~$0w7=z0CS%M`032{AmjiF zUAoON!Mm_rO*RIeeTre*hnT%DzSI5-;5C-h0$`ly2(}zY?@R{3ZsMN~$H!lf$HSA) z_Y|_wj|W&Ej?itk-l_5wuj?R^&t8Zv-FMgu<28U0f1BfC4qG~AaMh>lh{YVXba>eD zlZum@xKrK2N6bJ$iBp}GUoA<@NRDbXMmRe<|wcQ_@f8qORUv zUf$j=f9mqaU%sLLpY~p@R1b5js`pi$bG(#Xl@U|_jRQosE+dSoEmt3_F2I2g+tf{g zU~t)fY`6ddX_N`Z?w7(IiPyq>!(LfS_txw)!aiNZ{G{UH)4nkej?&X*6M8l+dJMqs%4>sx`FqQRRVVGfCd2ee~;y!hYK7&$0M-07wwU`v1?;MGFZy# z0$cYzl6-*xd*tnL?2D;)ZXwA?^92I(ZqEbK2!ZfdPNNq9q^*=;w*V>ea(>G_xB`&l zMF2uD19A^q25=b@Mf*gEslJ&}b|2N1ZFL@0M<7eGh_V5iCel`6p?+9OIa zqP9?3jrTbR06d1Q?5p@o=%w7B5U5O6LjKXD0>GbFbanP?^@Ey|{|eze*9dC^xHz~- q^5t4X$Zbyk7a{q*U#>O6ZTkZR08Up&ZQTt30000**H& delta 1019 zcmVjdg$+y3lC$9A^)EHAcodINvkA6g(jW({Vx&(z-`Uz{d;+5DMIv+5qST0)UkvO5*5V8wOevQ0irv zqmcJ$xte_8x07Hl*Rt9#vA6LrLA0yo^WX8)>Gkzw_;mUb{`TwF+v#l1C%&oT=ab;4a}_u5 zZ*TAKe;0Fk=bJC!|4;j9HmZkfYnqQuoHbs}{7#krI|qn-Tc>cY^;~^yx&Q}$`>yRO z3=WU|?*}e`fh@`d=l4rs58?GNe_(ICrzh|BD~7#1#Qe14;nTiz&w-@#0ucMaZagCJ z&t$z{6L@bQ5e!3yec<%bEL9wJ1LqKC$b%x^f6(3$(ggzKk7dro0}fw62PkZn0rn!B zSwv~I;pG89*4QcoWRFo!+%@r*mL#iVjImN8u25ioXyYVQiM`mA*C(>}5+QE?hW*dYL9d+dZ7 zjNQ;%LKt=mf!I$;e5m0vzEm&@!%kLN!keJF2LPb`yjpj47k1@Z0QRO%VESvlsM#Y* zrJ%Mj+9v~tCZfwmUd1P2)U;nHP?>CeLD5J75YHR9ImfN~!Cb|EgW-Iw5w<#Tad6S# p%dLjc+g1E8iuiq8ZZ*Pv`vXfMPC?dvrV{`F002ovPDHLkV1o0e@S^|# diff --git a/code/modules/unit_tests/~skyrat/loadout_dupes.dm b/code/modules/unit_tests/~skyrat/loadout_dupes.dm deleted file mode 100644 index 23bfe3689059e..0000000000000 --- a/code/modules/unit_tests/~skyrat/loadout_dupes.dm +++ /dev/null @@ -1,14 +0,0 @@ -///Checks that loadout items' item_paths are unique to the category of loadout item it belongs to -/datum/unit_test/loadout_dupes - -/datum/unit_test/loadout_dupes/Run() - var/list/item_paths = list() - for(var/datum/loadout_item/item as anything in subtypesof(/datum/loadout_item)) - var/loadout_item_category = initial(item.category) - var/item_path = initial(item.item_path) - if(item_paths[item_path] == loadout_item_category) - TEST_FAIL("Duplicate loadout item! [item_path] is already being used by [item].") - if(isnull(item_path)) // can be null, for subcategories of loadout items - continue - - item_paths[item_path] = loadout_item_category diff --git a/icons/obj/fluff/previews.dmi b/icons/obj/fluff/previews.dmi index c62b055f71efdd4ad3004a609435699c244944a1..8a69c1363189db811fd877a9368310c8aee58591 100644 GIT binary patch literal 8491 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 BirN4G literal 7799 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 diff --git a/modular_skyrat/master_files/code/modules/client/preferences.dm b/modular_skyrat/master_files/code/modules/client/preferences.dm index da1f0e282de66..90a1ce9c83aff 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences.dm @@ -1,8 +1,6 @@ #define MAX_MUTANT_ROWS 4 /datum/preferences - /// Loadout prefs. Assoc list of [typepaths] to [associated list of item info]. - var/list/loadout_list /// Associative list, keyed by language typepath, pointing to LANGUAGE_UNDERSTOOD, or LANGUAGE_SPOKEN, for whether we understand or speak the language var/list/languages = list() /// List of chosen augmentations. It's an associative list with key name of the slot, pointing to a typepath of an augment define diff --git a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm index d2cb359c89f90..567f825c25c57 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm @@ -66,16 +66,6 @@ background_info = sanitize_text(background_info) exploitable_info = sanitize_text(exploitable_info) - var/list/save_loadout = SANITIZE_LIST(save_data["loadout_list"]) - for(var/loadout in save_loadout) - var/entry = save_loadout[loadout] - save_loadout -= loadout - - if(istext(loadout)) - loadout = _text2path(loadout) - save_loadout[loadout] = entry - loadout_list = sanitize_loadout_list(save_loadout) - var/list/save_languages = SANITIZE_LIST(save_data["languages"]) for(var/language in save_languages) var/value = save_languages[language] @@ -267,7 +257,6 @@ /// Saves the modular customizations of a character on the savefile /datum/preferences/proc/save_character_skyrat(list/save_data) - save_data["loadout_list"] = loadout_list save_data["augments"] = augments save_data["augment_limb_styles"] = augment_limb_styles save_data["features"] = features diff --git a/modular_skyrat/master_files/code/modules/loadout/categories/accessories.dm b/modular_skyrat/master_files/code/modules/loadout/categories/accessories.dm new file mode 100644 index 0000000000000..beec66ae715fe --- /dev/null +++ b/modular_skyrat/master_files/code/modules/loadout/categories/accessories.dm @@ -0,0 +1,56 @@ +/* +* ARMBANDS +*/ + +/datum/loadout_item/accessory/armband_medblue + name = "Blue-White Armband" + item_path = /obj/item/clothing/accessory/armband/medblue/nonsec + +/datum/loadout_item/accessory/armband_med + name = "White Armband" + item_path = /obj/item/clothing/accessory/armband/med/nonsec + +/datum/loadout_item/accessory/armband_cargo + name = "Brown Armband" + item_path = /obj/item/clothing/accessory/armband/cargo/nonsec + +/datum/loadout_item/accessory/armband_engineering + name = "Orange Armband" + item_path = /obj/item/clothing/accessory/armband/engine/nonsec + +/datum/loadout_item/accessory/armband_security_nonsec + name = "Blue Armband" + item_path = /obj/item/clothing/accessory/armband/deputy/lopland/nonsec + +/datum/loadout_item/accessory/armband_security + name = "Security Armband" + item_path = /obj/item/clothing/accessory/armband/deputy/lopland + restricted_roles = list(JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_DETECTIVE, JOB_CORRECTIONS_OFFICER) + +/datum/loadout_item/accessory/armband_security_deputy + name = "Security Deputy Armband" + item_path = /obj/item/clothing/accessory/armband/deputy + restricted_roles = list(JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_DETECTIVE, JOB_CORRECTIONS_OFFICER) + +/datum/loadout_item/accessory/armband_science + name = "Purple Armband" + item_path = /obj/item/clothing/accessory/armband/science/nonsec + +/* +* ARMOURLESS +*/ + +/datum/loadout_item/accessory/bone_charm + name = "Heirloom Bone Talisman" + item_path = /obj/item/clothing/accessory/talisman/armourless + additional_displayed_text = list(TOOLTIP_NO_ARMOR) + +/datum/loadout_item/accessory/bone_codpiece + name = "Heirloom Skull Codpiece" + item_path = /obj/item/clothing/accessory/skullcodpiece/armourless + additional_displayed_text = list(TOOLTIP_NO_ARMOR) + +/datum/loadout_item/accessory/sinew_kilt + name = "Heirloom Sinew Skirt" + item_path = /obj/item/clothing/accessory/skilt/armourless + additional_displayed_text = list(TOOLTIP_NO_ARMOR) diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_belts.dm b/modular_skyrat/master_files/code/modules/loadout/categories/belts.dm similarity index 67% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_belts.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/belts.dm index eaca1035a2767..f482fcab18465 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_belts.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/belts.dm @@ -1,24 +1,16 @@ -/* -* LOADOUT ITEM DATUMS FOR THE BELT SLOT -*/ - -/// Belt Slot Items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_belts, generate_loadout_items(/datum/loadout_item/belts)) +/datum/loadout_category/belts + category_name = "Belts" + category_ui_icon = FA_ICON_USER_TIE + type_to_generate = /datum/loadout_item/belts + tab_order = /datum/loadout_category/head::tab_order + 6 /datum/loadout_item/belts - category = LOADOUT_ITEM_BELT - -/datum/loadout_item/belts/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) // don't bother storing in backpack, can't fit - if(initial(outfit_important_for_life.belt)) - return TRUE + abstract_type = /datum/loadout_item/belts -/datum/loadout_item/belts/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.belt) - LAZYADD(outfit.backpack_contents, outfit.belt) - outfit.belt = item_path - else - outfit.belt = item_path +/datum/loadout_item/belts/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.belt) + LAZYADD(outfit.backpack_contents, outfit.belt) + outfit.belt = item_path /datum/loadout_item/belts/fanny_pack_black name = "Black Fannypack" diff --git a/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm b/modular_skyrat/master_files/code/modules/loadout/categories/donator_personal.dm similarity index 100% rename from modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/donator_personal.dm diff --git a/modular_skyrat/master_files/code/modules/loadout/categories/ears.dm b/modular_skyrat/master_files/code/modules/loadout/categories/ears.dm new file mode 100644 index 0000000000000..b2d7118ad20d0 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/loadout/categories/ears.dm @@ -0,0 +1,21 @@ +/datum/loadout_category/ears + category_name = "Ears" + category_ui_icon = FA_ICON_EAR_LISTEN + type_to_generate = /datum/loadout_item/ears + tab_order = /datum/loadout_category/head::tab_order + 7 + +/datum/loadout_item/ears + abstract_type = /datum/loadout_item/ears + +/datum/loadout_item/ears/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.ears) + LAZYADD(outfit.backpack_contents, outfit.ears) + outfit.ears = item_path + +/datum/loadout_item/ears/headphones + name = "Headphones" + item_path = /obj/item/instrument/piano_synth/headphones + +/datum/loadout_item/ears/earmuffs + name = "Earmuffs" + item_path = /obj/item/clothing/ears/earmuffs diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_glasses.dm b/modular_skyrat/master_files/code/modules/loadout/categories/glasses.dm similarity index 86% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_glasses.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/glasses.dm index 0a1d94de1b577..0c104a252cbde 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_glasses.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/glasses.dm @@ -1,47 +1,11 @@ /* -* LOADOUT ITEM DATUMS FOR THE EYE SLOT -*/ - -/// Glasses Slot Items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_glasses, generate_loadout_items(/datum/loadout_item/glasses)) - -/datum/loadout_item/glasses - category = LOADOUT_ITEM_GLASSES - -/datum/loadout_item/glasses/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.glasses)) - .. () - return TRUE - -/datum/loadout_item/glasses/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.glasses) - LAZYADD(outfit.backpack_contents, outfit.glasses) - outfit.glasses = item_path - else - outfit.glasses = item_path - -/datum/loadout_item/glasses/post_equip_item(datum/preferences/preference_source, mob/living/carbon/human/equipper) - var/obj/item/clothing/glasses/equipped_glasses = locate(item_path) in equipper.get_equipped_items() - if (!equipped_glasses) - return - if(equipped_glasses.glass_colour_type) - equipper.update_glasses_color(equipped_glasses, TRUE) - if(equipped_glasses.tint) - equipper.update_tint() - if(equipped_glasses.vision_flags \ - || equipped_glasses.invis_override \ - || equipped_glasses.invis_view \ - || !isnull(equipped_glasses.color_cutoffs)) - equipper.update_sight() -/* * PRESCRIPTION GLASSES */ /datum/loadout_item/glasses/prescription_glasses name = "Glasses" item_path = /obj/item/clothing/glasses/regular - additional_tooltip_contents = list("PRESCRIPTION - This item functions with the 'nearsighted' quirk.") + additional_displayed_text = list("PRESCRIPTION") /datum/loadout_item/glasses/prescription_glasses/circle_glasses name = "Circle Glasses" @@ -111,9 +75,6 @@ GLOBAL_LIST_INIT(loadout_glasses, generate_loadout_items(/datum/loadout_item/gla name = "Medical Eyepatch" item_path = /obj/item/clothing/glasses/eyepatch/medical -/datum/loadout_item/glasses/blindfold - name = "Blindfold" - item_path = /obj/item/clothing/glasses/blindfold /datum/loadout_item/glasses/fakeblindfold name = "Fake Blindfold" @@ -289,9 +250,7 @@ GLOBAL_LIST_INIT(loadout_glasses, generate_loadout_items(/datum/loadout_item/gla * DONATOR */ -/datum/loadout_item/glasses/donator - donator_only = TRUE - -/datum/loadout_item/glasses/donator/fake_sunglasses +/datum/loadout_item/glasses/fake_sunglasses name = "Fake Sunglasses" item_path = /obj/item/clothing/glasses/fake_sunglasses + donator_only = TRUE diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_gloves.dm b/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm similarity index 75% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_gloves.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm index 3d78c20d1aa50..190c7a1db44e3 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_gloves.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm @@ -1,24 +1,20 @@ -/* -* LOADOUT ITEM DATUMS FOR THE HAND SLOT -*/ - -/// Glove Slot Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_gloves, generate_loadout_items(/datum/loadout_item/gloves)) +/datum/loadout_category/gloves + category_name = "Gloves" + category_ui_icon = FA_ICON_HAND + type_to_generate = /datum/loadout_item/gloves + tab_order = /datum/loadout_category/head::tab_order + 8 /datum/loadout_item/gloves - category = LOADOUT_ITEM_GLOVES + abstract_type = /datum/loadout_item/gloves -/datum/loadout_item/gloves/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.gloves)) - .. () - return TRUE - -/datum/loadout_item/gloves/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.gloves) - LAZYADD(outfit.backpack_contents, outfit.gloves) - outfit.gloves = item_path +/datum/loadout_item/gloves/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(equipper.dna?.species?.outfit_important_for_life) + if(!visuals_only) + to_chat(equipper, "Your loadout gloves were not equipped directly due to your species outfit.") + LAZYADD(outfit.backpack_contents, item_path) else + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.gloves) + LAZYADD(outfit.backpack_contents, outfit.gloves) outfit.gloves = item_path /datum/loadout_item/gloves/fingerless @@ -64,7 +60,7 @@ GLOBAL_LIST_INIT(loadout_gloves, generate_loadout_items(/datum/loadout_item/glov /datum/loadout_item/gloves/yellow name = "Yellow Gloves" item_path = /obj/item/clothing/gloves/color/ffyellow - additional_tooltip_contents = list("NON-INSULATING - This item is purely cosmetic and provide no shock insulation.") + additional_displayed_text = list("NON-INSULATING - This item is purely cosmetic and provide no shock insulation.") /datum/loadout_item/gloves/white name = "White Gloves" @@ -114,9 +110,7 @@ GLOBAL_LIST_INIT(loadout_gloves, generate_loadout_items(/datum/loadout_item/glov * DONATOR */ -/datum/loadout_item/gloves/donator - donator_only = TRUE - -/datum/loadout_item/gloves/donator/military +/datum/loadout_item/gloves/military name = "Military Gloves" item_path = /obj/item/clothing/gloves/military + donator_only = TRUE diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_heads.dm b/modular_skyrat/master_files/code/modules/loadout/categories/heads.dm similarity index 87% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_heads.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/heads.dm index f9bdd75292a5a..0180fff6ddc45 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_heads.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/heads.dm @@ -1,54 +1,7 @@ -/* -* LOADOUT ITEM DATUMS FOR THE HEAD SLOT -*/ - -/// Head Slot Items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_helmets, generate_loadout_items(/datum/loadout_item/head)) - -/datum/loadout_item/head - category = LOADOUT_ITEM_HEAD - -/datum/loadout_item/head/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.head)) - .. () - return TRUE - -/datum/loadout_item/head/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.head) - LAZYADD(outfit.backpack_contents, outfit.head) - outfit.head = item_path - else - outfit.head = item_path - /* * BEANIES */ -/datum/loadout_item/head/white_beanie - name = "Recolorable Beanie" - item_path = /obj/item/clothing/head/beanie - -/datum/loadout_item/head/black_beanie - name = "Black Beanie" - item_path = /obj/item/clothing/head/beanie/black - -/datum/loadout_item/head/red_beanie - name = "Red Beanie" - item_path = /obj/item/clothing/head/beanie/red - -/datum/loadout_item/head/dark_blue_beanie - name = "Dark Blue Beanie" - item_path = /obj/item/clothing/head/beanie/darkblue - -/datum/loadout_item/head/yellow_beanie - name = "Yellow Beanie" - item_path = /obj/item/clothing/head/beanie/yellow - -/datum/loadout_item/head/orange_beanie - name = "Orange Beanie" - item_path = /obj/item/clothing/head/beanie/orange - /datum/loadout_item/head/rastafarian name = "Rastafarian Cap" item_path = /obj/item/clothing/head/rasta @@ -61,11 +14,7 @@ GLOBAL_LIST_INIT(loadout_helmets, generate_loadout_items(/datum/loadout_item/hea * BERETS */ -/datum/loadout_item/head/greyscale_beret - name = "Greyscale Beret" - item_path = /obj/item/clothing/head/beret - -/datum/loadout_item/head/greyscale_beret/badge +/datum/loadout_item/head/beret_with_badge name = "Greyscale Beret with Badge" item_path = /obj/item/clothing/head/beret/badge @@ -385,12 +334,12 @@ GLOBAL_LIST_INIT(loadout_helmets, generate_loadout_items(/datum/loadout_item/hea /datum/loadout_item/head/maidhead name = "Simple Maid Headband" item_path = /obj/item/clothing/head/costume/skyrat/maid - additional_tooltip_contents = list("Small headband that only fits on top the head.") + additional_displayed_text = list("Small headband that only fits on top the head.") /datum/loadout_item/head/maidhead2 name = "Frilly Maid Headband" item_path = /obj/item/clothing/head/costume/maidheadband - additional_tooltip_contents = list("Larger headband from the maid rework. Fits around head and ears.") + additional_displayed_text = list("Larger headband from the maid rework. Fits around head and ears.") /datum/loadout_item/head/wig name = "Wig" @@ -645,57 +594,60 @@ GLOBAL_LIST_INIT(loadout_helmets, generate_loadout_items(/datum/loadout_item/hea name = "Deckers Hat" item_path = /obj/item/clothing/head/costume/deckers -/datum/loadout_item/head/saints - name = "Fancy Hat" - item_path = /obj/item/clothing/head/costume/fancy - /* * DONATOR */ -/datum/loadout_item/head/donator - donator_only = TRUE /* * FLOWERS */ -/datum/loadout_item/head/donator/poppy +/datum/loadout_item/head/poppy name = "Poppy Flower" item_path = /obj/item/food/grown/poppy + donator_only = TRUE -/datum/loadout_item/head/donator/lily +/datum/loadout_item/head/lily name = "Lily Flower" item_path = /obj/item/food/grown/poppy/lily + donator_only = TRUE -/datum/loadout_item/head/donator/geranium +/datum/loadout_item/head/geranium name = "Geranium Flower" item_path = /obj/item/food/grown/poppy/geranium + donator_only = TRUE -/datum/loadout_item/head/donator/fraxinella +/datum/loadout_item/head/fraxinella name = "Fraxinella Flower" item_path = /obj/item/food/grown/poppy/geranium/fraxinella + donator_only = TRUE -/datum/loadout_item/head/donator/harebell +/datum/loadout_item/head/harebell name = "Harebell Flower" item_path = /obj/item/food/grown/harebell + donator_only = TRUE -/datum/loadout_item/head/donator/rose +/datum/loadout_item/head/rose name = "Rose Flower" item_path = /obj/item/food/grown/rose + donator_only = TRUE -/datum/loadout_item/head/donator/carbon_rose +/datum/loadout_item/head/carbon_rose name = "Carbon Rose Flower" item_path = /obj/item/grown/carbon_rose + donator_only = TRUE -/datum/loadout_item/head/donator/sunflower +/datum/loadout_item/head/sunflower name = "Sunflower" item_path = /obj/item/food/grown/sunflower + donator_only = TRUE -/datum/loadout_item/head/donator/rainbow_bunch +/datum/loadout_item/head/rainbow_bunch name = "Rainbow Bunch" item_path = /obj/item/food/grown/rainbow_flower - additional_tooltip_contents = list(TOOLTIP_RANDOM_COLOR) + additional_displayed_text = list(TOOLTIP_RANDOM_COLOR) + donator_only = TRUE // Legacy unpaintable cowboy hat because it fits a character better /datum/loadout_item/head/cowboyhat_legacy diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_inhands.dm b/modular_skyrat/master_files/code/modules/loadout/categories/inhands.dm similarity index 63% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_inhands.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/inhands.dm index 7d3cb8ff7562c..c015049270824 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_inhands.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/inhands.dm @@ -1,27 +1,3 @@ -/* -* LOADOUT ITEM DATUMS FOR BOTH HAND SLOTS -*/ - -/// Inhand items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_inhand_items, generate_loadout_items(/datum/loadout_item/inhand)) - -/datum/loadout_item/inhand - category = LOADOUT_ITEM_INHAND - -/datum/loadout_item/inhand/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - // if no hands are available then put in backpack - if(initial(outfit_important_for_life.r_hand) && initial(outfit_important_for_life.l_hand)) - if(!visuals_only) - LAZYADD(outfit.backpack_contents, item_path) - return TRUE - -/datum/loadout_item/inhand/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(outfit.l_hand && !outfit.r_hand) - outfit.r_hand = item_path - else - if(outfit.l_hand) - LAZYADD(outfit.backpack_contents, outfit.l_hand) - outfit.l_hand = item_path /datum/loadout_item/inhand/cane name = "Cane" @@ -31,10 +7,6 @@ GLOBAL_LIST_INIT(loadout_inhand_items, generate_loadout_items(/datum/loadout_ite name = "Crutch" item_path = /obj/item/cane/crutch -/datum/loadout_item/inhand/cane/white - name = "White Cane" - item_path = /obj/item/cane/white - /datum/loadout_item/inhand/briefcase name = "Briefcase" item_path = /obj/item/storage/briefcase @@ -72,10 +44,6 @@ GLOBAL_LIST_INIT(loadout_inhand_items, generate_loadout_items(/datum/loadout_ite name = "Rose Bouquet" item_path = /obj/item/bouquet/rose -/datum/loadout_item/inhand/smokingpipe - name = "Smoking Pipe" - item_path = /obj/item/clothing/mask/cigarette/pipe - /datum/loadout_item/inhand/flag_nt name = "Folded Nanotrasen Flag" item_path = /obj/item/sign/flag/nanotrasen diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_masks.dm b/modular_skyrat/master_files/code/modules/loadout/categories/mask.dm similarity index 84% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_masks.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/mask.dm index 160ff263b0b68..b7de4ae7edd35 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_masks.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/mask.dm @@ -1,25 +1,16 @@ -/* -* LOADOUT ITEM DATUMS FOR THE MASK SLOT -*/ - -/// Mask Slot Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_masks, generate_loadout_items(/datum/loadout_item/mask)) +/datum/loadout_category/mask + category_name = "Masks" + category_ui_icon = FA_ICON_MASK + type_to_generate = /datum/loadout_item/mask + tab_order = /datum/loadout_category/head::tab_order + 12 /datum/loadout_item/mask - category = LOADOUT_ITEM_MASK - -/datum/loadout_item/mask/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.mask)) - ..() - return TRUE - -/datum/loadout_item/mask/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.mask) - LAZYADD(outfit.backpack_contents, outfit.mask) - outfit.mask = item_path - else - outfit.mask = item_path + abstract_type = /datum/loadout_item/mask + +/datum/loadout_item/mask/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.mask) + LAZYADD(outfit.backpack_contents, outfit.mask) + outfit.mask = item_path /* * BANDANAS diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_neck.dm b/modular_skyrat/master_files/code/modules/loadout/categories/neck.dm similarity index 86% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_neck.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/neck.dm index 5b8e042926ee1..f783703dc53e9 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_neck.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/neck.dm @@ -1,25 +1,3 @@ -/* -* LOADOUT ITEM DATUMS FOR THE NECK SLOT -*/ - -/// Neck Slot Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_necks, generate_loadout_items(/datum/loadout_item/neck)) - -/datum/loadout_item/neck - category = LOADOUT_ITEM_NECK - -/datum/loadout_item/neck/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.neck)) - .. () - return TRUE - -/datum/loadout_item/neck/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK) - if(outfit.neck) - LAZYADD(outfit.backpack_contents, outfit.neck && !visuals_only) - outfit.neck = item_path - else - outfit.neck = item_path /* @@ -66,9 +44,6 @@ GLOBAL_LIST_INIT(loadout_necks, generate_loadout_items(/datum/loadout_item/neck) name = "Yellow Scarf" item_path = /obj/item/clothing/neck/scarf/yellow -/datum/loadout_item/neck/scarf_white - name = "White Scarf" - item_path = /obj/item/clothing/neck/scarf /datum/loadout_item/neck/scarf_red_striped name = "Striped Red Scarf" @@ -86,10 +61,6 @@ GLOBAL_LIST_INIT(loadout_necks, generate_loadout_items(/datum/loadout_item/neck) name = "Zebra Scarf" item_path = /obj/item/clothing/neck/scarf/zebra -/datum/loadout_item/neck/scarf_infinity - name = "Infinity Scarf" - item_path = /obj/item/clothing/neck/infinity_scarf - /* * NECKTIES */ @@ -287,10 +258,6 @@ BUBBER EDIT END */ name = "Maid Neck Cover" item_path = /obj/item/clothing/neck/maid -/datum/loadout_item/neck/link_scryer - name = "MODlink Scryer" - item_path = /obj/item/clothing/neck/link_scryer/loaded - /datum/loadout_item/neck/holobadge name = "Holobadge" item_path = /obj/item/clothing/accessory/badge/holo diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_pocket.dm b/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm similarity index 99% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_pocket.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm index b84a5ace07636..67087ff72cc25 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_pocket.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm @@ -354,4 +354,4 @@ GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_ite /datum/loadout_item/pocket_items/donator/vape name = "E-Cigarette" - item_path = /obj/item/clothing/mask/vape \ No newline at end of file + item_path = /obj/item/clothing/mask/vape diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_shoes.dm b/modular_skyrat/master_files/code/modules/loadout/categories/shoes.dm similarity index 89% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_shoes.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/shoes.dm index 71d665a904e53..2dc0c1ff29d07 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_shoes.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/shoes.dm @@ -1,25 +1,16 @@ -/* -* LOADOUT ITEM DATUMS FOR THE SHOE SLOT -*/ - -/// Shoe Slot Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_shoes, generate_loadout_items(/datum/loadout_item/shoes)) +/datum/loadout_category/shoes + category_name = "Shoes" + category_ui_icon = FA_ICON_SHOE_PRINTS + type_to_generate = /datum/loadout_item/shoes + tab_order = /datum/loadout_category/head::tab_order + 11 /datum/loadout_item/shoes - category = LOADOUT_ITEM_SHOES - -/datum/loadout_item/shoes/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.shoes)) - .. () - return TRUE - -/datum/loadout_item/shoes/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.shoes) - LAZYADD(outfit.backpack_contents, outfit.shoes) - outfit.shoes = item_path - else - outfit.shoes = item_path + abstract_type = /datum/loadout_item/shoes + +/datum/loadout_item/shoes/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.shoes) + LAZYADD(outfit.backpack_contents, outfit.shoes) + outfit.shoes = item_path /* * JACKBOOTS diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm b/modular_skyrat/master_files/code/modules/loadout/categories/suit.dm similarity index 96% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/suit.dm index 11ba23c667b26..bda99eccec66c 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/suit.dm @@ -1,24 +1,16 @@ -/* -* LOADOUT ITEM DATUMS FOR THE (EXO/OUTER)SUIT SLOT -*/ - -/// Exosuit / Outersuit Slot Items (Moves items to backpack) -GLOBAL_LIST_INIT(loadout_exosuits, generate_loadout_items(/datum/loadout_item/suit)) +/datum/loadout_category/suit + category_name = "Suits" + category_ui_icon = FA_ICON_TOILET + type_to_generate = /datum/loadout_item/suit + tab_order = /datum/loadout_category/head::tab_order + 10 /datum/loadout_item/suit - category = LOADOUT_ITEM_SUIT - -/datum/loadout_item/suit/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) // don't bother storing in backpack, can't fit - if(initial(outfit_important_for_life.suit)) - return TRUE - -/datum/loadout_item/suit/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.suit) - LAZYADD(outfit.backpack_contents, outfit.suit) - outfit.suit = item_path - else - outfit.suit = item_path + abstract_type = /datum/loadout_item/suit + +/datum/loadout_item/suit/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.suit) + LAZYADD(outfit.backpack_contents, outfit.suit) + outfit.suit = item_path /* * WINTER COATS diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm b/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm similarity index 96% rename from modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/toys.dm index cfb0cc14e3af4..e6315cda2dcc0 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_toys.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm @@ -1,14 +1,11 @@ -GLOBAL_LIST_INIT(loadout_toys, generate_loadout_items(/datum/loadout_item/toys)) +/datum/loadout_category/toys + category_name = "Toys" + category_ui_icon = FA_ICON_GOLF_BALL + type_to_generate = /datum/loadout_item/toys + tab_order = /datum/loadout_category/head::tab_order + 13 /datum/loadout_item/toys - category = LOADOUT_ITEM_TOYS - -/* -* PLUSHIES -*/ - -/datum/loadout_item/toys/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) // these go in the backpack - return FALSE + abstract_type = /datum/loadout_item/toys /datum/loadout_item/toys/bee name = "Bee Plushie" diff --git a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm b/modular_skyrat/master_files/code/modules/loadout/categories/uniform.dm similarity index 64% rename from modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm rename to modular_skyrat/master_files/code/modules/loadout/categories/uniform.dm index 9269b02860a2a..fe44fdcc656b4 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/uniform.dm @@ -1,244 +1,233 @@ - -// --- Loadout item datums for under suits --- - -/// Underslot - Jumpsuit Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_jumpsuits, generate_loadout_items(/datum/loadout_item/under/jumpsuit)) - -/// Underslot - Formal Suit Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_undersuits, generate_loadout_items(/datum/loadout_item/under/formal)) - -/// Underslot - Misc. Under Items (Deletes overrided items) -GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/under/miscellaneous)) - -/datum/loadout_item/under - category = LOADOUT_ITEM_UNIFORM - -/datum/loadout_item/under/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.uniform)) - .. () - return TRUE - -/datum/loadout_item/under/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.uniform) - LAZYADD(outfit.backpack_contents, outfit.uniform) - outfit.uniform = item_path +/datum/loadout_category/uniform + category_name = "Uniform" + category_ui_icon = FA_ICON_SHIRT + type_to_generate = /datum/loadout_item/uniform + tab_order = /datum/loadout_category/head::tab_order + 9 + +/datum/loadout_item/uniform + abstract_type = /datum/loadout_item/uniform + +/datum/loadout_item/uniform/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only, loadout_placement_preference) + if(equipper.dna?.species?.outfit_important_for_life) + if(!visuals_only) + to_chat(equipper, "Your loadout uniform was not equipped directly due to your species outfit.") + LAZYADD(outfit.backpack_contents, item_path) else + if(loadout_placement_preference != LOADOUT_OVERRIDE_JOB && outfit.uniform) + LAZYADD(outfit.backpack_contents, outfit.uniform) outfit.uniform = item_path - outfit.modified_outfit_slots |= ITEM_SLOT_ICLOTHING + /* * JUMPSUITS */ -/datum/loadout_item/under/jumpsuit - -/datum/loadout_item/under/jumpsuit/greyscale +/datum/loadout_item/uniform/jumpsuit/greyscale name = "Greyscale Jumpsuit" item_path = /obj/item/clothing/under/color -/datum/loadout_item/under/jumpsuit/greyscale_skirt +/datum/loadout_item/uniform/jumpsuit/greyscale_skirt name = "Greyscale Jumpskirt" item_path = /obj/item/clothing/under/color/jumpskirt -/datum/loadout_item/under/jumpsuit/random +/datum/loadout_item/uniform/jumpsuit/random name = "Random Jumpsuit" item_path = /obj/item/clothing/under/color/random - additional_tooltip_contents = list(TOOLTIP_RANDOM_COLOR) + additional_displayed_text = list(TOOLTIP_RANDOM_COLOR) -/datum/loadout_item/under/jumpsuit/random_skirt +/datum/loadout_item/uniform/jumpsuit/random_skirt name = "Random Jumpskirt" item_path = /obj/item/clothing/under/color/jumpskirt/random - additional_tooltip_contents = list(TOOLTIP_RANDOM_COLOR) + additional_displayed_text = list(TOOLTIP_RANDOM_COLOR) -/datum/loadout_item/under/jumpsuit/rainbow +/datum/loadout_item/uniform/jumpsuit/rainbow name = "Rainbow Jumpsuit" item_path = /obj/item/clothing/under/color/rainbow -/datum/loadout_item/under/jumpsuit/rainbow_skirt +/datum/loadout_item/uniform/jumpsuit/rainbow_skirt name = "Rainbow Jumpskirt" item_path = /obj/item/clothing/under/color/jumpskirt/rainbow -/datum/loadout_item/under/jumpsuit/akula_wetsuit +/datum/loadout_item/uniform/jumpsuit/akula_wetsuit name = "Shoredress Wetsuit" item_path = /obj/item/clothing/under/akula_wetsuit -/datum/loadout_item/under/jumpsuit/impcap +/datum/loadout_item/uniform/jumpsuit/impcap name = "Captain's Naval Jumpsuit" item_path = /obj/item/clothing/under/rank/captain/skyrat/imperial restricted_roles = list(JOB_CAPTAIN, JOB_NT_REP) -/datum/loadout_item/under/jumpsuit/imphop +/datum/loadout_item/uniform/jumpsuit/imphop name = "Head of Personnel's Naval Jumpsuit" item_path = /obj/item/clothing/under/rank/civilian/head_of_personnel/skyrat/imperial restricted_roles = list(JOB_HEAD_OF_PERSONNEL, JOB_NT_REP) -/datum/loadout_item/under/jumpsuit/imphos +/datum/loadout_item/uniform/jumpsuit/imphos name = "Head of Security's Naval Uniform" item_path = /obj/item/clothing/under/rank/security/head_of_security/skyrat/imperial restricted_roles = list(JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/impcmo +/datum/loadout_item/uniform/jumpsuit/impcmo name = "Chief Medical Officer's Naval Uniform" item_path = /obj/item/clothing/under/rank/medical/chief_medical_officer/skyrat/imperial restricted_roles = list(JOB_CHIEF_MEDICAL_OFFICER) -/datum/loadout_item/under/jumpsuit/impce +/datum/loadout_item/uniform/jumpsuit/impce name = "Chief Engineer's Naval Uniform" item_path = /obj/item/clothing/under/rank/engineering/chief_engineer/skyrat/imperial restricted_roles = list(JOB_CHIEF_ENGINEER) -/datum/loadout_item/under/jumpsuit/imprd +/datum/loadout_item/uniform/jumpsuit/imprd name = "Research Director's Naval Uniform" item_path = /obj/item/clothing/under/rank/rnd/research_director/skyrat/imperial restricted_roles = list(JOB_RESEARCH_DIRECTOR) -/datum/loadout_item/under/jumpsuit/impcommand +/datum/loadout_item/uniform/jumpsuit/impcommand name = "Light Grey Officer's Naval Jumpsuit" item_path = /obj/item/clothing/under/rank/captain/skyrat/imperial/generic -/datum/loadout_item/under/jumpsuit/impcom +/datum/loadout_item/uniform/jumpsuit/impcom name = "Grey Officer's Naval Jumpsuit" item_path = /obj/item/clothing/under/rank/captain/skyrat/imperial/generic/grey -/datum/loadout_item/under/jumpsuit/impred +/datum/loadout_item/uniform/jumpsuit/impred name = "Red Officer's Naval Jumpsuit" item_path = /obj/item/clothing/under/rank/captain/skyrat/imperial/generic/red -/datum/loadout_item/under/jumpsuit/impcomtrous +/datum/loadout_item/uniform/jumpsuit/impcomtrous name = "Grey Officer's Naval Jumpsuit (Trousers)" item_path = /obj/item/clothing/under/rank/captain/skyrat/imperial/generic/pants -/datum/loadout_item/under/jumpsuit/security_skirt +/datum/loadout_item/uniform/jumpsuit/security_skirt name = "Security Battledress" item_path = /obj/item/clothing/under/rank/security/peacekeeper/skirt restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_trousers +/datum/loadout_item/uniform/jumpsuit/security_trousers name = "Security Trousers" item_path = /obj/item/clothing/under/rank/security/peacekeeper/trousers restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY, JOB_SECURITY_MEDIC) -/datum/loadout_item/under/jumpsuit/security_shorts +/datum/loadout_item/uniform/jumpsuit/security_shorts name = "Security Shorts" item_path = /obj/item/clothing/under/rank/security/peacekeeper/trousers/shorts restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_jumpskirt +/datum/loadout_item/uniform/jumpsuit/security_jumpskirt name = "Security Jumpskirt" item_path = /obj/item/clothing/under/rank/security/officer/skirt restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_shortskirt +/datum/loadout_item/uniform/jumpsuit/security_shortskirt name = "Security Shortskirt" item_path = /obj/item/clothing/under/rank/security/peacekeeper/shortskirt restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_miniskirt +/datum/loadout_item/uniform/jumpsuit/security_miniskirt name = "Security Miniskirt" item_path = /obj/item/clothing/under/rank/security/peacekeeper/miniskirt restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_jumpsuit +/datum/loadout_item/uniform/jumpsuit/security_jumpsuit name = "Security Jumpsuit" item_path = /obj/item/clothing/under/rank/security/peacekeeper/jumpsuit restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) -/datum/loadout_item/under/jumpsuit/security_peacekeeper +/datum/loadout_item/uniform/jumpsuit/security_peacekeeper name = "Security Peacekeeper Uniform" item_path = /obj/item/clothing/under/rank/security/peacekeeper restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY, JOB_SECURITY_MEDIC) -/datum/loadout_item/under/jumpsuit/imperial_police_uniform +/datum/loadout_item/uniform/jumpsuit/imperial_police_uniform name = "Imperial Police Uniform" item_path = /obj/item/clothing/under/colonial/nri_police restricted_roles = list(JOB_SECURITY_OFFICER, JOB_DETECTIVE) -/datum/loadout_item/under/jumpsuit/disco +/datum/loadout_item/uniform/jumpsuit/disco name = "Superstar Cop Uniform" item_path = /obj/item/clothing/under/rank/security/detective/disco -/datum/loadout_item/under/jumpsuit/kim +/datum/loadout_item/uniform/jumpsuit/kim name = "Aerostatic Suit" item_path = /obj/item/clothing/under/rank/security/detective/kim -/datum/loadout_item/under/jumpsuit/paramed_light +/datum/loadout_item/uniform/jumpsuit/paramed_light name = "Light Paramedic Uniform" item_path = /obj/item/clothing/under/rank/medical/paramedic/skyrat/light -/datum/loadout_item/under/jumpsuit/paramed_light_skirt +/datum/loadout_item/uniform/jumpsuit/paramed_light_skirt name = "Light Paramedic Skirt" item_path = /obj/item/clothing/under/rank/medical/paramedic/skyrat/light/skirt -/datum/loadout_item/under/jumpsuit/chemist_formal +/datum/loadout_item/uniform/jumpsuit/chemist_formal name = "Chemist's Formal Jumpsuit" item_path = /obj/item/clothing/under/rank/medical/chemist/skyrat/formal -/datum/loadout_item/under/jumpsuit/chemist_formal_skirt +/datum/loadout_item/uniform/jumpsuit/chemist_formal_skirt name = "Chemist's Formal Jumpskirt" item_path = /obj/item/clothing/under/rank/medical/chemist/skyrat/formal/skirt -/datum/loadout_item/under/jumpsuit/viro_jumpsuit +/datum/loadout_item/uniform/jumpsuit/viro_jumpsuit name = "Virologist's Jumpsuit" item_path = /obj/item/clothing/under/rank/medical/virologist -/datum/loadout_item/under/jumpsuit/hlscientist +/datum/loadout_item/uniform/jumpsuit/hlscientist name = "Ridiculous Scientist Outfit" item_path = /obj/item/clothing/under/rank/rnd/scientist/skyrat/hlscience -/datum/loadout_item/under/jumpsuit/rd_jumpsuit +/datum/loadout_item/uniform/jumpsuit/rd_jumpsuit name = "Research Director's Jumpsuit" item_path = /obj/item/clothing/under/rank/rnd/research_director/skyrat/jumpsuit restricted_roles = list(JOB_RESEARCH_DIRECTOR) -/datum/loadout_item/under/jumpsuit/rd_jumpskirt +/datum/loadout_item/uniform/jumpsuit/rd_jumpskirt name = "Research Director's Jumpskirt" item_path = /obj/item/clothing/under/rank/rnd/research_director/skyrat/jumpsuit/skirt restricted_roles = list(JOB_RESEARCH_DIRECTOR) -/datum/loadout_item/under/jumpsuit/cargo +/datum/loadout_item/uniform/jumpsuit/cargo name = "Cargo Technician's Jumpsuit" item_path = /obj/item/clothing/under/rank/cargo/tech -/datum/loadout_item/under/jumpsuit/cargo/skirt +/datum/loadout_item/uniform/jumpsuit/cargo/skirt name = "Cargo Technician's Skirt" item_path = /obj/item/clothing/under/rank/cargo/tech/skirt -/datum/loadout_item/under/jumpsuit/cargo/skirt/alt +/datum/loadout_item/uniform/jumpsuit/cargo/skirt/alt name = "Cargo Technician's Shortskirt" item_path = /obj/item/clothing/under/rank/cargo/tech/skirt/alt -/datum/loadout_item/under/jumpsuit/cargo/qm +/datum/loadout_item/uniform/jumpsuit/cargo/qm name = "Quartermaster's Uniform" item_path = /obj/item/clothing/under/rank/cargo/qm restricted_roles = list(JOB_QUARTERMASTER) -/datum/loadout_item/under/jumpsuit/utility +/datum/loadout_item/uniform/jumpsuit/utility name = "Utility Uniform" item_path = /obj/item/clothing/under/misc/skyrat/utility -/datum/loadout_item/under/jumpsuit/utility_eng +/datum/loadout_item/uniform/jumpsuit/utility_eng name = "Engineering Utility Uniform" item_path = /obj/item/clothing/under/rank/engineering/engineer/skyrat/utility -/datum/loadout_item/under/jumpsuit/utility_med +/datum/loadout_item/uniform/jumpsuit/utility_med name = "Medical Utility Uniform" item_path = /obj/item/clothing/under/rank/medical/doctor/skyrat/utility -/datum/loadout_item/under/jumpsuit/utility_sci +/datum/loadout_item/uniform/jumpsuit/utility_sci name = "Science Utility Uniform" item_path = /obj/item/clothing/under/rank/rnd/scientist/skyrat/utility -/datum/loadout_item/under/jumpsuit/utility_cargo +/datum/loadout_item/uniform/jumpsuit/utility_cargo name = "Supply Utility Uniform" item_path = /obj/item/clothing/under/rank/cargo/tech/skyrat/utility -/datum/loadout_item/under/jumpsuit/utility_sec +/datum/loadout_item/uniform/jumpsuit/utility_sec name = "Security Utility Uniform" item_path = /obj/item/clothing/under/rank/security/skyrat/utility restricted_roles = list(JOB_SECURITY_OFFICER, JOB_DETECTIVE, JOB_WARDEN, JOB_BLUESHIELD, JOB_HEAD_OF_SECURITY, JOB_CORRECTIONS_OFFICER) -/datum/loadout_item/under/jumpsuit/utility_com +/datum/loadout_item/uniform/jumpsuit/utility_com name = "Command Utility Uniform" item_path = /obj/item/clothing/under/rank/captain/skyrat/utility restricted_roles = list(JOB_CAPTAIN, JOB_HEAD_OF_PERSONNEL, JOB_BLUESHIELD, JOB_HEAD_OF_SECURITY, JOB_RESEARCH_DIRECTOR, JOB_QUARTERMASTER, JOB_CHIEF_MEDICAL_OFFICER, JOB_CHIEF_ENGINEER) @@ -247,422 +236,422 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ * MISC UNDERSUITS */ -/datum/loadout_item/under/miscellaneous +/datum/loadout_item/uniform/miscellaneous -/datum/loadout_item/under/miscellaneous/christmas +/datum/loadout_item/uniform/miscellaneous/christmas name = "Christmas Suit" item_path = /obj/item/clothing/under/costume/skyrat/christmas -/datum/loadout_item/under/miscellaneous/christmas/green +/datum/loadout_item/uniform/miscellaneous/christmas/green name = "Green Christmas Suit" item_path = /obj/item/clothing/under/costume/skyrat/christmas/green -/datum/loadout_item/under/miscellaneous/christmas/female +/datum/loadout_item/uniform/miscellaneous/christmas/female name = "Revealing Christmas Suit" item_path = /obj/item/clothing/under/costume/skyrat/christmas/croptop -/datum/loadout_item/under/miscellaneous/christmas/female/green +/datum/loadout_item/uniform/miscellaneous/christmas/female/green name = "Revealing Green Christmas Suit" item_path = /obj/item/clothing/under/costume/skyrat/christmas/croptop/green -/datum/loadout_item/under/miscellaneous/buttondown +/datum/loadout_item/uniform/miscellaneous/buttondown name = "Recolorable Buttondown Shirt with Slacks" item_path = /obj/item/clothing/under/costume/buttondown/slacks -/datum/loadout_item/under/miscellaneous/buttondown_shorts +/datum/loadout_item/uniform/miscellaneous/buttondown_shorts name = "Recolorable Buttondown Shirt with Shorts" item_path = /obj/item/clothing/under/costume/buttondown/shorts -/datum/loadout_item/under/miscellaneous/buttondown_skirt +/datum/loadout_item/uniform/miscellaneous/buttondown_skirt name = "Recolorable Buttondown Shirt with Skirt" item_path = /obj/item/clothing/under/costume/buttondown/skirt -/datum/loadout_item/under/miscellaneous/vicvest +/datum/loadout_item/uniform/miscellaneous/vicvest name = "Recolorable Buttondown Shirt with Double-Breasted Vest" item_path = /obj/item/clothing/under/pants/skyrat/vicvest -/datum/loadout_item/under/miscellaneous/slacks +/datum/loadout_item/uniform/miscellaneous/slacks name = "Recolorable Slacks" item_path = /obj/item/clothing/under/pants/slacks -/datum/loadout_item/under/miscellaneous/jeans +/datum/loadout_item/uniform/miscellaneous/jeans name = "Recolorable Jeans" item_path = /obj/item/clothing/under/pants/jeans -/datum/loadout_item/under/miscellaneous/jeansripped +/datum/loadout_item/uniform/miscellaneous/jeansripped name = "Recolorable Ripped Jeans" item_path = /obj/item/clothing/under/pants/skyrat/jeans_ripped -/datum/loadout_item/under/miscellaneous/yoga +/datum/loadout_item/uniform/miscellaneous/yoga name = "Recolorable Yoga Pants" item_path = /obj/item/clothing/under/pants/skyrat/yoga -/datum/loadout_item/under/miscellaneous/track +/datum/loadout_item/uniform/miscellaneous/track name = "Track Pants" item_path = /obj/item/clothing/under/pants/track -/datum/loadout_item/under/miscellaneous/camo +/datum/loadout_item/uniform/miscellaneous/camo name = "Camo Pants" item_path = /obj/item/clothing/under/pants/camo -/datum/loadout_item/under/miscellaneous/jeanshorts //This doesnt look like a word. Short. Jean-Short. Eugh. +/datum/loadout_item/uniform/miscellaneous/jeanshorts //This doesnt look like a word. Short. Jean-Short. Eugh. name = "Recolorable Jean Shorts" item_path = /obj/item/clothing/under/shorts/jeanshorts -/datum/loadout_item/under/miscellaneous/pants_blackshorts +/datum/loadout_item/uniform/miscellaneous/pants_blackshorts name = "Recolorable Ripped Jean Shorts" item_path = /obj/item/clothing/under/shorts/skyrat/shorts_ripped -/datum/loadout_item/under/miscellaneous/shortershorts +/datum/loadout_item/uniform/miscellaneous/shortershorts name = "Recolorable Shorter Shorts" item_path = /obj/item/clothing/under/shorts/skyrat/shortershorts -/datum/loadout_item/under/miscellaneous/shorts +/datum/loadout_item/uniform/miscellaneous/shorts name = "Recolorable Shorts" item_path = /obj/item/clothing/under/shorts -/datum/loadout_item/under/miscellaneous/red_short +/datum/loadout_item/uniform/miscellaneous/red_short name = "Red Shorts" item_path = /obj/item/clothing/under/shorts/red -/datum/loadout_item/under/miscellaneous/green_short +/datum/loadout_item/uniform/miscellaneous/green_short name = "Green Shorts" item_path = /obj/item/clothing/under/shorts/green -/datum/loadout_item/under/miscellaneous/blue_short +/datum/loadout_item/uniform/miscellaneous/blue_short name = "Blue Shorts" item_path = /obj/item/clothing/under/shorts/blue -/datum/loadout_item/under/miscellaneous/black_short +/datum/loadout_item/uniform/miscellaneous/black_short name = "Black Shorts" item_path = /obj/item/clothing/under/shorts/black -/datum/loadout_item/under/miscellaneous/grey_short +/datum/loadout_item/uniform/miscellaneous/grey_short name = "Grey Shorts" item_path = /obj/item/clothing/under/shorts/grey -/datum/loadout_item/under/miscellaneous/purple_short +/datum/loadout_item/uniform/miscellaneous/purple_short name = "Purple Shorts" item_path = /obj/item/clothing/under/shorts/purple -/datum/loadout_item/under/miscellaneous/recolorable_kilt +/datum/loadout_item/uniform/miscellaneous/recolorable_kilt name = "Recolorable Kilt" item_path = /obj/item/clothing/under/pants/skyrat/kilt //TODO: split loadout's miscellaneous to have "Pants/Shorts" and "Dresses/Skirts" as options too. Misc is stupid. -/datum/loadout_item/under/miscellaneous/dress_striped +/datum/loadout_item/uniform/miscellaneous/dress_striped name = "Striped Dress" item_path = /obj/item/clothing/under/dress/striped -/datum/loadout_item/under/miscellaneous/skirt_black +/datum/loadout_item/uniform/miscellaneous/skirt_black name = "Black Skirt" item_path = /obj/item/clothing/under/dress/skirt -/datum/loadout_item/under/miscellaneous/skirt_plaid +/datum/loadout_item/uniform/miscellaneous/skirt_plaid name = "Recolorable Plaid Skirt" item_path = /obj/item/clothing/under/dress/skirt/plaid -/datum/loadout_item/under/miscellaneous/skirt_turtleneck +/datum/loadout_item/uniform/miscellaneous/skirt_turtleneck name = "Recolorable Turtleneck Skirt" item_path = /obj/item/clothing/under/dress/skirt/turtleskirt -/datum/loadout_item/under/miscellaneous/skirt_cableknit +/datum/loadout_item/uniform/miscellaneous/skirt_cableknit name = "Recolorable Cableknit Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/turtleskirt_knit -/datum/loadout_item/under/miscellaneous/dress_tango +/datum/loadout_item/uniform/miscellaneous/dress_tango name = "Recolorable Tango Dress" item_path = /obj/item/clothing/under/dress/tango -/datum/loadout_item/under/miscellaneous/dress_sun +/datum/loadout_item/uniform/miscellaneous/dress_sun name = "Recolorable Sundress" item_path = /obj/item/clothing/under/dress/sundress -/datum/loadout_item/under/miscellaneous/straplessdress +/datum/loadout_item/uniform/miscellaneous/straplessdress name = "Recolorable Strapless Dress" item_path = /obj/item/clothing/under/dress/skyrat/strapless -/datum/loadout_item/under/miscellaneous/pentagramdress +/datum/loadout_item/uniform/miscellaneous/pentagramdress name = "Recolorable Pentagram Strapped Dress" item_path = /obj/item/clothing/under/dress/skyrat/pentagram -/datum/loadout_item/under/miscellaneous/jacarta_dress +/datum/loadout_item/uniform/miscellaneous/jacarta_dress name = "Jacarta Dress" item_path = /obj/item/clothing/under/dress/skyrat/jute -/datum/loadout_item/under/miscellaneous/striped_skirt +/datum/loadout_item/uniform/miscellaneous/striped_skirt name = "Red Striped Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/striped_skirt -/datum/loadout_item/under/miscellaneous/red_skirt +/datum/loadout_item/uniform/miscellaneous/red_skirt name = "Red Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/red_skirt -/datum/loadout_item/under/miscellaneous/black_skirt +/datum/loadout_item/uniform/miscellaneous/black_skirt name = "Black Skirt (Skyrat)" item_path = /obj/item/clothing/under/dress/skirt/skyrat/black_skirt -/datum/loadout_item/under/miscellaneous/swept_skirt +/datum/loadout_item/uniform/miscellaneous/swept_skirt name = "Swept Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/swept -/datum/loadout_item/under/miscellaneous/lone_skirt +/datum/loadout_item/uniform/miscellaneous/lone_skirt name = "Recolorable Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/lone_skirt -/datum/loadout_item/under/miscellaneous/medium_skirt +/datum/loadout_item/uniform/miscellaneous/medium_skirt name = "Medium Colourable Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/medium -/datum/loadout_item/under/miscellaneous/long_skirt +/datum/loadout_item/uniform/miscellaneous/long_skirt name = "Long Colourable Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/long -/datum/loadout_item/under/miscellaneous/denim_skirt +/datum/loadout_item/uniform/miscellaneous/denim_skirt name = "Jean Skirt" item_path = /obj/item/clothing/under/dress/skirt/skyrat/jean -/datum/loadout_item/under/miscellaneous/littleblack +/datum/loadout_item/uniform/miscellaneous/littleblack name = "Short Black Dress" item_path = /obj/item/clothing/under/dress/skyrat/short_dress -/datum/loadout_item/under/miscellaneous/pinktutu +/datum/loadout_item/uniform/miscellaneous/pinktutu name = "Pink Tutu" item_path = /obj/item/clothing/under/dress/skyrat/pinktutu -/datum/loadout_item/under/miscellaneous/flowerdress +/datum/loadout_item/uniform/miscellaneous/flowerdress name = "Flower Dress" item_path = /obj/item/clothing/under/dress/skyrat/flower -/datum/loadout_item/under/miscellaneous/kilt +/datum/loadout_item/uniform/miscellaneous/kilt name = "Kilt" item_path = /obj/item/clothing/under/costume/kilt -/datum/loadout_item/under/miscellaneous/treasure_hunter +/datum/loadout_item/uniform/miscellaneous/treasure_hunter name = "Treasure Hunter" item_path = /obj/item/clothing/under/rank/civilian/curator/treasure_hunter -/datum/loadout_item/under/miscellaneous/jester +/datum/loadout_item/uniform/miscellaneous/jester name = "Jester Suit" item_path = /obj/item/clothing/under/rank/civilian/clown/jester -/datum/loadout_item/under/miscellaneous/jesteralt +/datum/loadout_item/uniform/miscellaneous/jesteralt name = "Jeset Suit (Alt)" item_path = /obj/item/clothing/under/rank/civilian/clown/jesteralt -/datum/loadout_item/under/miscellaneous/overalls +/datum/loadout_item/uniform/miscellaneous/overalls name = "Overalls" item_path = /obj/item/clothing/under/misc/overalls -/datum/loadout_item/under/miscellaneous/pj_blue +/datum/loadout_item/uniform/miscellaneous/pj_blue name = "Mailman Jumpsuit" item_path = /obj/item/clothing/under/misc/mailman -/datum/loadout_item/under/miscellaneous/vice_officer +/datum/loadout_item/uniform/miscellaneous/vice_officer name = "Vice Officer Jumpsuit" item_path = /obj/item/clothing/under/misc/vice_officer -/datum/loadout_item/under/miscellaneous/soviet +/datum/loadout_item/uniform/miscellaneous/soviet name = "Soviet Uniform" item_path = /obj/item/clothing/under/costume/soviet -/datum/loadout_item/under/miscellaneous/redcoat +/datum/loadout_item/uniform/miscellaneous/redcoat name = "Redcoat" item_path = /obj/item/clothing/under/costume/redcoat -/datum/loadout_item/under/miscellaneous/pj_red +/datum/loadout_item/uniform/miscellaneous/pj_red name = "Red PJs" item_path = /obj/item/clothing/under/misc/pj/red -/datum/loadout_item/under/miscellaneous/pj_blue +/datum/loadout_item/uniform/miscellaneous/pj_blue name = "Blue PJs" item_path = /obj/item/clothing/under/misc/pj/blue -/datum/loadout_item/under/miscellaneous/tactical_hawaiian_orange +/datum/loadout_item/uniform/miscellaneous/tactical_hawaiian_orange name = "Tactical Hawaiian Outfit - Orange" item_path = /obj/item/clothing/under/tachawaiian -/datum/loadout_item/under/miscellaneous/tactical_hawaiian_blue +/datum/loadout_item/uniform/miscellaneous/tactical_hawaiian_blue name = "Tactical Hawaiian Outfit - Blue" item_path = /obj/item/clothing/under/tachawaiian/blue -/datum/loadout_item/under/miscellaneous/tactical_hawaiian_purple +/datum/loadout_item/uniform/miscellaneous/tactical_hawaiian_purple name = "Tactical Hawaiian Outfit - Purple" item_path = /obj/item/clothing/under/tachawaiian/purple -/datum/loadout_item/under/miscellaneous/tactical_hawaiian_green +/datum/loadout_item/uniform/miscellaneous/tactical_hawaiian_green name = "Tactical Hawaiian Outfit - Green" item_path = /obj/item/clothing/under/tachawaiian/green -/datum/loadout_item/under/miscellaneous/maidcostume +/datum/loadout_item/uniform/miscellaneous/maidcostume name = "Maid Costume" item_path = /obj/item/clothing/under/costume/maid -/datum/loadout_item/under/miscellaneous/maid_costume +/datum/loadout_item/uniform/miscellaneous/maid_costume name = "Colourable Maid Uniform" item_path = /obj/item/clothing/under/maid_costume -/datum/loadout_item/under/miscellaneous/yukata +/datum/loadout_item/uniform/miscellaneous/yukata name = "Recolorable Yukata" item_path = /obj/item/clothing/under/costume/skyrat/yukata -/datum/loadout_item/under/miscellaneous/qipao_black +/datum/loadout_item/uniform/miscellaneous/qipao_black name = "Recolorable Qipao" item_path = /obj/item/clothing/under/costume/skyrat/qipao -/datum/loadout_item/under/miscellaneous/cheongsam +/datum/loadout_item/uniform/miscellaneous/cheongsam name = "Recolorable Cheongsam" item_path = /obj/item/clothing/under/costume/skyrat/cheongsam -/datum/loadout_item/under/miscellaneous/kimono +/datum/loadout_item/uniform/miscellaneous/kimono name = "Fancy Kimono" item_path = /obj/item/clothing/under/costume/skyrat/kimono -/datum/loadout_item/under/miscellaneous/chaps +/datum/loadout_item/uniform/miscellaneous/chaps name = "Black Chaps" item_path = /obj/item/clothing/under/pants/skyrat/chaps -/datum/loadout_item/under/miscellaneous/tracky +/datum/loadout_item/uniform/miscellaneous/tracky name = "Blue Tracksuit" item_path = /obj/item/clothing/under/misc/bluetracksuit -/datum/loadout_item/under/miscellaneous/cybersleek +/datum/loadout_item/uniform/miscellaneous/cybersleek name = "Sleek Modern Coat" item_path = /obj/item/clothing/under/costume/cybersleek -/datum/loadout_item/under/miscellaneous/cybersleek_long +/datum/loadout_item/uniform/miscellaneous/cybersleek_long name = "Long Modern Coat" item_path = /obj/item/clothing/under/costume/cybersleek/long -/datum/loadout_item/under/miscellaneous/dutch +/datum/loadout_item/uniform/miscellaneous/dutch name = "Dutch Suit" item_path = /obj/item/clothing/under/costume/dutch -/datum/loadout_item/under/miscellaneous/cavalry +/datum/loadout_item/uniform/miscellaneous/cavalry name = "Cavalry Uniform" item_path = /obj/item/clothing/under/costume/skyrat/cavalry -/datum/loadout_item/under/miscellaneous/tacticool_turtleneck +/datum/loadout_item/uniform/miscellaneous/tacticool_turtleneck name = "Tacticool Turtleneck" item_path = /obj/item/clothing/under/syndicate/tacticool //This has been rebalanced in modular_skyrat\master_files\code\modules\clothing\under\syndicate.dm -/datum/loadout_item/under/miscellaneous/tactical_skirt +/datum/loadout_item/uniform/miscellaneous/tactical_skirt name = "Tacticool Skirtleneck" item_path = /obj/item/clothing/under/syndicate/tacticool/skirt //This has been rebalanced in modular_skyrat\master_files\code\modules\clothing\under\syndicate.dm -/datum/loadout_item/under/miscellaneous/tactical_pants +/datum/loadout_item/uniform/miscellaneous/tactical_pants name = "Tactical Pants" item_path = /obj/item/clothing/under/pants/tactical -/datum/loadout_item/under/miscellaneous/blastwave_uniform +/datum/loadout_item/uniform/miscellaneous/blastwave_uniform name = "Blastwave Uniform" item_path = /obj/item/clothing/under/blastwave //HALLOWEEN -/datum/loadout_item/under/miscellaneous/pj_blood +/datum/loadout_item/uniform/miscellaneous/pj_blood name = "Blood-red Pajamas" item_path = /obj/item/clothing/under/syndicate/bloodred/sleepytime/sensors -/datum/loadout_item/under/miscellaneous/gladiator +/datum/loadout_item/uniform/miscellaneous/gladiator name = "Gladiator Uniform" item_path = /obj/item/clothing/under/costume/gladiator -/datum/loadout_item/under/miscellaneous/griffon +/datum/loadout_item/uniform/miscellaneous/griffon name = "Griffon Uniform" item_path = /obj/item/clothing/under/costume/griffin -/datum/loadout_item/under/miscellaneous/owl +/datum/loadout_item/uniform/miscellaneous/owl name = "Owl Uniform" item_path = /obj/item/clothing/under/costume/owl -/datum/loadout_item/under/miscellaneous/villain +/datum/loadout_item/uniform/miscellaneous/villain name = "Villain Suit" item_path = /obj/item/clothing/under/costume/villain -/datum/loadout_item/under/miscellaneous/sweater +/datum/loadout_item/uniform/miscellaneous/sweater name = "Cableknit Sweater" //Different than the Suit item ("Sweater")!! item_path = /obj/item/clothing/under/sweater -/datum/loadout_item/under/miscellaneous/keyhole +/datum/loadout_item/uniform/miscellaneous/keyhole name = "Keyhole Sweater" item_path = /obj/item/clothing/under/sweater/keyhole -/datum/loadout_item/under/miscellaneous/blacknwhite +/datum/loadout_item/uniform/miscellaneous/blacknwhite name = "Classic Prisoner Jumpsuit" item_path = /obj/item/clothing/under/rank/prisoner/classic -/datum/loadout_item/under/miscellaneous/redscrubs +/datum/loadout_item/uniform/miscellaneous/redscrubs name = "Red Scrubs" item_path = /obj/item/clothing/under/rank/medical/scrubs/skyrat/red -/datum/loadout_item/under/miscellaneous/bluescrubs +/datum/loadout_item/uniform/miscellaneous/bluescrubs name = "Blue Scrubs" item_path = /obj/item/clothing/under/rank/medical/scrubs/blue -/datum/loadout_item/under/miscellaneous/greenscrubs +/datum/loadout_item/uniform/miscellaneous/greenscrubs name = "Green Scrubs" item_path = /obj/item/clothing/under/rank/medical/scrubs/green -/datum/loadout_item/under/miscellaneous/purplescrubs +/datum/loadout_item/uniform/miscellaneous/purplescrubs name = "Purple Scrubs" item_path = /obj/item/clothing/under/rank/medical/scrubs/purple -/datum/loadout_item/under/miscellaneous/whitescrubs +/datum/loadout_item/uniform/miscellaneous/whitescrubs name = "White Scrubs" item_path = /obj/item/clothing/under/rank/medical/scrubs/skyrat/white -/datum/loadout_item/under/miscellaneous/gear_harness +/datum/loadout_item/uniform/miscellaneous/gear_harness name = "Gear Harness" item_path = /obj/item/clothing/under/misc/skyrat/gear_harness -/datum/loadout_item/under/miscellaneous/taccas +/datum/loadout_item/uniform/miscellaneous/taccas name = "Tacticasual Uniform" item_path = /obj/item/clothing/under/misc/skyrat/taccas -/datum/loadout_item/under/miscellaneous/cargo_casual +/datum/loadout_item/uniform/miscellaneous/cargo_casual name = "Cargo Tech Casualwear" item_path = /obj/item/clothing/under/rank/cargo/tech/skyrat/casualman -/datum/loadout_item/under/miscellaneous/cargo_shorts +/datum/loadout_item/uniform/miscellaneous/cargo_shorts name = "Cargo Tech Shorts" item_path = /obj/item/clothing/under/rank/cargo/tech/alt -/datum/loadout_item/under/miscellaneous/cargo_black +/datum/loadout_item/uniform/miscellaneous/cargo_black name = "Black Cargo Uniform" item_path = /obj/item/clothing/under/rank/cargo/tech/skyrat/evil -/datum/loadout_item/under/miscellaneous/cargo_turtle +/datum/loadout_item/uniform/miscellaneous/cargo_turtle name = "Cargo Turtleneck" item_path = /obj/item/clothing/under/rank/cargo/tech/skyrat/turtleneck -/datum/loadout_item/under/miscellaneous/cargo_skirtle +/datum/loadout_item/uniform/miscellaneous/cargo_skirtle name = "Cargo Skirtleneck" item_path = /obj/item/clothing/under/rank/cargo/tech/skyrat/turtleneck/skirt -/datum/loadout_item/under/miscellaneous/qm_skirtle +/datum/loadout_item/uniform/miscellaneous/qm_skirtle name = "Quartermaster's Skirtleneck" item_path = /obj/item/clothing/under/rank/cargo/qm/skyrat/turtleneck/skirt restricted_roles = list(JOB_QUARTERMASTER) -/datum/loadout_item/under/miscellaneous/qm_gorka +/datum/loadout_item/uniform/miscellaneous/qm_gorka name = "Quartermaster's Gorka Uniform" item_path = /obj/item/clothing/under/rank/cargo/qm/skyrat/gorka restricted_roles = list(JOB_QUARTERMASTER) -/datum/loadout_item/under/miscellaneous/eve +/datum/loadout_item/uniform/miscellaneous/eve name = "Collection of Leaves" item_path = /obj/item/clothing/under/misc/skyrat/gear_harness/eve -/datum/loadout_item/under/miscellaneous/adam +/datum/loadout_item/uniform/miscellaneous/adam name = "Leaf" item_path = /obj/item/clothing/under/misc/skyrat/gear_harness/adam -/datum/loadout_item/under/miscellaneous/ethereal_tunic +/datum/loadout_item/uniform/miscellaneous/ethereal_tunic name = "Ethereal Tunic" item_path = /obj/item/clothing/under/ethereal_tunic -/datum/loadout_item/under/miscellaneous/mech_suit +/datum/loadout_item/uniform/miscellaneous/mech_suit name = "Mech Suit" item_path = /obj/item/clothing/under/costume/mech_suit @@ -670,290 +659,303 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ * FORMAL UNDERSUITS */ -/datum/loadout_item/under/formal +/datum/loadout_item/uniform/formal -/datum/loadout_item/under/formal/amish_suit +/datum/loadout_item/uniform/formal/amish_suit name = "White Buttondown Shirt with Black Slacks" item_path = /obj/item/clothing/under/costume/buttondown/slacks/service -/datum/loadout_item/under/formal/formaldressred +/datum/loadout_item/uniform/formal/formaldressred name = "Formal Red Dress" item_path = /obj/item/clothing/under/dress/skyrat/redformal -/datum/loadout_item/under/formal/countessdress +/datum/loadout_item/uniform/formal/countessdress name = "Countess Dress" item_path = /obj/item/clothing/under/dress/skyrat/countess -/datum/loadout_item/under/formal/assistant +/datum/loadout_item/uniform/formal/assistant name = "Assistant Formal" item_path = /obj/item/clothing/under/misc/assistantformal -/datum/loadout_item/under/formal/beige_suit +/datum/loadout_item/uniform/formal/beige_suit name = "Beige Suit" item_path = /obj/item/clothing/under/suit/beige -/datum/loadout_item/under/formal/black_suit +/datum/loadout_item/uniform/formal/black_suit name = "Black Suit" item_path = /obj/item/clothing/under/suit/black -/datum/loadout_item/under/formal/black_suitskirt +/datum/loadout_item/uniform/formal/black_suitskirt name = "Black Suitskirt" item_path = /obj/item/clothing/under/suit/black/skirt -/datum/loadout_item/under/formal/black_lawyer_suit +/datum/loadout_item/uniform/formal/black_lawyer_suit name = "Black Lawyer Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/black -/datum/loadout_item/under/formal/black_lawyer_skirt +/datum/loadout_item/uniform/formal/black_lawyer_skirt name = "Black Lawyer Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/black/skirt -/datum/loadout_item/under/formal/blue_suit +/datum/loadout_item/uniform/formal/blue_suit name = "Blue Buttondown Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/bluesuit -/datum/loadout_item/under/formal/blue_suitskirt +/datum/loadout_item/uniform/formal/blue_suitskirt name = "Blue Buttondown Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/bluesuit/skirt -/datum/loadout_item/under/formal/blue_lawyer_suit +/datum/loadout_item/uniform/formal/blue_lawyer_suit name = "Blue Lawyer Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/blue -/datum/loadout_item/under/formal/blue_lawyer_skirt +/datum/loadout_item/uniform/formal/blue_lawyer_skirt name = "Blue Lawyer Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/blue/skirt -/datum/loadout_item/under/formal/burgundy_suit +/datum/loadout_item/uniform/formal/burgundy_suit name = "Burgundy Suit" item_path = /obj/item/clothing/under/suit/burgundy -/datum/loadout_item/under/formal/charcoal_suit +/datum/loadout_item/uniform/formal/charcoal_suit name = "Charcoal Suit" item_path = /obj/item/clothing/under/suit/charcoal -/datum/loadout_item/under/formal/checkered_suit +/datum/loadout_item/uniform/formal/checkered_suit name = "Checkered Suit" item_path = /obj/item/clothing/under/suit/checkered -/datum/loadout_item/under/formal/executive_suit +/datum/loadout_item/uniform/formal/executive_suit name = "Executive Suit" item_path = /obj/item/clothing/under/suit/black_really -/datum/loadout_item/under/formal/executive_skirt +/datum/loadout_item/uniform/formal/executive_skirt name = "Executive Suitskirt" item_path = /obj/item/clothing/under/suit/black_really/skirt -/datum/loadout_item/under/formal/executive_suit_alt +/datum/loadout_item/uniform/formal/executive_suit_alt name = "Wide-collared Executive Suit" item_path = /obj/item/clothing/under/suit/skyrat/black_really_collared -/datum/loadout_item/under/formal/executive_skirt_alt +/datum/loadout_item/uniform/formal/executive_skirt_alt name = "Wide-collared Executive Suitskirt" item_path = /obj/item/clothing/under/suit/skyrat/black_really_collared/skirt -/datum/loadout_item/under/formal/navy_suit +/datum/loadout_item/uniform/formal/navy_suit name = "Navy Suit" item_path = /obj/item/clothing/under/suit/navy -/datum/loadout_item/under/formal/maid_uniform +/datum/loadout_item/uniform/formal/maid_uniform name = "Maid Uniform" item_path = /obj/item/clothing/under/rank/civilian/janitor/maid -/datum/loadout_item/under/formal/purple_suit +/datum/loadout_item/uniform/formal/purple_suit name = "Purple Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/purpsuit -/datum/loadout_item/under/formal/purple_suitskirt +/datum/loadout_item/uniform/formal/purple_suitskirt name = "Purple Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/purpsuit/skirt -/datum/loadout_item/under/formal/red_suit +/datum/loadout_item/uniform/formal/red_suit name = "Red Suit" item_path = /obj/item/clothing/under/suit/red -/datum/loadout_item/under/formal/helltaker +/datum/loadout_item/uniform/formal/helltaker name = "Red Shirt with White Trousers" item_path = /obj/item/clothing/under/suit/skyrat/helltaker -/datum/loadout_item/under/formal/helltaker/skirt +/datum/loadout_item/uniform/formal/helltaker/skirt name = "Red Shirt with White Skirt" item_path = /obj/item/clothing/under/suit/skyrat/helltaker/skirt -/datum/loadout_item/under/formal/red_lawyer_skirt +/datum/loadout_item/uniform/formal/red_lawyer_skirt name = "Red Lawyer Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/red -/datum/loadout_item/under/formal/red_lawyer_skirt +/datum/loadout_item/uniform/formal/red_lawyer_skirt name = "Red Lawyer Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/red/skirt -/datum/loadout_item/under/formal/red_gown +/datum/loadout_item/uniform/formal/red_gown name = "Red Evening Gown" item_path = /obj/item/clothing/under/dress/eveninggown -/datum/loadout_item/under/formal/sailor +/datum/loadout_item/uniform/formal/sailor name = "Sailor Suit" item_path = /obj/item/clothing/under/costume/sailor -/datum/loadout_item/under/formal/sailor_skirt +/datum/loadout_item/uniform/formal/sailor_skirt name = "Sailor Dress" item_path = /obj/item/clothing/under/dress/sailor -/datum/loadout_item/under/formal/sensible_suit +/datum/loadout_item/uniform/formal/sensible_suit name = "Sensible Suit" item_path = /obj/item/clothing/under/rank/civilian/curator -/datum/loadout_item/under/formal/sensible_skirt +/datum/loadout_item/uniform/formal/sensible_skirt name = "Sensible Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/curator/skirt -/datum/loadout_item/under/formal/tuxedo +/datum/loadout_item/uniform/formal/tuxedo name = "Tuxedo Suit" item_path = /obj/item/clothing/under/suit/tuxedo -/datum/loadout_item/under/formal/waiter +/datum/loadout_item/uniform/formal/waiter name = "Waiter's Suit" item_path = /obj/item/clothing/under/suit/waiter -/datum/loadout_item/under/formal/white_suit +/datum/loadout_item/uniform/formal/white_suit name = "White Suit" item_path = /obj/item/clothing/under/suit/white -/datum/loadout_item/under/formal/fancy_suit +/datum/loadout_item/uniform/formal/fancy_suit name = "Fancy Suit" item_path = /obj/item/clothing/under/suit/fancy -/datum/loadout_item/under/formal/recolorable_suit +/datum/loadout_item/uniform/formal/recolorable_suit name = "Recolorable Formal Suit" item_path = /obj/item/clothing/under/suit/skyrat/recolorable -/datum/loadout_item/under/formal/recolorable_suitskirt +/datum/loadout_item/uniform/formal/recolorable_suitskirt name = "Recolorable Formal Suitskirt" item_path = /obj/item/clothing/under/suit/skyrat/recolorable/skirt -/datum/loadout_item/under/formal/trek_command +/datum/loadout_item/uniform/formal/trek_command name = "Trekkie Command Uniform" item_path = /obj/item/clothing/under/trek/command -/datum/loadout_item/under/formal/trek_engsec +/datum/loadout_item/uniform/formal/trek_engsec name = "Trekkie Engsec Uniform" item_path = /obj/item/clothing/under/trek/engsec -/datum/loadout_item/under/formal/trek_medsci +/datum/loadout_item/uniform/formal/trek_medsci name = "Trekkie Medsci Uniform" item_path = /obj/item/clothing/under/trek/medsci -/datum/loadout_item/under/formal/trek_next_command +/datum/loadout_item/uniform/formal/trek_next_command name = "Trekkie TNG Command Uniform" item_path = /obj/item/clothing/under/trek/command/next -/datum/loadout_item/under/formal/trek_next_engsec +/datum/loadout_item/uniform/formal/trek_next_engsec name = "Trekkie TNG Engsec Uniform" item_path = /obj/item/clothing/under/trek/engsec/next -/datum/loadout_item/under/formal/trek_next_medsci +/datum/loadout_item/uniform/formal/trek_next_medsci name = "Trekkie TNG Medsci Uniform" item_path = /obj/item/clothing/under/trek/medsci/next -/datum/loadout_item/under/formal/trek_ent_command +/datum/loadout_item/uniform/formal/trek_ent_command name = "Trekkie ENT Command Uniform" item_path = /obj/item/clothing/under/trek/command/ent -/datum/loadout_item/under/formal/trek_ent_engsec +/datum/loadout_item/uniform/formal/trek_ent_engsec name = "Trekkie ENT Engsec Uniform" item_path = /obj/item/clothing/under/trek/engsec/ent -/datum/loadout_item/under/formal/trek_ent_medsci +/datum/loadout_item/uniform/formal/trek_ent_medsci name = "Trekkie ENT Medsci Uniform" item_path = /obj/item/clothing/under/trek/medsci/ent -/datum/loadout_item/under/formal/the_q +/datum/loadout_item/uniform/formal/the_q name = "French Marshall's Uniform" item_path = /obj/item/clothing/under/trek/q //FAMILIES GEAR -/datum/loadout_item/under/formal/osi +/datum/loadout_item/uniform/formal/osi name = "OSI Uniform" item_path = /obj/item/clothing/under/costume/osi -/datum/loadout_item/under/formal/tmc +/datum/loadout_item/uniform/formal/tmc name = "TMC Uniform" item_path = /obj/item/clothing/under/costume/tmc -/datum/loadout_item/under/formal/inferno +/datum/loadout_item/uniform/formal/inferno name = "Inferno Suit" item_path = /obj/item/clothing/under/suit/skyrat/inferno -/datum/loadout_item/under/formal/inferno_skirt +/datum/loadout_item/uniform/formal/inferno_skirt name = "Inferno Skirt" item_path = /obj/item/clothing/under/suit/skyrat/inferno/skirt -/datum/loadout_item/under/formal/designer_inferno +/datum/loadout_item/uniform/formal/designer_inferno name = "Designer Inferno Suit" item_path = /obj/item/clothing/under/suit/skyrat/inferno/beeze -/datum/loadout_item/under/formal/pencil +/datum/loadout_item/uniform/formal/pencil name = "Black Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil -/datum/loadout_item/under/formal/pencil/black_really +/datum/loadout_item/uniform/formal/pencil/black_really name = "Executive Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/black_really -/datum/loadout_item/under/formal/pencil/charcoal +/datum/loadout_item/uniform/formal/pencil/charcoal name = "Charcoal Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/charcoal -/datum/loadout_item/under/formal/pencil/navy +/datum/loadout_item/uniform/formal/pencil/navy name = "Navy Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/navy -/datum/loadout_item/under/formal/pencil/burgandy +/datum/loadout_item/uniform/formal/pencil/burgandy name = "Burgandy Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/burgandy -/datum/loadout_item/under/formal/pencil/checkered +/datum/loadout_item/uniform/formal/pencil/checkered name = "Checkered Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/checkered -/datum/loadout_item/under/formal/pencil/tan +/datum/loadout_item/uniform/formal/pencil/tan name = "Tan Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/tan -/datum/loadout_item/under/formal/pencil/green +/datum/loadout_item/uniform/formal/pencil/green name = "Green Pencilskirt" item_path = /obj/item/clothing/under/suit/skyrat/pencil/green -/datum/loadout_item/under/formal/azulea_oldblood +/datum/loadout_item/uniform/formal/azulea_oldblood name = " Oldblood's Royal regalia" item_path = /obj/item/clothing/under/rank/azulean/old_blood restricted_roles = list(JOB_CAPTAIN, JOB_NT_REP) restricted_species = list(SPECIES_AKULA) -/datum/loadout_item/under/formal/azulea_oldblood/skirt +/datum/loadout_item/uniform/formal/azulea_oldblood/skirt name = " Oldblood's Royal regalia (Skirt)" item_path = /obj/item/clothing/under/rank/azulean/old_blood/skirt restricted_roles = list(JOB_CAPTAIN, JOB_NT_REP) restricted_species = list(SPECIES_AKULA) -/datum/loadout_item/under/formal/azulea_upstart +/datum/loadout_item/uniform/formal/azulea_upstart name = "Upstart's Noble Getup" item_path = /obj/item/clothing/under/rank/azulean/upstart restricted_roles = list(JOB_CAPTAIN, JOB_NT_REP) restricted_species = list(SPECIES_AKULA) -/datum/loadout_item/under/formal/azulea_upstart/skirt +/datum/loadout_item/uniform/formal/azulea_upstart/skirt name = "Upstart's Noble Getup (Skirt)" item_path = /obj/item/clothing/under/rank/azulean/upstart/skirt restricted_roles = list(JOB_CAPTAIN, JOB_NT_REP) restricted_species = list(SPECIES_AKULA) -/// DONATOR -/datum/loadout_item/under/donator - donator_only = TRUE - -/datum/loadout_item/under/donator/captain_black +// DONATOR ONLY +/datum/loadout_item/uniform/captain_black name = "Captains Black Uniform" item_path = /obj/item/clothing/under/rank/captain/skyrat/black restricted_roles = list(JOB_CAPTAIN) + donator_only = TRUE + +/datum/loadout_item/under/jumpsuit/donator + donator_only = TRUE + +/datum/loadout_item/under/jumpsuit/donator/enclavesergeant + name = "Enclave - Sergeant" + item_path = /obj/item/clothing/under/syndicate/skyrat/enclave + +/datum/loadout_item/under/jumpsuit/donator/enclaveofficer + name = "Enclave - Officer" + item_path = /obj/item/clothing/under/syndicate/skyrat/enclave/officer + +/datum/loadout_item/under/jumpsuit/donator/blondie + name = "Blonde Cowboy Uniform" + item_path = /obj/item/clothing/under/rank/security/detective/cowboy/armorless diff --git a/modular_skyrat/modules/better_vox/code/vox_species.dm b/modular_skyrat/modules/better_vox/code/vox_species.dm index 04f8e0f65c8fa..76a7e13643ef4 100644 --- a/modular_skyrat/modules/better_vox/code/vox_species.dm +++ b/modular_skyrat/modules/better_vox/code/vox_species.dm @@ -36,16 +36,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/vox_primalis, ) custom_worn_icons = list( - LOADOUT_ITEM_HEAD = VOX_PRIMALIS_HEAD_ICON, - LOADOUT_ITEM_MASK = VOX_PRIMALIS_MASK_ICON, + OFFSET_HEAD = VOX_PRIMALIS_HEAD_ICON, + OFFSET_MASK = VOX_PRIMALIS_MASK_ICON, LOADOUT_ITEM_SUIT = VOX_PRIMALIS_SUIT_ICON, LOADOUT_ITEM_UNIFORM = VOX_PRIMALIS_UNIFORM_ICON, LOADOUT_ITEM_GLOVES = VOX_PRIMALIS_GLOVES_ICON, - LOADOUT_ITEM_SHOES = VOX_PRIMALIS_FEET_ICON, + OFFSET_SHOES = VOX_PRIMALIS_FEET_ICON, LOADOUT_ITEM_GLASSES = VOX_PRIMALIS_EYES_ICON, - LOADOUT_ITEM_BELT = VOX_PRIMALIS_BELT_ICON, + OFFSET_BELT = VOX_PRIMALIS_BELT_ICON, LOADOUT_ITEM_MISC = VOX_PRIMALIS_BACK_ICON, - LOADOUT_ITEM_EARS = VOX_PRIMALIS_EARS_ICON, + OFFSET_EARS = VOX_PRIMALIS_EARS_ICON, ) /datum/species/vox_primalis/get_default_mutant_bodyparts() diff --git a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm index 564ca6941c33f..70f6d6a1bad82 100644 --- a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm +++ b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm @@ -109,37 +109,6 @@ // Chemical reactions aren't handled here because they're loaded in the reagents SS // See Initialize() on SSReagents - // Loadouts - for(var/loadout_path in GLOB.all_loadout_datums) - var/datum/loadout_item/loadout_datum = GLOB.all_loadout_datums[loadout_path] - if(!loadout_datum.erp_item) - continue - GLOB.all_loadout_datums -= loadout_path - // Ensure this FULLY works later - - var/list/loadout_lists = list( - GLOB.loadout_belts, - GLOB.loadout_ears, - GLOB.loadout_glasses, - GLOB.loadout_gloves, - GLOB.loadout_helmets, - GLOB.loadout_masks, - GLOB.loadout_necks, - GLOB.loadout_shoes, - GLOB.loadout_exosuits, - GLOB.loadout_jumpsuits, - GLOB.loadout_undersuits, - GLOB.loadout_miscunders, - GLOB.loadout_accessory, - GLOB.loadout_inhand_items, - GLOB.loadout_toys, - GLOB.loadout_pocket_items, - ) - for(var/loadout_list in loadout_lists) - for(var/datum/loadout_item/loadout_typepath in loadout_list) - if(!initial(loadout_typepath.erp_item)) - continue - loadout_list -= loadout_typepath // Underwear for(var/sprite_name in SSaccessories.underwear_list) diff --git a/modular_skyrat/modules/customization/modules/clothing/under/accessories.dm b/modular_skyrat/modules/customization/modules/clothing/under/accessories.dm index c6e25fb1e2405..79382f4b01a99 100644 --- a/modular_skyrat/modules/customization/modules/clothing/under/accessories.dm +++ b/modular_skyrat/modules/customization/modules/clothing/under/accessories.dm @@ -160,22 +160,3 @@ new /obj/item/clothing/accessory/badge/holo/cord(src) return -// Pride Pin Over-ride -/obj/item/clothing/accessory/pride - icon = 'modular_skyrat/master_files/icons/obj/clothing/accessories.dmi' - worn_icon = 'modular_skyrat/master_files/icons/mob/clothing/accessories.dmi' - -GLOBAL_LIST_INIT(pride_pin_reskins, list( - "Rainbow Pride" = "pride", - "Bisexual Pride" = "pride_bi", - "Pansexual Pride" = "pride_pan", - "Asexual Pride" = "pride_ace", - "Non-binary Pride" = "pride_enby", - "Transgender Pride" = "pride_trans", - "Intersex Pride" = "pride_intersex", - "Lesbian Pride" = "pride_lesbian", - "Man-Loving-Man / Gay Pride" = "pride_mlm", - "Genderfluid Pride" = "pride_genderfluid", - "Genderqueer Pride" = "pride_genderqueer", - "Aromantic Pride" = "pride_aromantic", -)) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/custom_bodytype.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/custom_bodytype.dm index d5b07bc60ede9..d82eefa85d8e6 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/custom_bodytype.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/custom_bodytype.dm @@ -1,7 +1,7 @@ /** * Modularly returns one of worn_icon_vox, worn_icon_teshari, etc. * Arguments: - * * item_slot: The slot we're updating. One of LOADOUT_ITEM_HEAD, etc. + * * item_slot: The slot we're updating. One of OFFSET_HEAD, etc. * * item is the item we're checking. */ /datum/species/proc/get_custom_worn_icon(item_slot, obj/item/item) @@ -10,7 +10,7 @@ /** * Modularly set one of worn_icon_vox, worn_icon_teshari, etc. * Arguments: - * * item_slot: The slot we're updating. One of LOADOUT_ITEM_HEAD, etc. + * * item_slot: The slot we're updating. One of OFFSET_HEAD, etc. * * item is the item we're updating. * * icon is the icon we're setting to the var. */ @@ -21,7 +21,7 @@ * Modularly get the species' fallback greyscale config. * Only used if you use generate_custom_worn_icon_fallback() * Arguments: - * * item_slot: The slot we're updating. One of LOADOUT_ITEM_HEAD, etc. + * * item_slot: The slot we're updating. One of OFFSET_HEAD, etc. * * item: The item being rendered. */ /datum/species/proc/get_custom_worn_config_fallback(item_slot, obj/item/item) @@ -55,7 +55,7 @@ * Allow for custom clothing icon generation. Only called if the species is BODYSHAPE_CUSTOM * If null is returned, use default human icon. * Arguments: - * * item_slot: The slot we're updating. One of LOADOUT_ITEM_HEAD, etc. + * * item_slot: The slot we're updating. One of OFFSET_HEAD, etc. * * item: The item being rendered. * * human_owner: The human wearing the item. */ diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm index ea6ac0ac47973..2937cfccdc87d 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm @@ -33,16 +33,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/vox, ) custom_worn_icons = list( - LOADOUT_ITEM_HEAD = VOX_HEAD_ICON, - LOADOUT_ITEM_MASK = VOX_MASK_ICON, + OFFSET_HEAD = VOX_HEAD_ICON, + OFFSET_MASK = VOX_MASK_ICON, LOADOUT_ITEM_SUIT = VOX_SUIT_ICON, LOADOUT_ITEM_UNIFORM = VOX_UNIFORM_ICON, LOADOUT_ITEM_HANDS = VOX_HANDS_ICON, - LOADOUT_ITEM_SHOES = VOX_FEET_ICON, + OFFSET_SHOES = VOX_FEET_ICON, LOADOUT_ITEM_GLASSES = VOX_EYES_ICON, - LOADOUT_ITEM_BELT = VOX_BELT_ICON, + OFFSET_BELT = VOX_BELT_ICON, LOADOUT_ITEM_MISC = VOX_BACK_ICON, - LOADOUT_ITEM_EARS = VOX_EARS_ICON + OFFSET_EARS = VOX_EARS_ICON ) meat = /obj/item/food/meat/slab/chicken/human //item file in teshari module @@ -79,7 +79,7 @@ /datum/species/vox/get_custom_worn_icon(item_slot, obj/item/item) // snowflakey but vox legs weird. - if(item_slot == LOADOUT_ITEM_SHOES) + if(item_slot == OFFSET_SHOES) var/obj/item/bodypart/leg = bodypart_overrides[BODY_ZONE_L_LEG] || bodypart_overrides[BODY_ZONE_R_LEG] if(initial(leg?.limb_id) != "digitigrade") // normal legs, use normal human shoes diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/worn_overlays.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/worn_overlays.dm index a35a261439a34..a5802e962cf57 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/worn_overlays.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/worn_overlays.dm @@ -7,9 +7,9 @@ var/mob/living/carbon/human/human_wearer = loc - // Handle custom_worn_icons[LOADOUT_ITEM_ACCESSORY] - if(LOADOUT_ITEM_ACCESSORY in human_wearer.dna.species.custom_worn_icons) - var/icon/custom_accessory_icon = human_wearer.dna.species.custom_worn_icons[LOADOUT_ITEM_ACCESSORY] + // Handle custom_worn_icons[OFFSET_ACCESSORY] + if(OFFSET_ACCESSORY in human_wearer.dna.species.custom_worn_icons) + var/icon/custom_accessory_icon = human_wearer.dna.species.custom_worn_icons[OFFSET_ACCESSORY] var/list/custom_accessory_states = icon_states(custom_accessory_icon) if(accessory_overlay.icon_state in custom_accessory_states) diff --git a/modular_skyrat/modules/events/code/event_spawner.dm b/modular_skyrat/modules/events/code/event_spawner.dm index bc37576345529..16d9f209bafa8 100644 --- a/modular_skyrat/modules/events/code/event_spawner.dm +++ b/modular_skyrat/modules/events/code/event_spawner.dm @@ -126,10 +126,6 @@ else equipped.forceMove(get_turf(H)) - if(gets_loadout) - for(var/datum/loadout_item/item as anything in loadout_list_to_datums(H?.client?.prefs?.loadout_list)) - item.post_equip_item(H.client?.prefs, H) - //Override access of the ID card here var/obj/item/card/id/ID if(length(access_override)) diff --git a/modular_skyrat/modules/loadouts/loadout_items/_loadout_datum.dm b/modular_skyrat/modules/loadouts/loadout_items/_loadout_datum.dm deleted file mode 100644 index 5a4d3bc6a5411..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_items/_loadout_datum.dm +++ /dev/null @@ -1,135 +0,0 @@ -// -- The loadout item datum and related procs. -- - -/// Global list of ALL loadout datums instantiated. -GLOBAL_LIST_EMPTY(all_loadout_datums) - -/* - * Generate a list of singleton loadout_item datums from all subtypes of [type_to_generate] - * - * returns a list of singleton datums. - */ -/proc/generate_loadout_items(type_to_generate) - RETURN_TYPE(/list) - - . = list() - if(!ispath(type_to_generate)) - CRASH("generate_loadout_items(): called with an invalid or null path as an argument!") - - for(var/datum/loadout_item/found_type as anything in subtypesof(type_to_generate)) - /// Any item without a name is "abstract" - if(isnull(initial(found_type.name))) - continue - - if(!ispath(initial(found_type.item_path))) - stack_trace("generate_loadout_items(): Attempted to instantiate a loadout item ([initial(found_type.name)]) with an invalid or null typepath! (got path: [initial(found_type.item_path)])") - continue - - var/datum/loadout_item/spawned_type = new found_type() - // Let's sanitize in case somebody inserted the player's byond name instead of ckey in canonical form - if(spawned_type.ckeywhitelist) - for (var/i = 1, i <= length(spawned_type.ckeywhitelist), i++) - spawned_type.ckeywhitelist[i] = ckey(spawned_type.ckeywhitelist[i]) - GLOB.all_loadout_datums[spawned_type.item_path] = spawned_type - . |= spawned_type - -/// Loadout item datum. -/// Holds all the information about each loadout items. -/// A list of singleton loadout items are generated on initialize. -/datum/loadout_item - /// Displayed name of the loadout item. - var/name - /// Whether this item can be renamed and described. - var/can_be_named = TRUE - /// The category of the loadout item. - var/category - /// The actual item path of the loadout item. - var/atom/item_path - /// List of additional text for the tooltip displayed on this item. - var/list/additional_tooltip_contents - /// If set, it's a list containing ckeys which only can get the item - var/list/ckeywhitelist - /// If set, is a list of job names of which can get the loadout item - var/list/restricted_roles - /// If set, is a list of job names of which can't get the loadout item - var/list/blacklisted_roles - /// If set, is a list of species which can get the loadout item - var/list/restricted_species - /// Whether the item is restricted to supporters - var/donator_only - /// Whether the item requires a specific season in order to be available - var/required_season = null - /// If the item won't appear when the ERP config is disabled - var/erp_item = FALSE - -/* - * Place our [var/item_path] into [outfit]. - * - * By default, just adds the item into the outfit's backpack contents, if non-visual. - * - * equipper - If we're equipping our outfit onto a mob at the time, this is the mob it is equipped on. Can be null. - * outfit - The outfit we're equipping our items into. - * visual - If TRUE, then our outfit is only for visual use (for example, a preview). - */ -/datum/loadout_item/proc/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(!visuals_only) - LAZYADD(outfit.backpack_contents, item_path) - -/* - * To be called before insert_path_into_outfit() - * - * Checks if an important_for_life item exists and puts the loadout item into the backpack if they would take up the same slot as it. - * - * equipper - If we're equipping our outfit onto a mob at the time, this is the mob it is equipped on. Can be null. - * outfit - The outfit we're equipping our items into. - * outfit_important_for_life - The outfit whose slots we want to make sure we don't equip an item into. - * visual - If TRUE, then our outfit is only for visual use (for example, a preview). - * - * Returns TRUE if there is an important_for_life item in the slot that the loadout item would normally occupy, FALSE otherwise - */ -/datum/loadout_item/proc/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(!visuals_only) - LAZYADD(outfit.backpack_contents, item_path) - -/* - * Called When the item is equipped on [equipper]. - */ -/datum/loadout_item/proc/on_equip_item(datum/preferences/preference_source, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(!preference_source) - return - - var/list/our_loadout = preference_source.loadout_list - var/atom/loadout_atom = item_path - var/can_be_greyscale = !!(initial(loadout_atom.greyscale_config) && initial(loadout_atom.greyscale_colors) && (initial(loadout_atom.flags_1) & IS_PLAYER_COLORABLE_1)) - if(can_be_greyscale && (INFO_GREYSCALE in our_loadout[item_path])) - if(ispath(item_path, /obj/item/clothing)) - // When an outfit is equipped in preview, get_equipped_items() does not work, so we have to use get_all_contents() - var/obj/item/clothing/equipped_item = locate(item_path) in (visuals_only ? equipper.get_all_contents() : equipper.get_all_gear()) // needs held items for briefcasers - if(equipped_item) - equipped_item.set_greyscale(our_loadout[item_path][INFO_GREYSCALE]) - else - stack_trace("[type] on_equip_item(): Could not locate clothing item (path: [item_path]) in [equipper]'s [visuals_only ? "visible":"all"] contents to set greyscaling!") - - else if(!visuals_only) - var/obj/item/other_item = locate(item_path) in equipper.get_all_gear() - if(other_item) - other_item.set_greyscale(our_loadout[item_path][INFO_GREYSCALE]) - else - stack_trace("[type] on_equip_item(): Could not locate backpack item (path: [item_path]) in [equipper]'s contents to set greyscaling!") - - if(can_be_named && !visuals_only) - var/obj/item/equipped_item = locate(item_path) in equipper.get_all_gear() - if(equipped_item) - if(INFO_NAMED in our_loadout[item_path]) - equipped_item.name = our_loadout[item_path][INFO_NAMED] - equipped_item.on_loadout_custom_named() - if(INFO_DESCRIBED in our_loadout[item_path]) - equipped_item.desc = our_loadout[item_path][INFO_DESCRIBED] - equipped_item.on_loadout_custom_described() - else - stack_trace("[type] on_equip_item(): Could not locate item (path: [item_path]) in [equipper]'s contents to set name/desc!") - -/* - * Called after the item is equipped on [equipper], at the end of character setup. - */ -/datum/loadout_item/proc/post_equip_item(datum/preferences/preference_source, mob/living/carbon/human/equipper) - return FALSE diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_accessory.dm b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_accessory.dm deleted file mode 100644 index addd37faf581a..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_accessory.dm +++ /dev/null @@ -1,104 +0,0 @@ -/* -* LOADOUT ITEM DATUMS FOR THE ACCESSORY SLOT -*/ - -/// Accessory Items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_accessory, generate_loadout_items(/datum/loadout_item/accessory)) - -/datum/loadout_item/accessory - category = LOADOUT_ITEM_ACCESSORY - -/datum/loadout_item/accessory/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, visuals_only = FALSE) - if(initial(outfit_important_for_life.accessory)) - .. () - return TRUE - -/datum/loadout_item/accessory/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.accessory) - LAZYADD(outfit.backpack_contents, outfit.accessory) - outfit.accessory = item_path - else - outfit.accessory = item_path - -/datum/loadout_item/accessory/maid_apron - name = "Maid Apron" - item_path = /obj/item/clothing/accessory/maidapron - -/datum/loadout_item/accessory/waistcoat - name = "Waistcoat" - item_path = /obj/item/clothing/accessory/waistcoat - -/datum/loadout_item/accessory/pocket_protector - name = "Pocket Protector (Empty)" - item_path = /obj/item/clothing/accessory/pocketprotector - -/datum/loadout_item/accessory/full_pocket_protector - name = "Pocket Protector (Filled)" - item_path = /obj/item/clothing/accessory/pocketprotector/full - additional_tooltip_contents = list("CONTAINS PENS - This item contains multiple pens on spawn.") - -/datum/loadout_item/accessory/ribbon - name = "Ribbon" - item_path = /obj/item/clothing/accessory/medal/ribbon - -/datum/loadout_item/accessory/pride - name = "Pride Pin" - item_path = /obj/item/clothing/accessory/pride - -/* -* ARMBANDS -*/ - -/datum/loadout_item/accessory/armband_medblue - name = "Blue-White Armband" - item_path = /obj/item/clothing/accessory/armband/medblue/nonsec - -/datum/loadout_item/accessory/armband_med - name = "White Armband" - item_path = /obj/item/clothing/accessory/armband/med/nonsec - -/datum/loadout_item/accessory/armband_cargo - name = "Brown Armband" - item_path = /obj/item/clothing/accessory/armband/cargo/nonsec - -/datum/loadout_item/accessory/armband_engineering - name = "Orange Armband" - item_path = /obj/item/clothing/accessory/armband/engine/nonsec - -/datum/loadout_item/accessory/armband_security_nonsec - name = "Blue Armband" - item_path = /obj/item/clothing/accessory/armband/deputy/lopland/nonsec - -/datum/loadout_item/accessory/armband_security - name = "Security Armband" - item_path = /obj/item/clothing/accessory/armband/deputy/lopland - restricted_roles = list(JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_DETECTIVE, JOB_CORRECTIONS_OFFICER) - -/datum/loadout_item/accessory/armband_security_deputy - name = "Security Deputy Armband" - item_path = /obj/item/clothing/accessory/armband/deputy - restricted_roles = list(JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_DETECTIVE, JOB_CORRECTIONS_OFFICER) - -/datum/loadout_item/accessory/armband_science - name = "Purple Armband" - item_path = /obj/item/clothing/accessory/armband/science/nonsec - -/* -* ARMOURLESS -*/ - -/datum/loadout_item/accessory/bone_charm - name = "Heirloom Bone Talisman" - item_path = /obj/item/clothing/accessory/talisman/armourless - additional_tooltip_contents = list(TOOLTIP_NO_ARMOR) - -/datum/loadout_item/accessory/bone_codpiece - name = "Heirloom Skull Codpiece" - item_path = /obj/item/clothing/accessory/skullcodpiece/armourless - additional_tooltip_contents = list(TOOLTIP_NO_ARMOR) - -/datum/loadout_item/accessory/sinew_kilt - name = "Heirloom Sinew Skirt" - item_path = /obj/item/clothing/accessory/skilt/armourless - additional_tooltip_contents = list(TOOLTIP_NO_ARMOR) diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_ears.dm b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_ears.dm deleted file mode 100644 index 81c1b149480d5..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_ears.dm +++ /dev/null @@ -1,30 +0,0 @@ -/* -* LOADOUT ITEM DATUMS FOR THE EAR SLOT -*/ - -/// Ear Slot Items (Moves overrided items to backpack) -GLOBAL_LIST_INIT(loadout_ears, generate_loadout_items(/datum/loadout_item/ears)) - -/datum/loadout_item/ears - category = LOADOUT_ITEM_EARS - -/datum/loadout_item/ears/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) - if(initial(outfit_important_for_life.ears)) - .. () - return TRUE - -/datum/loadout_item/ears/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE, override_items = LOADOUT_OVERRIDE_BACKPACK) - if(override_items == LOADOUT_OVERRIDE_BACKPACK && !visuals_only) - if(outfit.ears) - LAZYADD(outfit.backpack_contents, outfit.ears) - outfit.ears = item_path - else - outfit.ears = item_path - -/datum/loadout_item/ears/headphones - name = "Headphones" - item_path = /obj/item/instrument/piano_synth/headphones - -/datum/loadout_item/ears/earmuffs - name = "Earmuffs" - item_path = /obj/item/clothing/ears/earmuffs diff --git a/modular_skyrat/modules/loadouts/loadout_items/under/donator.dm b/modular_skyrat/modules/loadouts/loadout_items/under/donator.dm deleted file mode 100644 index da5fb6bbd228a..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_items/under/donator.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/loadout_item/under/jumpsuit/donator - donator_only = TRUE - -/datum/loadout_item/under/jumpsuit/donator/enclavesergeant - name = "Enclave - Sergeant" - item_path = /obj/item/clothing/under/syndicate/skyrat/enclave - -/datum/loadout_item/under/jumpsuit/donator/enclaveofficer - name = "Enclave - Officer" - item_path = /obj/item/clothing/under/syndicate/skyrat/enclave/officer - -/datum/loadout_item/under/jumpsuit/donator/blondie - name = "Blonde Cowboy Uniform" - item_path = /obj/item/clothing/under/rank/security/detective/cowboy/armorless diff --git a/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm b/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm deleted file mode 100644 index 3d5c144a69a00..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm +++ /dev/null @@ -1,342 +0,0 @@ -/// -- The loadout manager and UI -- -/// Tracking when a client has an open loadout manager, to prevent funky stuff. -/client - /// A weakref to loadout_manager datum. - var/datum/weakref/open_loadout_ui - -/// Datum holder for the loadout manager UI. -/datum/loadout_manager - /// The client of the person using the UI - var/client/owner - /// The current selected loadout list. - var/list/loadout_on_open - /// Our currently open greyscaling menu. - var/datum/greyscale_modify_menu/menu - -/datum/loadout_manager/Destroy(force, ...) - if(menu) - SStgui.close_uis(menu) - menu = null - owner?.open_loadout_ui = null - owner = null - QDEL_NULL(menu) - return ..() - -/datum/loadout_manager/New(user) - owner = CLIENT_FROM_VAR(user) - loadout_on_open = LAZYLISTDUPLICATE(owner.prefs.loadout_list) - owner.open_loadout_ui = WEAKREF(src) - -/datum/loadout_manager/ui_close(mob/user) - owner?.prefs.save_character() - if(menu) - SStgui.close_uis(menu) - menu = null - owner?.open_loadout_ui = null - qdel(src) - -/datum/loadout_manager/ui_state(mob/user) - return GLOB.always_state - -/datum/loadout_manager/ui_interact(mob/user, datum/tgui/ui) - - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "LoadoutManager") - ui.set_autoupdate(FALSE) - ui.open() - -/datum/loadout_manager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - var/datum/loadout_item/interacted_item - if(params["path"]) - interacted_item = GLOB.all_loadout_datums[text2path(params["path"])] - if(!interacted_item) - stack_trace("Failed to locate desired loadout item (path: [params["path"]]) in the global list of loadout datums!") - return - - switch(action) - // Closes the UI, reverting our loadout to before edits if params["revert"] is set - if("close_ui") - if(params["revert"]) - owner.prefs.loadout_list = loadout_on_open - SStgui.close_uis(src) - return - - if("select_item") - //Here we will perform basic checks to ensure there are no exploits happening - if(interacted_item.donator_only && !GLOB.donator_list[owner.ckey] && !is_admin(owner)) - message_admins("LOADOUT SYSTEM: Possible exploit detected, non-donator [owner.ckey] tried loading [interacted_item.item_path], but this is donator only.") - return - - if(interacted_item.ckeywhitelist && !(owner.ckey in interacted_item.ckeywhitelist)) - message_admins("LOADOUT SYSTEM: Possible exploit detected, non-donator [owner.ckey] tried loading [interacted_item.item_path], but this is ckey locked.") - return - if(params["deselect"]) - deselect_item(interacted_item) - owner?.prefs?.character_preview_view.update_body() - else - select_item(interacted_item) - owner?.prefs?.character_preview_view.update_body() - - if("select_color") - select_item_color(interacted_item) - - if("set_name") - set_item_name(interacted_item) - - if("display_restrictions") - display_job_restrictions(interacted_item) - display_job_blacklists(interacted_item) - display_species_restrictions(interacted_item) - - // Clears the loadout list entirely. - if("clear_all_items") - LAZYNULL(owner.prefs.loadout_list) - owner?.prefs?.character_preview_view.update_body() - - if("donator_explain") - if(GLOB.donator_list[owner.ckey]) - to_chat(owner, examine_block("Thank you for donating, this item is for you <3!")) - else - to_chat(owner, examine_block(span_boldnotice("This item is restricted to donators only, for more information, please check the discord(#server-info) for more information!"))) - - if("ckey_explain") - to_chat(owner, examine_block(span_green("This item is restricted to your ckey only. Thank you!"))) - - return TRUE - -/// Select [path] item to [category_slot] slot. -/datum/loadout_manager/proc/select_item(datum/loadout_item/selected_item) - var/num_misc_items = 0 - var/datum/loadout_item/first_misc_found - for(var/datum/loadout_item/item as anything in loadout_list_to_datums(owner.prefs.loadout_list)) - if(item.category == selected_item.category) - if((item.category == LOADOUT_ITEM_MISC || item.category == LOADOUT_ITEM_TOYS) && ++num_misc_items < MAX_ALLOWED_MISC_ITEMS) - if(!first_misc_found) - first_misc_found = item - continue - - deselect_item(first_misc_found || item) - continue - - LAZYSET(owner.prefs.loadout_list, selected_item.item_path, list()) - -/// Deselect [deselected_item]. -/datum/loadout_manager/proc/deselect_item(datum/loadout_item/deselected_item) - LAZYREMOVE(owner.prefs.loadout_list, deselected_item.item_path) - -/// Select [path] item to [category_slot] slot, and open up the greyscale UI to customize [path] in [category] slot. -/datum/loadout_manager/proc/select_item_color(datum/loadout_item/item) - if(menu) - to_chat(owner, span_warning("You already have a greyscaling window open!")) - return - - var/obj/item/colored_item = item.item_path - - var/list/allowed_configs = list() - if(initial(colored_item.greyscale_config)) - allowed_configs += "[initial(colored_item.greyscale_config)]" - if(initial(colored_item.greyscale_config_worn)) - allowed_configs += "[initial(colored_item.greyscale_config_worn)]" - if(initial(colored_item.greyscale_config_inhand_left)) - allowed_configs += "[initial(colored_item.greyscale_config_inhand_left)]" - if(initial(colored_item.greyscale_config_inhand_right)) - allowed_configs += "[initial(colored_item.greyscale_config_inhand_right)]" - - var/slot_starting_colors = initial(colored_item.greyscale_colors) - if((colored_item in owner.prefs.loadout_list) && (INFO_GREYSCALE in owner.prefs.loadout_list[colored_item])) - slot_starting_colors = owner.prefs.loadout_list[colored_item][INFO_GREYSCALE] - - menu = new( - src, - usr, - allowed_configs, - CALLBACK(src, PROC_REF(set_slot_greyscale), colored_item), - starting_icon_state = initial(colored_item.icon_state), - starting_config = initial(colored_item.greyscale_config), - starting_colors = slot_starting_colors, - unlocked = TRUE, - ) - RegisterSignal(menu, COMSIG_PREQDELETED, TYPE_PROC_REF(/datum/loadout_manager, cleanup_greyscale_menu)) - menu.ui_interact(usr) - -/// A proc to make sure our menu gets null'd properly when it's deleted. -/// If we delete the greyscale menu from the greyscale datum, we don't null it correctly here, it harddels. -/datum/loadout_manager/proc/cleanup_greyscale_menu(datum/source) - SIGNAL_HANDLER - - menu = null - -/// Sets [category_slot]'s greyscale colors to the colors in the currently opened [open_menu]. -/datum/loadout_manager/proc/set_slot_greyscale(path, datum/greyscale_modify_menu/open_menu) - if(!open_menu) - CRASH("set_slot_greyscale called without a greyscale menu!") - - if(isnull(owner)) - CRASH("set_slot_greyscale called without an owner!") - - if(!(path in owner.prefs.loadout_list)) - to_chat(owner, span_warning("Select the item before attempting to apply greyscale to it!")) - return - - var/list/colors = open_menu.split_colors - if(colors) - owner.prefs.loadout_list[path][INFO_GREYSCALE] = colors.Join("") - owner.prefs?.character_preview_view.update_body() - -/// Set [item]'s name to input provided. -/datum/loadout_manager/proc/set_item_name(datum/loadout_item/item) - var/current_name = "" - var/current_desc = "" - - if(!(item.item_path in owner.prefs.loadout_list)) - to_chat(owner, span_warning("Select the item before attempting to name it!")) - return - - if(INFO_NAMED in owner.prefs.loadout_list[item.item_path]) - current_name = owner.prefs.loadout_list[item.item_path][INFO_NAMED] - if(INFO_DESCRIBED in owner.prefs.loadout_list[item.item_path]) - current_desc = owner.prefs.loadout_list[item.item_path][INFO_DESCRIBED] - - var/input_name = tgui_input_text(owner, "What name do you want to give [item.name]? Leave blank to clear.", "[item.name] name", current_name, MAX_NAME_LEN) - var/input_desc = tgui_input_text(owner, "What description do you want to give [item.name]? 256 character max, leave blank to clear.", "[item.name] description", current_desc, 256, multiline = TRUE) - if(QDELETED(src) || QDELETED(owner) || QDELETED(owner.prefs)) - return - - if(input_name) - owner.prefs.loadout_list[item.item_path][INFO_NAMED] = input_name - else - if(INFO_NAMED in owner.prefs.loadout_list[item.item_path]) - owner.prefs.loadout_list[item.item_path] -= INFO_NAMED - if(input_desc) - owner.prefs.loadout_list[item.item_path][INFO_DESCRIBED] = input_desc - else - if(INFO_DESCRIBED in owner.prefs.loadout_list[item.item_path]) - owner.prefs.loadout_list[item.item_path] -= INFO_DESCRIBED - -/// If only certain jobs are allowed to equip this loadout item, display which -/datum/loadout_manager/proc/display_job_restrictions(datum/loadout_item/item) - if(!length(item.restricted_roles)) - return - var/composed_message = span_boldnotice("The [initial(item.item_path.name)] is whitelisted to the following roles:
") - for(var/job_type in item.restricted_roles) - composed_message += span_green("[job_type]
") - - to_chat(owner, examine_block(composed_message)) - -/// If certain jobs aren't allowed to equip this loadout item, display which -/datum/loadout_manager/proc/display_job_blacklists(datum/loadout_item/item) - if(!length(item.blacklisted_roles)) - return - var/composed_message = span_boldnotice("The [initial(item.item_path.name)] is blacklisted from the following roles:
") - for(var/job_type in item.blacklisted_roles) - composed_message += span_red("[job_type]
") - - to_chat(owner, examine_block(composed_message)) - -/// If only a certain species is allowed to equip this loadout item, display which -/datum/loadout_manager/proc/display_species_restrictions(datum/loadout_item/item) - if(!length(item.restricted_species)) - return - var/composed_message = span_boldnotice("\The [initial(item.item_path.name)] is restricted to the following species:
") - for(var/species_type in item.restricted_species) - composed_message += span_grey("[species_type]
") - - to_chat(owner, examine_block(composed_message)) - -/datum/loadout_manager/ui_data(mob/user) - var/list/data = list() - - var/list/all_selected_paths = list() - for(var/path in owner?.prefs?.loadout_list) - all_selected_paths += path - data["selected_loadout"] = all_selected_paths - data["user_is_donator"] = !!(GLOB.donator_list[owner.ckey] || is_admin(owner)) - - return data - -/datum/loadout_manager/ui_static_data() - var/list/data = list() - - // [name] is the name of the tab that contains all the corresponding contents. - // [title] is the name at the top of the list of corresponding contents. - // [contents] is a formatted list of all the possible items for that slot. - // - [contents.path] is the path the singleton datum holds - // - [contents.name] is the name of the singleton datum - // - [contents.is_renamable], whether the item can be renamed in the UI - // - [contents.is_greyscale], whether the item can be greyscaled in the UI - // - [contents.tooltip_text], any additional tooltip text that hovers over the item's select button - - var/list/loadout_tabs = list() - loadout_tabs += list(list("name" = "Belt", "title" = "Belt Slot Items", "contents" = list_to_data(GLOB.loadout_belts))) - loadout_tabs += list(list("name" = "Ears", "title" = "Ear Slot Items", "contents" = list_to_data(GLOB.loadout_ears))) - loadout_tabs += list(list("name" = "Glasses", "title" = "Glasses Slot Items", "contents" = list_to_data(GLOB.loadout_glasses))) - loadout_tabs += list(list("name" = "Gloves", "title" = "Glove Slot Items", "contents" = list_to_data(GLOB.loadout_gloves))) - loadout_tabs += list(list("name" = "Head", "title" = "Head Slot Items", "contents" = list_to_data(GLOB.loadout_helmets))) - loadout_tabs += list(list("name" = "Mask", "title" = "Mask Slot Items", "contents" = list_to_data(GLOB.loadout_masks))) - loadout_tabs += list(list("name" = "Neck", "title" = "Neck Slot Items", "contents" = list_to_data(GLOB.loadout_necks))) - loadout_tabs += list(list("name" = "Shoes", "title" = "Shoe Slot Items", "contents" = list_to_data(GLOB.loadout_shoes))) - loadout_tabs += list(list("name" = "Suit", "title" = "Suit Slot Items", "contents" = list_to_data(GLOB.loadout_exosuits))) - loadout_tabs += list(list("name" = "Jumpsuit", "title" = "Uniform Slot Items", "contents" = list_to_data(GLOB.loadout_jumpsuits))) - loadout_tabs += list(list("name" = "Formal", "title" = "Uniform Slot Items (cont)", "contents" = list_to_data(GLOB.loadout_undersuits))) - loadout_tabs += list(list("name" = "Misc. Under", "title" = "Uniform Slot Items (cont)", "contents" = list_to_data(GLOB.loadout_miscunders))) - loadout_tabs += list(list("name" = "Accessory", "title" = "Uniform Accessory Slot Items", "contents" = list_to_data(GLOB.loadout_accessory))) - loadout_tabs += list(list("name" = "Inhand", "title" = "In-hand Items", "contents" = list_to_data(GLOB.loadout_inhand_items))) - loadout_tabs += list(list("name" = "Toys", "title" = "Toys! ([MAX_ALLOWED_MISC_ITEMS] max)", "contents" = list_to_data(GLOB.loadout_toys))) - loadout_tabs += list(list("name" = "Other", "title" = "Backpack Items ([MAX_ALLOWED_MISC_ITEMS] max)", "contents" = list_to_data(GLOB.loadout_pocket_items))) - - data["loadout_tabs"] = loadout_tabs - - return data - -/* - * Takes an assoc list of [typepath]s to [singleton datum] - * And formats it into an object for TGUI. - * - * - list[name] is the name of the datum. - * - list[path] is the typepath of the item. - */ -/datum/loadout_manager/proc/list_to_data(list_of_datums) - if(!LAZYLEN(list_of_datums)) - return - - var/list/formatted_list = new(length(list_of_datums)) - - var/array_index = 1 - for(var/datum/loadout_item/item as anything in list_of_datums) - if(!isnull(item.ckeywhitelist)) //These checks are also performed in the backend. - if(!(owner.ckey in item.ckeywhitelist)) - formatted_list.len-- - continue - if(item.donator_only) //These checks are also performed in the backend. - if(!GLOB.donator_list[owner.ckey] && !is_admin(owner)) - formatted_list.len-- - continue - if(item.required_season && !check_holidays(item.required_season)) - formatted_list.len-- - continue - - var/atom/loadout_atom = item.item_path - - var/list/formatted_item = list() - formatted_item["name"] = item.name - formatted_item["path"] = item.item_path - formatted_item["is_greyscale"] = !!(initial(loadout_atom.greyscale_config) && initial(loadout_atom.greyscale_colors) && (initial(loadout_atom.flags_1) & IS_PLAYER_COLORABLE_1)) - formatted_item["is_renameable"] = item.can_be_named - formatted_item["is_job_restricted"] = !isnull(item.restricted_roles) - formatted_item["is_job_blacklisted"] = !isnull(item.blacklisted_roles) - formatted_item["is_species_restricted"] = !isnull(item.restricted_species) - formatted_item["is_donator_only"] = !isnull(item.donator_only) - formatted_item["is_ckey_whitelisted"] = !isnull(item.ckeywhitelist) - if(LAZYLEN(item.additional_tooltip_contents)) - formatted_item["tooltip_text"] = item.additional_tooltip_contents.Join("\n") - - formatted_list[array_index++] = formatted_item - - return formatted_list - - diff --git a/modular_skyrat/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm b/modular_skyrat/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm deleted file mode 100644 index 2469deb875e3d..0000000000000 --- a/modular_skyrat/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm +++ /dev/null @@ -1,168 +0,0 @@ -/// -- Outfit and mob helpers to equip our loadout items. -- - -/// An empty outfit we fill in with our loadout items to dress our dummy. -/datum/outfit/player_loadout - name = "Player Loadout" - -/datum/outfit/player_loadout/equip(mob/living/carbon/human/user, visualsOnly) - . = ..() - user.equip_outfit_and_loadout(new /datum/outfit(), user.client.prefs) - -/* - * Actually equip our mob with our job outfit and our loadout items. - * Loadout items override the pre-existing item in the corresponding slot of the job outfit. - * Some job items are preserved after being overridden - belt items, ear items, and glasses. - * The rest of the slots, the items are overridden completely and deleted. - * - * Plasmamen are snowflaked to not have any envirosuit pieces removed just in case. - * Their loadout items for those slots will be added to their backpack on spawn. - * - * outfit - the job outfit we're equipping - * visuals_only - whether we call special equipped procs, or if we just look like we equipped it - * preference_source - the preferences of the thing we're equipping - */ -/mob/living/carbon/human/proc/equip_outfit_and_loadout(datum/outfit/outfit, datum/preferences/preference_source, visuals_only = FALSE, datum/job/equipping_job) - if (!preference_source) - equipOutfit(outfit, visuals_only) // no prefs for loadout items, but we should still equip the outfit. - return FALSE - - var/datum/outfit/equipped_outfit - - if(ispath(outfit)) - equipped_outfit = new outfit() - else if(istype(outfit)) - equipped_outfit = outfit - else - CRASH("Outfit passed to equip_outfit_and_loadout was neither a path nor an instantiated type!") - - var/override_preference = preference_source.read_preference(/datum/preference/choiced/loadout_override_preference) - - var/list/loadout_datums = loadout_list_to_datums(preference_source?.loadout_list) - - if(override_preference == LOADOUT_OVERRIDE_CASE && !visuals_only) - var/obj/item/storage/briefcase/empty/briefcase = new(loc) - - for(var/datum/loadout_item/item as anything in loadout_datums) - if(item.restricted_roles && equipping_job && !(equipping_job.title in item.restricted_roles)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job restrictions!")) - continue - - if(item.blacklisted_roles && equipping_job && (equipping_job.title in item.blacklisted_roles)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job blacklists!")) - continue - - if(item.restricted_species && !(dna.species.id in item.restricted_species)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item ([initial(item.item_path.name)]) due to species restrictions!")) - continue - - new item.item_path(briefcase) - - briefcase.name = "[preference_source.read_preference(/datum/preference/name/real_name)]'s travel suitcase" - equipOutfit(equipped_outfit, visuals_only) - put_in_hands(briefcase) - else - for(var/datum/loadout_item/item as anything in loadout_datums) - if(item.restricted_roles && equipping_job && !(equipping_job.title in item.restricted_roles)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job restrictions!")) - continue - - if(item.blacklisted_roles && equipping_job && (equipping_job.title in item.blacklisted_roles)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item([initial(item.item_path.name)]) due to job blacklists!")) - continue - - if(item.restricted_species && !(dna.species.id in item.restricted_species)) - if(client) - to_chat(src, span_warning("You were unable to get a loadout item ([initial(item.item_path.name)]) due to species restrictions!")) - continue - - // Make sure the item is not overriding an important for life outfit item - var/datum/outfit/outfit_important_for_life = dna.species.outfit_important_for_life - if(!outfit_important_for_life || !item.pre_equip_item(equipped_outfit, outfit_important_for_life, src, visuals_only)) - item.insert_path_into_outfit(equipped_outfit, src, visuals_only, override_preference) - - - equipOutfit(equipped_outfit, visuals_only) - - for(var/datum/loadout_item/item as anything in loadout_datums) - if(item.restricted_roles && equipping_job && !(equipping_job.title in item.restricted_roles)) - continue - item.on_equip_item(preference_source, src, visuals_only) - - regenerate_icons() - return TRUE - -/* - * Takes a list of paths (such as a loadout list) - * and returns a list of their singleton loadout item datums - * - * loadout_list - the list being checked - * - * returns a list of singleton datums - */ -/proc/loadout_list_to_datums(list/loadout_list) - RETURN_TYPE(/list) - - . = list() - - if(!GLOB.all_loadout_datums.len) - CRASH("No loadout datums in the global loadout list!") - - for(var/path in loadout_list) - if(!GLOB.all_loadout_datums[path]) - stack_trace("Could not find ([path]) loadout item in the global list of loadout datums!") - continue - - . |= GLOB.all_loadout_datums[path] - - -/* - * Removes all invalid paths from loadout lists. - * - * passed_list - the loadout list we're sanitizing. - * - * returns a list - */ -/proc/update_loadout_list(list/passed_list) - RETURN_TYPE(/list) - - var/list/list_to_update = LAZYLISTDUPLICATE(passed_list) - for(var/thing in list_to_update) //thing, 'cause it could be a lot of things - if(ispath(thing)) - break - var/our_path = text2path(list_to_update[thing]) - - LAZYREMOVE(list_to_update, thing) - if(ispath(our_path)) - LAZYSET(list_to_update, our_path, list()) - - return list_to_update - -/* - * Removes all invalid paths from loadout lists. - * - * passed_list - the loadout list we're sanitizing. - * - * returns a list - */ -/proc/sanitize_loadout_list(list/passed_list) - RETURN_TYPE(/list) - - var/list/list_to_clean = LAZYLISTDUPLICATE(passed_list) - for(var/path in list_to_clean) - if(!ispath(path)) - stack_trace("invalid path found in loadout list! (Path: [path])") - LAZYREMOVE(list_to_clean, path) - - else if(!(path in GLOB.all_loadout_datums)) - stack_trace("invalid loadout slot found in loadout list! Path: [path]") - LAZYREMOVE(list_to_clean, path) - - return list_to_clean - -/obj/item/storage/briefcase/empty/PopulateContents() - return diff --git a/modular_skyrat/modules/loadouts/readme.md b/modular_skyrat/modules/loadouts/readme.md deleted file mode 100644 index f3ce555ea8ffb..0000000000000 --- a/modular_skyrat/modules/loadouts/readme.md +++ /dev/null @@ -1,12 +0,0 @@ -## Title: MrMelbert's loadout system! - -MODULE ID: LOADOUT - -### Description: - -A loadout system that uses TGUI to equip players post roundstart. - - -### Credits: -MrMelbert - https://github.com/Jolly-66/JollyStationCode/pull/78 (original code) -Gandalf2k15 - Porting diff --git a/modular_skyrat/modules/teshari/code/_teshari.dm b/modular_skyrat/modules/teshari/code/_teshari.dm index 6fd298110554a..39dd33443bfa5 100644 --- a/modular_skyrat/modules/teshari/code/_teshari.dm +++ b/modular_skyrat/modules/teshari/code/_teshari.dm @@ -20,18 +20,18 @@ payday_modifier = 1.0 mutanttongue = /obj/item/organ/internal/tongue/teshari custom_worn_icons = list( - LOADOUT_ITEM_HEAD = TESHARI_HEAD_ICON, - LOADOUT_ITEM_MASK = TESHARI_MASK_ICON, - LOADOUT_ITEM_NECK = TESHARI_NECK_ICON, + OFFSET_HEAD = TESHARI_HEAD_ICON, + OFFSET_MASK = TESHARI_MASK_ICON, + OFFSET_NECK = TESHARI_NECK_ICON, LOADOUT_ITEM_SUIT = TESHARI_SUIT_ICON, LOADOUT_ITEM_UNIFORM = TESHARI_UNIFORM_ICON, LOADOUT_ITEM_HANDS = TESHARI_HANDS_ICON, - LOADOUT_ITEM_SHOES = TESHARI_FEET_ICON, + OFFSET_SHOES = TESHARI_FEET_ICON, LOADOUT_ITEM_GLASSES = TESHARI_EYES_ICON, - LOADOUT_ITEM_BELT = TESHARI_BELT_ICON, + OFFSET_BELT = TESHARI_BELT_ICON, LOADOUT_ITEM_MISC = TESHARI_BACK_ICON, - LOADOUT_ITEM_ACCESSORY = TESHARI_ACCESSORIES_ICON, - LOADOUT_ITEM_EARS = TESHARI_EARS_ICON + OFFSET_ACCESSORY = TESHARI_ACCESSORIES_ICON, + OFFSET_EARS = TESHARI_EARS_ICON ) coldmod = TESHARI_COLDMOD heatmod = TESHARI_HEATMOD diff --git a/modular_skyrat/modules/teshari/code/teshari_bodytype.dm b/modular_skyrat/modules/teshari/code/teshari_bodytype.dm index 2cd6d1b918de5..57a83a48e3ec4 100644 --- a/modular_skyrat/modules/teshari/code/teshari_bodytype.dm +++ b/modular_skyrat/modules/teshari/code/teshari_bodytype.dm @@ -29,12 +29,12 @@ return // If there isn't even a fallback, use snouted sprites for masks and helmets, but offsetted - if((item_slot == LOADOUT_ITEM_MASK || item_slot == LOADOUT_ITEM_HEAD) && (item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) + if((item_slot == OFFSET_FACEMASK || item_slot == OFFSET_HEAD) && (item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) var/obj/item/bodypart/head/my_head = human_owner.get_bodypart(BODY_ZONE_HEAD) var/datum/worn_feature_offset/selected_offset var/human_icon var/human_icon_state = item.worn_icon_state || item.icon_state - if(item_slot == LOADOUT_ITEM_HEAD) + if(item_slot == OFFSET_HEAD) human_icon = item.worn_icon_muzzled || SNOUTED_HEAD_FILE selected_offset = my_head?.worn_head_offset diff --git a/tgstation.dme b/tgstation.dme index fbf9f7d6d54ca..29723ab8fa4f2 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -438,7 +438,7 @@ #include "code\__DEFINES\~skyrat_defines\lewd_defines.dm" #include "code\__DEFINES\~skyrat_defines\liquids.dm" #include "code\__DEFINES\~skyrat_defines\living.dm" -#include "code\__DEFINES\~skyrat_defines\loadouts.dm" +#include "code\__DEFINES\~skyrat_defines\loadout.dm" #include "code\__DEFINES\~skyrat_defines\logging.dm" #include "code\__DEFINES\~skyrat_defines\manufacturer_strings.dm" #include "code\__DEFINES\~skyrat_defines\mapping.dm" @@ -1843,7 +1843,6 @@ #include "code\datums\quirks\neutral_quirks\photographer.dm" #include "code\datums\quirks\neutral_quirks\pineapple_hater.dm" #include "code\datums\quirks\neutral_quirks\pineapple_liker.dm" -#include "code\datums\quirks\neutral_quirks\pride_pin.dm" #include "code\datums\quirks\neutral_quirks\shifty_eyes.dm" #include "code\datums\quirks\neutral_quirks\snob.dm" #include "code\datums\quirks\neutral_quirks\transhumanist.dm" @@ -3814,7 +3813,6 @@ #include "code\modules\client\preferences\pixel_size.dm" #include "code\modules\client\preferences\playtime_reward_cloak.dm" #include "code\modules\client\preferences\preferred_map.dm" -#include "code\modules\client\preferences\pride_pin.dm" #include "code\modules\client\preferences\prisoner_crime.dm" #include "code\modules\client\preferences\prosthetic_limb.dm" #include "code\modules\client\preferences\prosthetic_organ.dm" @@ -3850,6 +3848,7 @@ #include "code\modules\client\preferences\migrations\body_type_migration.dm" #include "code\modules\client\preferences\migrations\convert_to_json_savefile.dm" #include "code\modules\client\preferences\migrations\legacy_sound_toggles_migration.dm" +#include "code\modules\client\preferences\migrations\quirk_loadout_migration.dm" #include "code\modules\client\preferences\migrations\tgui_prefs_migration.dm" #include "code\modules\client\preferences\migrations\tts_blip_migration.dm" #include "code\modules\client\preferences\species_features\basic.dm" @@ -4524,6 +4523,17 @@ #include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" #include "code\modules\lighting\static_lighting_area.dm" +#include "code\modules\loadout\loadout_categories.dm" +#include "code\modules\loadout\loadout_helpers.dm" +#include "code\modules\loadout\loadout_items.dm" +#include "code\modules\loadout\loadout_menu.dm" +#include "code\modules\loadout\loadout_preference.dm" +#include "code\modules\loadout\categories\accessories.dm" +#include "code\modules\loadout\categories\glasses.dm" +#include "code\modules\loadout\categories\heads.dm" +#include "code\modules\loadout\categories\inhands.dm" +#include "code\modules\loadout\categories\neck.dm" +#include "code\modules\loadout\categories\pocket.dm" #include "code\modules\logging\log_category.dm" #include "code\modules\logging\log_entry.dm" #include "code\modules\logging\log_holder.dm" @@ -6630,6 +6640,21 @@ #include "modular_skyrat\master_files\code\modules\jobs\job_types\warden.dm" #include "modular_skyrat\master_files\code\modules\language\_language.dm" #include "modular_skyrat\master_files\code\modules\language\language_holder.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\accessories.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\belts.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\donator_personal.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\ears.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\glasses.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\gloves.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\heads.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\inhands.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\mask.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\neck.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\pocket.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\shoes.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\suit.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\toys.dm" +#include "modular_skyrat\master_files\code\modules\loadout\categories\uniform.dm" #include "modular_skyrat\master_files\code\modules\logging\categories\log_category_debug.dm" #include "modular_skyrat\master_files\code\modules\logging\categories\log_category_game.dm" #include "modular_skyrat\master_files\code\modules\logging\categories\log_category_uplink.dm" @@ -7621,25 +7646,6 @@ #include "modular_skyrat\modules\liquids\code\reagents\reagent_containers.dm" #include "modular_skyrat\modules\liquids\code\reagents\chemistry\holder.dm" #include "modular_skyrat\modules\liquids\code\reagents\chemistry\reagents.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\_loadout_datum.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_accessory.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_belts.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_ears.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_glasses.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_gloves.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_heads.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_inhands.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_masks.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_neck.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_pocket.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_shoes.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_suit.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\loadout_datum_toys.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\donator\personal\donator_personal.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\under\donator.dm" -#include "modular_skyrat\modules\loadouts\loadout_items\under\loadout_datum_under.dm" -#include "modular_skyrat\modules\loadouts\loadout_ui\loadout_manager.dm" -#include "modular_skyrat\modules\loadouts\loadout_ui\loadout_outfit_helpers.dm" #include "modular_skyrat\modules\lorecaster\code\archive_viewer.dm" #include "modular_skyrat\modules\lorecaster\code\config.dm" #include "modular_skyrat\modules\lorecaster\code\story_manager.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx index a366ee881fd99..05ce025e4d34c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx @@ -11,6 +11,7 @@ import { JobsPage } from './JobsPage'; import { LanguagesPage } from './LanguagesMenu'; import { LimbsPage } from './LimbsPage'; // SKYRAT EDIT END +import { LoadoutPage } from './loadout/index'; import { MainPage } from './MainPage'; import { PageButton } from './PageButton'; import { QuirksPage } from './QuirksPage'; @@ -26,6 +27,7 @@ enum Page { // SKYRAT EDIT END Species, Quirks, + Loadout, } const CharacterProfiles = (props: { @@ -95,6 +97,11 @@ export const CharacterPreferenceWindow = (props) => { case Page.Quirks: pageContents = ; break; + + case Page.Loadout: + pageContents = ; + break; + default: exhaustiveCheck(currentPage); } @@ -136,6 +143,16 @@ export const CharacterPreferenceWindow = (props) => { + + + Loadout + + + void; handleOpenSpecies: () => void; - handleLoadout: () => void; // SKYRAT EDIT ADDITION handleFood: () => void; // SKYRAT EDIT ADDITION gender: Gender; setGender: (gender: Gender) => void; @@ -82,17 +81,6 @@ const CharacterControls = (props: { )} {/* SKYRAT EDIT ADDITION START */} - {props.handleLoadout && ( - - + ); +}; + +const ItemListDisplay = (props: { items: LoadoutItem[] }) => { + const { data } = useBackend(); + const { loadout_list } = data.character_preferences.misc; + return ( + + {props.items.map((item) => ( + + + + ))} + + ); +}; + +export const LoadoutTabDisplay = (props: { + category: LoadoutCategory | undefined; +}) => { + const { category } = props; + if (!category) { + return ( + + Erroneous category detected! This is a bug, please report it. + + ); + } + + return ; +}; + +export const SearchDisplay = (props: { + loadout_tabs: LoadoutCategory[]; + currentSearch: string; +}) => { + const { loadout_tabs, currentSearch } = props; + + const search = createSearch( + currentSearch, + (loadout_item: LoadoutItem) => loadout_item.name, + ); + + const validLoadoutItems = loadout_tabs + .flatMap((tab) => tab.contents) + .filter(search) + .sort((a, b) => (a.name > b.name ? 1 : -1)); + + if (validLoadoutItems.length === 0) { + return No items found!; + } + + return ; +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ModifyPanel.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ModifyPanel.tsx new file mode 100644 index 0000000000000..70959691af850 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ModifyPanel.tsx @@ -0,0 +1,219 @@ +import { useBackend } from '../../../backend'; +import { + Box, + Button, + Dimmer, + DmIcon, + Flex, + Icon, + LabeledList, + Section, + Stack, +} from '../../../components'; +import { FAIcon, LoadoutItem, LoadoutManagerData, ReskinOption } from './base'; +import { ItemIcon } from './ItemDisplay'; + +// Used in LoadoutItem to make buttons relating to how an item can be edited +export type LoadoutButton = { + label: string; + act_key?: string; + button_icon?: FAIcon; + button_text?: string; + active_key?: string; + active_text?: string; + inactive_text?: string; + tooltip_text?: string; +}; + +const LoadoutModifyButton = (props: { + button: LoadoutButton; + modifyItemDimmer: LoadoutItem; +}) => { + const { act, data } = useBackend(); + const { loadout_list } = data.character_preferences.misc; + const { button, modifyItemDimmer } = props; + + const buttonIsActive = + button.active_key && loadout_list[modifyItemDimmer.path][button.active_key]; + + if (button.active_text && button.inactive_text) { + return ( + { + act('pass_to_loadout_item', { + subaction: button.act_key, + path: modifyItemDimmer.path, + }); + }} + > + {buttonIsActive ? button.active_text : button.inactive_text} + + ); + } + + return ( + + ); +}; + +const LoadoutModifyButtons = (props: { modifyItemDimmer: LoadoutItem }) => { + const { act, data } = useBackend(); + const { loadout_list } = data.character_preferences.misc; + const { modifyItemDimmer } = props; + + const isActive = (item: LoadoutItem, reskin: ReskinOption) => { + return loadout_list && loadout_list[item.path]['reskin'] + ? loadout_list[item.path]['reskin'] === reskin.name + : item.icon_state === reskin.skin_icon_state; + }; + + return ( + + + + {!!modifyItemDimmer.reskins && ( + + + {modifyItemDimmer.reskins.map((reskin) => ( + + + + ))} + + + )} + {modifyItemDimmer.buttons.map((button) => ( + + + + ))} + + + + ); +}; + +const LoadoutModifyItemDisplay = (props: { modifyItemDimmer: LoadoutItem }) => { + const { modifyItemDimmer } = props; + return ( + + + + {modifyItemDimmer.name} + + + + + + + ); +}; + +export const LoadoutModifyDimmer = (props: { + modifyItemDimmer: LoadoutItem; + setModifyItemDimmer: (dimmer: LoadoutItem | null) => void; +}) => { + const { act } = useBackend(); + const { modifyItemDimmer, setModifyItemDimmer } = props; + return ( + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts new file mode 100644 index 0000000000000..33f8cabea9cb0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts @@ -0,0 +1,46 @@ +import { BooleanLike } from '../../../../common/react'; +import { PreferencesMenuData } from '../data'; +import { LoadoutButton } from './ModifyPanel'; + +// Generic types +export type DmIconFile = string; +export type DmIconState = string; +export type FAIcon = string; +export type typePath = string; + +type LoadoutInfoKey = string; +type LoadoutInfoValue = string; +// Info about a loadout item (key to info, such as color, reskin, layer, etc) +type LoadoutListInfo = Record | []; +// Typepath to info about the item +export type LoadoutList = Record; + +// Used for holding reskin information +export type ReskinOption = { + name: string; + tooltip: string; + skin_icon_state: DmIconState; // The icon is the same as the item icon +}; + +// Actual item passed in from the loadout +export type LoadoutItem = { + name: string; + path: typePath; + icon: DmIconFile | null; + icon_state: DmIconState | null; + buttons: LoadoutButton[]; + reskins: ReskinOption[] | null; + information: string[]; +}; + +// Category of items in the loadout +export type LoadoutCategory = { + name: string; + category_icon: FAIcon | null; + category_info: string | null; + contents: LoadoutItem[]; +}; + +export type LoadoutManagerData = PreferencesMenuData & { + job_clothes: BooleanLike; +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/index.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/index.tsx new file mode 100644 index 0000000000000..211f8ed8ae5e1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/index.tsx @@ -0,0 +1,337 @@ +import { Fragment, useState } from 'react'; + +import { useBackend } from '../../../backend'; +import { + Box, + Button, + Divider, + Icon, + Input, + NoticeBox, + Section, + Stack, + Tabs, +} from '../../../components'; +import { CharacterPreview } from '../../common/CharacterPreview'; +import { ServerData } from '../data'; +import { ServerPreferencesFetcher } from '../ServerPreferencesFetcher'; +import { + LoadoutCategory, + LoadoutItem, + LoadoutManagerData, + typePath, +} from './base'; +import { ItemIcon, LoadoutTabDisplay, SearchDisplay } from './ItemDisplay'; +import { LoadoutModifyDimmer } from './ModifyPanel'; + +export const LoadoutPage = () => { + return ( + { + if (!serverData) { + return Loading...; + } + const loadoutServerData: ServerData = serverData; + return ( + + ); + }} + /> + ); +}; + +const LoadoutPageInner = (props: { loadout_tabs: LoadoutCategory[] }) => { + const { loadout_tabs } = props; + const [searchLoadout, setSearchLoadout] = useState(''); + const [selectedTabName, setSelectedTab] = useState(loadout_tabs[0].name); + const [modifyItemDimmer, setModifyItemDimmer] = useState( + null, + ); + + return ( + + + {!!modifyItemDimmer && ( + + )} +
setSearchLoadout(value)} + placeholder="Search for an item..." + value={searchLoadout} + /> + } + > + + {loadout_tabs.map((curTab) => ( + { + setSelectedTab(curTab.name); + setSearchLoadout(''); + }} + > + + {curTab.category_icon && ( + + )} + {curTab.name} + + + ))} + +
+
+ + + +
+ ); +}; + +const LoadoutTabs = (props: { + loadout_tabs: LoadoutCategory[]; + currentTab: string; + currentSearch: string; + modifyItemDimmer: LoadoutItem | null; + setModifyItemDimmer: (dimmer: LoadoutItem | null) => void; +}) => { + const { + loadout_tabs, + currentTab, + currentSearch, + modifyItemDimmer, + setModifyItemDimmer, + } = props; + const activeCategory = loadout_tabs.find((curTab) => { + return curTab.name === currentTab; + }); + const searching = currentSearch.length > 1; + + return ( + + + + + + + + + + + + + {searching || activeCategory?.contents ? ( +
+ {activeCategory.category_info} + + ) : null + } + > + + + {searching ? ( + + ) : ( + + )} + + +
+ ) : ( +
+ No contents for selected tab. +
+ )} +
+
+ ); +}; + +const typepathToLoadoutItem = ( + typepath: typePath, + all_tabs: LoadoutCategory[], +) => { + // Maybe a bit inefficient, could be replaced with a hashmap? + for (const tab of all_tabs) { + for (const item of tab.contents) { + if (item.path === typepath) { + return item; + } + } + } + return null; +}; + +const LoadoutSelectedItem = (props: { + path: typePath; + all_tabs: LoadoutCategory[]; + modifyItemDimmer: LoadoutItem | null; + setModifyItemDimmer: (dimmer: LoadoutItem | null) => void; +}) => { + const { all_tabs, path, modifyItemDimmer, setModifyItemDimmer } = props; + const { act } = useBackend(); + + const item = typepathToLoadoutItem(path, all_tabs); + if (!item) { + return null; + } + + return ( + + + + + {item.name} + {item.buttons.length ? ( + + + + ) : ( + // empty space + )} + + + + + ); +}; + +const LoadoutSelectedSection = (props: { + all_tabs: LoadoutCategory[]; + modifyItemDimmer: LoadoutItem | null; + setModifyItemDimmer: (dimmer: LoadoutItem | null) => void; +}) => { + const { act, data } = useBackend(); + const { loadout_list } = data.character_preferences.misc; + const { all_tabs, modifyItemDimmer, setModifyItemDimmer } = props; + + return ( +
act('clear_all_items')} + > + Clear All + + } + > + {loadout_list && + Object.entries(loadout_list).map(([path, item]) => ( + + + + + ))} +
+ ); +}; + +const LoadoutPreviewSection = () => { + const { act, data } = useBackend(); + + return ( +
act('toggle_job_clothes')} + > + Job Clothes + + } + > + + + + + + + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx deleted file mode 100644 index 70c6f8a8efec3..0000000000000 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { FeatureChoiced } from '../base'; -import { FeatureDropdownInput } from '../dropdowns'; - -export const pride_pin: FeatureChoiced = { - name: 'Pride Pin', - component: FeatureDropdownInput, -}; From 37afcb50045fc8f2a22956be5426b18f1f8b6e88 Mon Sep 17 00:00:00 2001 From: Waterpig Date: Tue, 2 Jul 2024 18:17:39 +0200 Subject: [PATCH 2/3] Loadout update fixes 1 --- code/_globalvars/traits/_traits.dm | 8 ++ .../code/modules/loadout/categories/pocket.dm | 82 ------------------- .../objects/structures/flags/signs_flags.dm | 2 - .../modules/loadout/categories/accessories.dm | 1 + .../code/modules/loadout/categories/ears.dm | 1 + .../categories/glasses.dm} | 0 .../categories/gloves.dm} | 0 .../categories/heads.dm} | 0 .../categories/inhands.dm} | 0 .../categories/masks.dm} | 0 .../categories/neck.dm} | 0 .../categories/pocket.dm} | 36 +++++++- .../categories/shoes.dm} | 0 .../categories/suit.dm} | 0 .../categories/toys.dm} | 0 .../categories/under.dm} | 0 .../categories}/~donator/donator_personal.dm | 0 .../overrides/loadout_items/loadout_datum.dm | 0 tgstation.dme | 26 +++--- 19 files changed, 55 insertions(+), 101 deletions(-) create mode 100644 modular_zubbers/code/modules/loadout/categories/accessories.dm create mode 100644 modular_zubbers/code/modules/loadout/categories/ears.dm rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_glasses.dm => loadout/categories/glasses.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_gloves.dm => loadout/categories/gloves.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_heads.dm => loadout/categories/heads.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_inhands.dm => loadout/categories/inhands.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_masks.dm => loadout/categories/masks.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_neck.dm => loadout/categories/neck.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_pocket.dm => loadout/categories/pocket.dm} (83%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_shoes.dm => loadout/categories/shoes.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_suit.dm => loadout/categories/suit.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_toys.dm => loadout/categories/toys.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items/loadout_datum_under.dm => loadout/categories/under.dm} (100%) rename modular_zubbers/code/modules/{loadouts/loadout_items => loadout/categories}/~donator/donator_personal.dm (100%) rename modular_zubbers/code/modules/{loadouts => loadout}/overrides/loadout_items/loadout_datum.dm (100%) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 6f4bbf8aa8b4b..05e72b3ace1d3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -139,6 +139,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BALD" = TRAIT_BALD, "TRAIT_BALLOON_SUTRA" = TRAIT_BALLOON_SUTRA, "TRAIT_BATON_RESISTANCE" = TRAIT_BATON_RESISTANCE, + "TRAIT_BEAST_EMPATHY" = TRAIT_BEAST_EMPATHY, "TRAIT_BEING_BLADE_SHIELDED" = TRAIT_BEING_BLADE_SHIELDED, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, @@ -209,6 +210,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_EXAMINE_FISHING_SPOT" = TRAIT_EXAMINE_FISHING_SPOT, "TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS, "TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV, + "TRAIT_EXPERT_FISHER" = TRAIT_EXPERT_FISHER, "TRAIT_EXTROVERT" = TRAIT_EXTROVERT, "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, "TRAIT_FASTMED" = TRAIT_FASTMED, @@ -418,6 +420,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROCK_METAMORPHIC" = TRAIT_ROCK_METAMORPHIC, "TRAIT_ROCK_STONER" = TRAIT_ROCK_STONER, "TRAIT_ROD_SUPLEX" = TRAIT_ROD_SUPLEX, + "TRAIT_ROUGHRIDER" = TRAIT_ROUGHRIDER, "TRAIT_SABRAGE_PRO" = TRAIT_SABRAGE_PRO, "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, @@ -450,7 +453,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_STIMULATED" = TRAIT_STIMULATED, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, + "TRAIT_STUBBY_BODY" = TRAIT_STUBBY_BODY, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, + "TRAIT_STURDY_FRAME" = TRAIT_STURDY_FRAME, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, "TRAIT_SUICIDED" = TRAIT_SUICIDED, "TRAIT_SUPERMATTER_SOOTHER" = TRAIT_SUPERMATTER_SOOTHER, @@ -551,6 +556,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /obj/item/bodypart = list( "TRAIT_PARALYSIS" = TRAIT_PARALYSIS, + /obj/item/bodypart = list( + "TRAIT_EASY_ATTACH" = TRAIT_EASY_ATTACH, + ), ), /obj/item/card/id = list( "TRAIT_JOB_FIRST_ID_CARD" = TRAIT_JOB_FIRST_ID_CARD, diff --git a/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm b/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm index 67087ff72cc25..8da5c716ce3a3 100644 --- a/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/pocket.dm @@ -1,85 +1,3 @@ -/* -* LOADOUT ITEM DATUMS FOR BACKPACK/POCKET SLOTS -*/ - -/// Pocket items (Moved to backpack) -GLOBAL_LIST_INIT(loadout_pocket_items, generate_loadout_items(/datum/loadout_item/pocket_items)) - -/datum/loadout_item/pocket_items - category = LOADOUT_ITEM_MISC - -/datum/loadout_item/pocket_items/pre_equip_item(datum/outfit/outfit, datum/outfit/outfit_important_for_life, mob/living/carbon/human/equipper, visuals_only = FALSE) // these go in the backpack - return FALSE - -// The wallet loadout item is special, and puts the player's ID and other small items into it on initialize (fancy!) -/datum/loadout_item/pocket_items/wallet - name = "Wallet" - item_path = /obj/item/storage/wallet - additional_tooltip_contents = list("FILLS AUTOMATICALLY - This item will populate itself with your ID card and other small items you may have on spawn.") - -// We add our wallet manually, later, so no need to put it in any outfits. -/datum/loadout_item/pocket_items/wallet/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only) - return FALSE - -// We didn't spawn any item yet, so nothing to call here. -/datum/loadout_item/pocket_items/wallet/on_equip_item(datum/preferences/preference_source, mob/living/carbon/human/equipper, visuals_only) - return FALSE - -// We add our wallet at the very end of character initialization (after quirks, etc) to ensure the backpack / their ID is all set by now. -/datum/loadout_item/pocket_items/wallet/post_equip_item(datum/preferences/preference_source, mob/living/carbon/human/equipper) - var/obj/item/card/id/advanced/id_card = equipper.get_item_by_slot(ITEM_SLOT_ID) - if(istype(id_card, /obj/item/storage/wallet)) - return - - var/obj/item/storage/wallet/wallet = new(equipper) - if(istype(id_card)) - equipper.temporarilyRemoveItemFromInventory(id_card, force = TRUE) - equipper.equip_to_slot_if_possible(wallet, ITEM_SLOT_ID, initial = TRUE) - id_card.forceMove(wallet) - - if(equipper.back) - var/list/backpack_stuff = equipper.back.atom_storage?.return_inv(FALSE) - for(var/obj/item/thing in backpack_stuff) - if(wallet.contents.len >= 3) - break - if(thing.w_class <= WEIGHT_CLASS_SMALL) - wallet.atom_storage.attempt_insert(src, thing, equipper, TRUE, FALSE) - else - if(!equipper.equip_to_slot_if_possible(wallet, slot = ITEM_SLOT_BACKPACK, initial = TRUE)) - wallet.forceMove(equipper.drop_location()) - -/* -* LUNCHBOX -*/ - -/datum/loadout_item/pocket_items/lunchbox_nanotrasen - name = "Nanotrasen Lunchbox" - item_path = /obj/item/storage/lunchbox/nanotrasen - -/datum/loadout_item/pocket_items/lunchbox_medical - name = "Medical Lunchbox" - item_path = /obj/item/storage/lunchbox/medical - -/datum/loadout_item/pocket_items/lunchbox_bunny - name = "Bunny Lunchbox" - item_path = /obj/item/storage/lunchbox/bunny - -/datum/loadout_item/pocket_items/lunchbox_corgi - name = "Corgi Lunchbox" - item_path = /obj/item/storage/lunchbox/corgi - -/datum/loadout_item/pocket_items/lunchbox_heart - name = "Heart Lunchbox" - item_path = /obj/item/storage/lunchbox/heart - -/datum/loadout_item/pocket_items/lunchbox_safetymoth - name = "Safety Moth Lunchbox" - item_path = /obj/item/storage/lunchbox/safetymoth - -/datum/loadout_item/pocket_items/lunchbox_amongus - name = "Suspicious Red Lunchbox" - item_path = /obj/item/storage/lunchbox/amongus - /* * GUM */ diff --git a/modular_zubbers/code/game/objects/structures/flags/signs_flags.dm b/modular_zubbers/code/game/objects/structures/flags/signs_flags.dm index 4dd078c3d327d..b04e033424b87 100644 --- a/modular_zubbers/code/game/objects/structures/flags/signs_flags.dm +++ b/modular_zubbers/code/game/objects/structures/flags/signs_flags.dm @@ -14,7 +14,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/flag/galfed, 32) desc = "The flag of the Tizirian Empire. The large red sun in the middle is a traditional Tizirian symbol representing their main deity, Aola." icon = 'modular_zubbers/icons/obj/flags.dmi' icon_state = "flag_tizira" - item_flag = /obj/item/sign/flag/tizira /obj/structure/sign/flag/terragov name = "flag of the Solarian State" @@ -32,7 +31,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/flag/galfed, 32) desc = "The folded flag of the Tizirian Empire." icon = 'modular_zubbers/icons/obj/flags.dmi' icon_state = "folded_tizira" - sign_path = /obj/structure/sign/flag/tizira /obj/item/sign/flag/terragov name = "folded flag of the Solarian State" diff --git a/modular_zubbers/code/modules/loadout/categories/accessories.dm b/modular_zubbers/code/modules/loadout/categories/accessories.dm new file mode 100644 index 0000000000000..b9ea3b8693650 --- /dev/null +++ b/modular_zubbers/code/modules/loadout/categories/accessories.dm @@ -0,0 +1 @@ +// THIS IS WHERE LOADOUT DATUMS GO FOR ACCESSORIES (REMOVE THIS COMMENT AND TICK THIS FILE IF YOU ADD ANYTHING) diff --git a/modular_zubbers/code/modules/loadout/categories/ears.dm b/modular_zubbers/code/modules/loadout/categories/ears.dm new file mode 100644 index 0000000000000..fd19e335a2217 --- /dev/null +++ b/modular_zubbers/code/modules/loadout/categories/ears.dm @@ -0,0 +1 @@ +// THIS IS WHERE LOADOUT DATUMS GO FOR EARS (REMOVE THIS COMMENT AND TICK THIS FILE IF YOU ADD ANYTHING) diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_glasses.dm b/modular_zubbers/code/modules/loadout/categories/glasses.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_glasses.dm rename to modular_zubbers/code/modules/loadout/categories/glasses.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_gloves.dm b/modular_zubbers/code/modules/loadout/categories/gloves.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_gloves.dm rename to modular_zubbers/code/modules/loadout/categories/gloves.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_heads.dm b/modular_zubbers/code/modules/loadout/categories/heads.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_heads.dm rename to modular_zubbers/code/modules/loadout/categories/heads.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_inhands.dm b/modular_zubbers/code/modules/loadout/categories/inhands.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_inhands.dm rename to modular_zubbers/code/modules/loadout/categories/inhands.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_masks.dm b/modular_zubbers/code/modules/loadout/categories/masks.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_masks.dm rename to modular_zubbers/code/modules/loadout/categories/masks.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_neck.dm b/modular_zubbers/code/modules/loadout/categories/neck.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_neck.dm rename to modular_zubbers/code/modules/loadout/categories/neck.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm b/modular_zubbers/code/modules/loadout/categories/pocket.dm similarity index 83% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm rename to modular_zubbers/code/modules/loadout/categories/pocket.dm index fc708a0f72bfe..2df1527444ef5 100644 --- a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm +++ b/modular_zubbers/code/modules/loadout/categories/pocket.dm @@ -102,10 +102,6 @@ name = "Folded Galactic Federation Flag" item_path = /obj/item/sign/flag/galfed -/datum/loadout_item/pocket_items/flag_moghes //sprites by Crumpaloo - name = "Folded Tizirian Empire Flag" - item_path = /obj/item/sign/flag/tizira - /* * NIF LENSES */ @@ -143,3 +139,35 @@ name = "Meson Scrying Lens Disk" item_path = /obj/item/disk/nifsoft_uploader/meson_hud restricted_roles = list(JOB_QUARTERMASTER, JOB_CARGO_TECHNICIAN, JOB_SHAFT_MINER, JOB_CUSTOMS_AGENT, JOB_CHIEF_ENGINEER, JOB_STATION_ENGINEER, JOB_ATMOSPHERIC_TECHNICIAN, JOB_ENGINEERING_GUARD) + +/* +* LUNCHBOX +*/ + +/datum/loadout_item/pocket_items/lunchbox_nanotrasen + name = "Nanotrasen Lunchbox" + item_path = /obj/item/storage/lunchbox/nanotrasen + +/datum/loadout_item/pocket_items/lunchbox_medical + name = "Medical Lunchbox" + item_path = /obj/item/storage/lunchbox/medical + +/datum/loadout_item/pocket_items/lunchbox_bunny + name = "Bunny Lunchbox" + item_path = /obj/item/storage/lunchbox/bunny + +/datum/loadout_item/pocket_items/lunchbox_corgi + name = "Corgi Lunchbox" + item_path = /obj/item/storage/lunchbox/corgi + +/datum/loadout_item/pocket_items/lunchbox_heart + name = "Heart Lunchbox" + item_path = /obj/item/storage/lunchbox/heart + +/datum/loadout_item/pocket_items/lunchbox_safetymoth + name = "Safety Moth Lunchbox" + item_path = /obj/item/storage/lunchbox/safetymoth + +/datum/loadout_item/pocket_items/lunchbox_amongus + name = "Suspicious Red Lunchbox" + item_path = /obj/item/storage/lunchbox/amongus diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_shoes.dm b/modular_zubbers/code/modules/loadout/categories/shoes.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_shoes.dm rename to modular_zubbers/code/modules/loadout/categories/shoes.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_suit.dm b/modular_zubbers/code/modules/loadout/categories/suit.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_suit.dm rename to modular_zubbers/code/modules/loadout/categories/suit.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_toys.dm b/modular_zubbers/code/modules/loadout/categories/toys.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_toys.dm rename to modular_zubbers/code/modules/loadout/categories/toys.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_under.dm b/modular_zubbers/code/modules/loadout/categories/under.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/loadout_datum_under.dm rename to modular_zubbers/code/modules/loadout/categories/under.dm diff --git a/modular_zubbers/code/modules/loadouts/loadout_items/~donator/donator_personal.dm b/modular_zubbers/code/modules/loadout/categories/~donator/donator_personal.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/loadout_items/~donator/donator_personal.dm rename to modular_zubbers/code/modules/loadout/categories/~donator/donator_personal.dm diff --git a/modular_zubbers/code/modules/loadouts/overrides/loadout_items/loadout_datum.dm b/modular_zubbers/code/modules/loadout/overrides/loadout_items/loadout_datum.dm similarity index 100% rename from modular_zubbers/code/modules/loadouts/overrides/loadout_items/loadout_datum.dm rename to modular_zubbers/code/modules/loadout/overrides/loadout_items/loadout_datum.dm diff --git a/tgstation.dme b/tgstation.dme index 29723ab8fa4f2..61ec8517b0597 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -8762,19 +8762,19 @@ #include "modular_zubbers\code\modules\languages\vampiric.dm" #include "modular_zubbers\code\modules\lewd_machinery\lustwish.dm" #include "modular_zubbers\code\modules\liquids\height_floors.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_glasses.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_gloves.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_heads.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_inhands.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_masks.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_neck.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_pocket.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_shoes.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_suit.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_toys.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\loadout_datum_under.dm" -#include "modular_zubbers\code\modules\loadouts\loadout_items\~donator\donator_personal.dm" -#include "modular_zubbers\code\modules\loadouts\overrides\loadout_items\loadout_datum.dm" +#include "modular_zubbers\code\modules\loadout\categories\glasses.dm" +#include "modular_zubbers\code\modules\loadout\categories\gloves.dm" +#include "modular_zubbers\code\modules\loadout\categories\heads.dm" +#include "modular_zubbers\code\modules\loadout\categories\inhands.dm" +#include "modular_zubbers\code\modules\loadout\categories\masks.dm" +#include "modular_zubbers\code\modules\loadout\categories\neck.dm" +#include "modular_zubbers\code\modules\loadout\categories\pocket.dm" +#include "modular_zubbers\code\modules\loadout\categories\shoes.dm" +#include "modular_zubbers\code\modules\loadout\categories\suit.dm" +#include "modular_zubbers\code\modules\loadout\categories\toys.dm" +#include "modular_zubbers\code\modules\loadout\categories\under.dm" +#include "modular_zubbers\code\modules\loadout\categories\~donator\donator_personal.dm" +#include "modular_zubbers\code\modules\loadout\overrides\loadout_items\loadout_datum.dm" #include "modular_zubbers\code\modules\lunchbox\code\lunchbox.dm" #include "modular_zubbers\code\modules\mapping\access_helpers.dm" #include "modular_zubbers\code\modules\mapping\limastation\areas.dm" From ad153174a25a87506c0ad2326600244c5154b90f Mon Sep 17 00:00:00 2001 From: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com> Date: Tue, 2 Jul 2024 03:56:28 -0600 Subject: [PATCH 3/3] Loadout Fixes (#28540) * wee * I am so smart * It werks --------- Co-authored-by: Waterpig Co-authored-by: Waterpig <49160555+Majkl-J@users.noreply.github.com> --- code/modules/loadout/loadout_categories.dm | 6 +- code/modules/loadout/loadout_items.dm | 13 ++- code/modules/loadout/loadout_menu.dm | 25 +++-- .../code/modules/loadout/categories/gloves.dm | 2 +- .../code/modules/loadout/categories/toys.dm | 1 + .../tgui/interfaces/PreferencesMenu/data.ts | 2 + .../PreferencesMenu/loadout/ItemDisplay.tsx | 100 +++++++++++++++++- .../PreferencesMenu/loadout/base.ts | 8 ++ 8 files changed, 139 insertions(+), 18 deletions(-) diff --git a/code/modules/loadout/loadout_categories.dm b/code/modules/loadout/loadout_categories.dm index ae9aca7e9146f..c64a564b2ecb6 100644 --- a/code/modules/loadout/loadout_categories.dm +++ b/code/modules/loadout/loadout_categories.dm @@ -53,17 +53,13 @@ return all_items /// Returns a list of all /datum/loadout_items in this category, formatted for UI use. Only ran once. -/datum/loadout_category/proc/items_to_ui_data(client/user) as /list // SKYRAT EDIT CHANGE - Added user poaram +/datum/loadout_category/proc/items_to_ui_data() as /list if(!length(associated_items)) return list() var/list/formatted_list = list() for(var/datum/loadout_item/item as anything in associated_items) - // SKYRAT EDIT ADDITION - if(item.ckeywhitelist && !(user?.ckey in item.ckeywhitelist)) - continue - // SKYRAT EDIT END var/list/item_data = item.to_ui_data() UNTYPED_LIST_ADD(formatted_list, item_data) diff --git a/code/modules/loadout/loadout_items.dm b/code/modules/loadout/loadout_items.dm index e02d15e7a44f3..5ad95840d8278 100644 --- a/code/modules/loadout/loadout_items.dm +++ b/code/modules/loadout/loadout_items.dm @@ -42,7 +42,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) var/can_be_greyscale = FALSE /// Whether this item can be renamed. /// I recommend you apply this sparingly becuase it certainly can go wrong (or get reset / overridden easily) - var/can_be_named = FALSE + var/can_be_named = TRUE // SKYRAT EDIT /// Whether this item can be reskinned. /// Only works if the item has a "unique reskin" list set. var/can_be_reskinned = FALSE @@ -315,6 +315,14 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) formatted_item["reskins"] = get_reskin_options() formatted_item["icon"] = ui_icon formatted_item["icon_state"] = ui_icon_state + + // SKYRAT EDIT BEGIN - Extra loadout stuff + formatted_item["ckey_whitelist"] = ckeywhitelist + formatted_item["donator_only"] = donator_only + formatted_item["restricted_roles"] = restricted_roles + formatted_item["blacklisted_roles"] = restricted_roles + // SKYRAT EDIT END + return formatted_item /** @@ -342,6 +350,9 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) if(donator_only) displayed_text += "Donator only" + if(ckeywhitelist) + displayed_text += "Unique" + if(restricted_roles || blacklisted_roles) displayed_text += "Role restricted" diff --git a/code/modules/loadout/loadout_menu.dm b/code/modules/loadout/loadout_menu.dm index f01d4215c69fe..0fdbe81ee81f2 100644 --- a/code/modules/loadout/loadout_menu.dm +++ b/code/modules/loadout/loadout_menu.dm @@ -73,15 +73,15 @@ continue if(!item.category.handle_duplicate_entires(src, item, selected_item, loadout_datums)) return - // SKYRAT EDIT ADDITION - if(item.ckeywhitelist && !(preferences?.parent?.ckey in item.ckeywhitelist)) - to_chat(preferences.parent, span_warning("You cannot select this item!")) - return + // SKYRAT EDIT ADDITION + if(!isnull(selected_item.ckeywhitelist) && !(preferences?.parent?.ckey in selected_item.ckeywhitelist)) + to_chat(preferences.parent, span_warning("You cannot select this item!")) + return - if(item.donator_only && !GLOB.donator_list[preferences?.parent?.ckey]) - to_chat(preferences.parent, span_warning("That item is for donators only.")) - return - // SKYRAT EDIT END + if(!isnull(selected_item.donator_only) && !GLOB.donator_list[preferences?.parent?.ckey]) + to_chat(preferences.parent, span_warning("This item is for donators only.")) + return + // SKYRAT EDIT END LAZYSET(loadout, selected_item.item_path, list()) preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout) @@ -111,6 +111,11 @@ /datum/preference_middleware/loadout/get_ui_static_data(mob/user) var/list/data = list() data["loadout_preview_view"] = preferences.character_preview_view.assigned_map + // SKYRAT EDIT START - EXPANDED LOADOUT + data["ckey"] = user.ckey + if(SSplayer_ranks.is_donator(user.client)) + data["is_donator"] = TRUE + // SKYRAT EDIT END return data /datum/preference_middleware/loadout/get_constant_data() @@ -121,8 +126,8 @@ "name" = category.category_name, "category_icon" = category.category_ui_icon, "category_info" = category.category_info, - "contents" = category.items_to_ui_data(preferences?.parent), - ) // SKYRAT EDIT CHANGE - items_to_ui_data(preferences?.parent) + "contents" = category.items_to_ui_data(), + ) UNTYPED_LIST_ADD(loadout_tabs, cat_data) data["loadout_tabs"] = loadout_tabs diff --git a/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm b/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm index 190c7a1db44e3..2de958137c9e4 100644 --- a/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/gloves.dm @@ -60,7 +60,7 @@ /datum/loadout_item/gloves/yellow name = "Yellow Gloves" item_path = /obj/item/clothing/gloves/color/ffyellow - additional_displayed_text = list("NON-INSULATING - This item is purely cosmetic and provide no shock insulation.") + additional_displayed_text = list("NON-INSULATING") /datum/loadout_item/gloves/white name = "White Gloves" diff --git a/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm b/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm index e6315cda2dcc0..2177efa0faca0 100644 --- a/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm +++ b/modular_skyrat/master_files/code/modules/loadout/categories/toys.dm @@ -6,6 +6,7 @@ /datum/loadout_item/toys abstract_type = /datum/loadout_item/toys + can_be_named = TRUE /datum/loadout_item/toys/bee name = "Bee Plushie" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts index 5e54245eaf40c..a9471b22d4446 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts @@ -234,6 +234,8 @@ export type PreferencesMenuData = { quirks_balance: number; positive_quirk_count: number; species_restricted_jobs?: string[]; + ckey: string; + is_donator: BooleanLike; // SKYRAT EDIT END keybindings: Record; overflow_role: string; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx index 11b20b0097963..a7a3f9b5e0146 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx @@ -84,6 +84,20 @@ export const ItemDisplay = (props: { {info} ))} + { + // SKYRAT EDIT START - EXPANDED LOADOUT + + {ShouldDisplayJobRestriction(item) && ItemJobRestriction(item)} + {ShouldDisplayPlayerRestriction(item) && + ItemPlayerRestriction(item)} + + + /* SKYRAT EDIT END */ + } )} @@ -94,9 +108,10 @@ export const ItemDisplay = (props: { const ItemListDisplay = (props: { items: LoadoutItem[] }) => { const { data } = useBackend(); const { loadout_list } = data.character_preferences.misc; + const itemList = FilterItemList(props.items); // SKYRAT EDIT - EXPANDED LOADOUT return ( - {props.items.map((item) => ( + {itemList.map((item /* SKYRAT EDIT : {props.items.map((item) => (*/) => ( { ); }; +// SKYRAT EDIT START - EXPANDED LOADOUT +const FilterItemList = (items: LoadoutItem[]) => { + const { data } = useBackend(); + const { is_donator } = data; + const ckey = data.ckey; + + return items.filter((item: LoadoutItem) => { + if (item.ckey_whitelist && item.ckey_whitelist.indexOf(ckey) === -1) { + return false; + } + if (item.donator_only && !is_donator) { + return false; + } + return true; + }); +}; +const ShouldDisplayPlayerRestriction = (item: LoadoutItem) => { + if (item.ckey_whitelist || item.restricted_species) { + return true; + } + + return false; +}; + +const ShouldDisplayJobRestriction = (item: LoadoutItem) => { + if (item.restricted_roles || item.blacklisted_roles) { + return true; + } + + return false; +}; + +const ItemPlayerRestriction = (item: LoadoutItem) => { + let restrictions: string[] = []; + + if (item.ckey_whitelist) { + restrictions.push('CKEY Whitelist: ' + item.ckey_whitelist.join(', ')); + } + + if (item.restricted_species) { + restrictions.push( + 'Species Whitelist: ' + item.restricted_species.join(', '), + ); + } + + const tooltip = restrictions.join(', '); + + return ( +