From 80e17b42ca77f82e8191a80ee7acbee79e36f92f Mon Sep 17 00:00:00 2001 From: Geeves Date: Sat, 6 Jan 2024 14:43:24 +0200 Subject: [PATCH] Accessory Loadout Options (#18082) * Accessory Loadout Options * more * throw this on top * fluffy review * nope * more stuff * default log file * fix order? * indentation fix --- aurorastation.dme | 1 + code/__defines/_macros.dm | 1 + code/__defines/misc.dm | 8 ++ code/_helpers/logging/loadout.dm | 4 + code/controllers/configuration.dm | 2 + code/controllers/subsystems/job.dm | 84 +++++++++++++------ .../preference_setup/loadout/gear_tweaks.dm | 19 +++++ .../loadout/items/xeno/vaurca.dm | 2 + .../preference_setup/loadout/loadout.dm | 20 ++++- config/example/logging.json | 1 + config/example/logging_files.json | 1 + .../geeves-loadout_accessorizing.yml | 8 ++ 12 files changed, 121 insertions(+), 30 deletions(-) create mode 100644 code/_helpers/logging/loadout.dm create mode 100644 html/changelogs/geeves-loadout_accessorizing.yml diff --git a/aurorastation.dme b/aurorastation.dme index 51e36625c63..f562a89165f 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -179,6 +179,7 @@ #include "code\_helpers\logging\attack.dm" #include "code\_helpers\logging\debug.dm" #include "code\_helpers\logging\game.dm" +#include "code\_helpers\logging\loadout.dm" #include "code\_helpers\logging\manifest.dm" #include "code\_helpers\logging\paper.dm" #include "code\_helpers\logging\pda.dm" diff --git a/code/__defines/_macros.dm b/code/__defines/_macros.dm index e68aebaea6b..37f78355a80 100644 --- a/code/__defines/_macros.dm +++ b/code/__defines/_macros.dm @@ -115,6 +115,7 @@ #define isclient(A) istype(A, /client) #define isclothing(A) istype(A, /obj/item/clothing) +#define isaccessory(A) istype(A, /obj/item/clothing/accessory) /// Projectile helpers #define isprojectile(A) istype(A, /obj/item/projectile) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 0e715b6356c..6fa634b27a7 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -549,3 +549,11 @@ example: /// Gyrotron power usage modifier. #define GYRO_POWER 25000 + +// Accessory Slot Gear Tweak Settings +/// Spawns attached to the uniform +#define GEAR_TWEAK_ACCESSORY_SLOT_UNDER "Uniform" +/// Spawns attached to the suit slot item +#define GEAR_TWEAK_ACCESSORY_SLOT_SUIT "Suit" +/// Spawns standalone in the suit slot +#define GEAR_TWEAK_ACCESSORY_SLOT_SUIT_STANDALONE "Standalone Suit" diff --git a/code/_helpers/logging/loadout.dm b/code/_helpers/logging/loadout.dm new file mode 100644 index 00000000000..e1d9bf9fdd6 --- /dev/null +++ b/code/_helpers/logging/loadout.dm @@ -0,0 +1,4 @@ +/// Logging for loadout things +/proc/log_loadout(text) + if (GLOB.config.logsettings["log_loadout"]) + WRITE_LOG(GLOB.config.logfiles["world_loadout_log"], "LOADOUT: [text]") diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 5e4fcf94f79..b37cf4aed51 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -51,6 +51,7 @@ GLOBAL_LIST_EMPTY(gamemode_cache) "log_tools" = FALSE, // Tools "log_manifest" = TRUE, // Manifest "log_asset" = FALSE, // log asset caching + "log_loadout" = TRUE, // Loadout /*#### SUBSYSTEMS ####*/ @@ -105,6 +106,7 @@ GLOBAL_LIST_EMPTY(gamemode_cache) "harddel_log" = "harddel.log", "world_paper_log" = "world_paper.log", "world_manifest_log" = "world_manifest.log", + "world_loadout_log" = "world_loadout.log", /*#### SUBSYSTEMS ####*/ diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm index 085a4d93ed7..9cc29c476e9 100644 --- a/code/controllers/subsystems/job.dm +++ b/code/controllers/subsystems/job.dm @@ -670,14 +670,14 @@ SUBSYSTEM_DEF(jobs) // H, job, and prefs MUST be supplied and not null. // leftovers, storage, custom_equip_slots can be passed if their return values are required (proc mutates passed list), or ignored if not required. /datum/controller/subsystem/jobs/proc/EquipCustom(mob/living/carbon/human/H, datum/job/job, datum/preferences/prefs, list/leftovers = null, list/storage = null, list/custom_equip_slots = list()) - Debug("EC/([H]): Entry.") + log_loadout("EC/([H]): Entry.") if (!istype(H) || !job) - Debug("EC/([H]): Abort: invalid arguments.") + log_loadout("EC/([H]): Abort: invalid arguments.") return FALSE switch (job.title) if ("AI", "Cyborg") - Debug("EC/([H]): Abort: synthetic.") + log_loadout("EC/([H]): Abort: synthetic.") return FALSE for(var/thing in prefs.gear) @@ -698,23 +698,29 @@ SUBSYSTEM_DEF(jobs) to_chat(H, SPAN_WARNING(cant_spawn_reason)) continue + // we want to handle spawning accessories after all the other clothing items have been spawned in + var/list/spawn_data = G.get_spawn_item_data(H, metadata, H) + if(ispath(spawn_data[1], /obj/item/clothing/accessory)) + leftovers += thing + continue + if(G.slot && !(G.slot in custom_equip_slots)) // This is a miserable way to fix the loadout overwrite bug, but the alternative requires // adding an arg to a bunch of different procs. Will look into it after this merge. ~ Z var/obj/item/CI = G.spawn_item(null,metadata, H) if (H.equip_to_slot_or_del(CI, G.slot)) - to_chat(H, "Equipping you with [thing]!") + to_chat(H, SPAN_NOTICE("Equipping you with [thing]!")) if(G.slot != slot_tie) custom_equip_slots += G.slot - Debug("EC/([H]): Equipped [CI] successfully.") + log_loadout("EC/([H]): Equipped [CI] successfully.") else if (leftovers) leftovers += thing - Debug("EC/([H]): Unable to equip [thing]; sending to overflow.") + log_loadout("EC/([H]): Unable to equip [thing]; sending to overflow.") else if (storage) storage += thing - Debug("EC/([H]): Unable to equip [thing]; sending to storage.") + log_loadout("EC/([H]): Unable to equip [thing]; sending to storage.") - Debug("EC/([H]): Complete.") + log_loadout("EC/([H]): Complete.") return TRUE // Attempts to equip custom items that failed to equip in EquipCustom. @@ -722,7 +728,7 @@ SUBSYSTEM_DEF(jobs) // H and prefs must not be null. /datum/controller/subsystem/jobs/proc/EquipCustomDeferred(mob/living/carbon/human/H, datum/preferences/prefs, list/items, list/used_slots) . = list() - Debug("ECD/([H]): Entry.") + log_loadout("ECD/([H]): Entry.") for (var/thing in items) var/datum/gear/G = gear_datums[thing] @@ -735,25 +741,51 @@ SUBSYSTEM_DEF(jobs) metadata = gear_test else metadata = list() + var/obj/item/CI = G.spawn_item(H, metadata, H) - if (H.equip_to_slot_or_del(CI, G.slot)) - to_chat(H, "Equipping you with [thing]!") - used_slots += G.slot - Debug("ECD/([H]): Equipped [thing] successfully.") + var/equip_slot = G.slot + var/handled_accessory = FALSE - else - . += thing - Debug("ECD/([H]): Unable to equip [thing]; dumping into overflow.") + if(isaccessory(CI)) + var/datum/gear_tweak/accessory_slot/accessory_slot = locate(/datum/gear_tweak/accessory_slot) in G.gear_tweaks + if(accessory_slot && metadata["[accessory_slot]"]) + var/selected_slot = metadata["[accessory_slot]"] + switch(selected_slot) + if(GEAR_TWEAK_ACCESSORY_SLOT_UNDER) + if(isclothing(H.w_uniform)) + var/obj/item/clothing/worn_uniform = H.w_uniform + if(worn_uniform.can_attach_accessory(CI)) + to_chat(H, SPAN_NOTICE("Attaching \the [CI] to your uniform!")) + worn_uniform.attach_accessory(H, CI) + handled_accessory = TRUE + if(GEAR_TWEAK_ACCESSORY_SLOT_SUIT) + if(isclothing(H.wear_suit)) + var/obj/item/clothing/worn_suit = H.wear_suit + if(worn_suit.can_attach_accessory(CI)) + to_chat(H, SPAN_NOTICE("Attaching \the [CI] to your suit!")) + worn_suit.attach_accessory(H, CI) + handled_accessory = TRUE + if(GEAR_TWEAK_ACCESSORY_SLOT_SUIT_STANDALONE) + equip_slot = slot_wear_suit - Debug("ECD/([H]): Complete.") + if(!handled_accessory) + if (H.equip_to_slot_or_del(CI, equip_slot)) + to_chat(H, SPAN_NOTICE("Equipping you with [thing]!")) + used_slots += equip_slot + log_loadout("ECD/([H]): Equipped [thing] successfully.") + else + . += thing + log_loadout("ECD/([H]): Unable to equip [thing]; dumping into overflow.") + + log_loadout("ECD/([H]): Complete.") // Attempts to place everything in items into a storage object located on H, deleting them if they're unable to be inserted. // H and prefs must not be null. // Returns nothing. /datum/controller/subsystem/jobs/proc/EquipItemsStorage(mob/living/carbon/human/H, datum/preferences/prefs, list/items) - Debug("EIS/([H]): Entry.") + log_loadout("EIS/([H]): Entry.") if (LAZYLEN(items)) - Debug("EIS/([H]): [items.len] items.") + log_loadout("EIS/([H]): [items.len] items.") var/obj/item/storage/B = locate() in H if (B) for (var/thing in items) @@ -766,13 +798,13 @@ SUBSYSTEM_DEF(jobs) else metadata = list() G.spawn_item(B, metadata, H) - Debug("EIS/([H]): placed [thing] in [B].") + log_loadout("EIS/([H]): placed [thing] in [B].") else to_chat(H, "Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.") - Debug("EIS/([H]): unable to equip; no storage.") + log_loadout("EIS/([H]): unable to equip; no storage.") - Debug("EIS/([H]): Complete.") + log_loadout("EIS/([H]): Complete.") /datum/controller/subsystem/jobs/proc/get_roundstart_spawnpoint(var/rank) var/list/loc_list = list() @@ -803,16 +835,16 @@ SUBSYSTEM_DEF(jobs) /datum/controller/subsystem/jobs/proc/EquipAugments(mob/living/carbon/human/H, datum/preferences/prefs) - Debug("EA/([H]): Entry.") + log_loadout("EA/([H]): Entry.") if(!istype(H)) - Debug("EA/([H]): Abort: invalid arguments.") + log_loadout("EA/([H]): Abort: invalid arguments.") return FALSE var/datum/job/rank = GetJob(H.mind.assigned_role) switch (rank.title) if ("AI", "Cyborg") - Debug("EA/([H]): Abort: synthetic.") + log_loadout("EA/([H]): Abort: synthetic.") return FALSE for(var/thing in prefs.gear) @@ -839,7 +871,7 @@ SUBSYSTEM_DEF(jobs) A.replaced(H, affected) H.update_body() - Debug("EA/([H]): Complete.") + log_loadout("EA/([H]): Complete.") return TRUE /proc/show_location_blurb(client/C, duration) diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 35a4690dfca..2381e06b6f9 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -349,3 +349,22 @@ Paper Data BT.id = metadata[1] BT.distance = metadata[2] BT.search_interval = metadata[3] SECONDS + + +// Accessory Slot Settings +var/datum/gear_tweak/accessory_slot/gear_tweak_accessory_slot = new() + +/datum/gear_tweak/accessory_slot + var/static/list/accessory_slots = list(GEAR_TWEAK_ACCESSORY_SLOT_UNDER, GEAR_TWEAK_ACCESSORY_SLOT_SUIT, GEAR_TWEAK_ACCESSORY_SLOT_SUIT_STANDALONE) + +/datum/gear_tweak/accessory_slot/get_contents(var/metadata) + return "Spawn Slot: [metadata]" + +/datum/gear_tweak/accessory_slot/get_default() + return GEAR_TWEAK_ACCESSORY_SLOT_UNDER + +/datum/gear_tweak/accessory_slot/get_metadata(var/user, var/metadata) + return tgui_input_list(user, "Choose a type.", "Character Preference", accessory_slots, metadata) + +/datum/gear_tweak/accessory_slot/tweak_item(var/obj/item/clothing/accessory/buddytag/BT, var/list/metadata, var/mob/living/carbon/human/H) + return diff --git a/code/modules/client/preference_setup/loadout/items/xeno/vaurca.dm b/code/modules/client/preference_setup/loadout/items/xeno/vaurca.dm index 83386fb97a8..8e2bf4d85dc 100644 --- a/code/modules/client/preference_setup/loadout/items/xeno/vaurca.dm +++ b/code/modules/client/preference_setup/loadout/items/xeno/vaurca.dm @@ -44,6 +44,7 @@ display_name = "tunnel cloak (recolourable)" path = /obj/item/storage/backpack/cloak cost = 1 + slot = slot_back whitelisted = list(SPECIES_VAURCA_WORKER, SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_BULWARK) sort_category = "Xenowear - Vaurca" flags = GEAR_HAS_NAME_SELECTION | GEAR_HAS_DESC_SELECTION | GEAR_HAS_COLOR_SELECTION @@ -52,6 +53,7 @@ display_name = "tunnel cloak selection" path = /obj/item/storage/backpack/cloak cost = 1 + slot = slot_back whitelisted = list(SPECIES_VAURCA_WORKER, SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_BULWARK) sort_category = "Xenowear - Vaurca" flags = GEAR_HAS_DESC_SELECTION diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 4708680ad02..22b3953350d 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -438,6 +438,8 @@ var/list/gear_datums = list() gear_tweaks += list(gear_tweak_free_desc) if(flags & GEAR_HAS_COLOR_ROTATION_SELECTION) gear_tweaks += list(gear_tweak_color_rotation) + if(ispath(path, /obj/item/clothing/accessory)) + gear_tweaks += list(gear_tweak_accessory_slot) /datum/gear_data var/path @@ -472,24 +474,34 @@ var/list/gear_datums = list() return "You cannot spawn with the [initial(spawning_item.name)] with your current origin!" return null -/datum/gear/proc/spawn_item(var/location, var/metadata, var/mob/living/carbon/human/H) +/// Returns a list of spawn item data. The first entry is the path, the second is the location +/datum/gear/proc/get_spawn_item_data(var/location, var/metadata, var/mob/living/carbon/human/H) var/datum/gear_data/gd = new(path, location, faction) for(var/datum/gear_tweak/gt in gear_tweaks) if(metadata["[gt]"]) gt.tweak_gear_data(metadata["[gt]"], gd, H) else gt.tweak_gear_data(gt.get_default(), gd, H) - if(ispath(gd.path, /obj/item/organ/external)) - var/obj/item/organ/external/external_aug = gd.path + return list(gd.path, gd.location) + +/datum/gear/proc/spawn_item(var/location, var/metadata, var/mob/living/carbon/human/H) + var/list/spawn_item_data = get_spawn_item_data(location, metadata, H) + var/spawn_path = spawn_item_data[1] + var/spawn_location = spawn_item_data[2] + + if(ispath(spawn_path, /obj/item/organ/external)) + var/obj/item/organ/external/external_aug = spawn_path var/obj/item/organ/external/replaced_limb = H.get_organ(initial(external_aug.limb_name)) replaced_limb.droplimb(TRUE, DROPLIMB_EDGE, FALSE) qdel(replaced_limb) - var/item = new gd.path(gd.location) + + var/item = new spawn_path(spawn_location) for(var/datum/gear_tweak/gt in gear_tweaks) if(metadata["[gt]"]) gt.tweak_item(item, metadata["[gt]"], H) else gt.tweak_item(item, gt.get_default(), H) + return item /datum/gear/proc/spawn_random(var/location) diff --git a/config/example/logging.json b/config/example/logging.json index f21fab777b1..7d9349be9e5 100644 --- a/config/example/logging.json +++ b/config/example/logging.json @@ -24,6 +24,7 @@ "log_telecomms":0, "log_speech_indicators":0, "log_tools":0, + "log_loadout":1, "log_manifest":1, "log_subsystems":1, "log_subsystems_chemistry":1, diff --git a/config/example/logging_files.json b/config/example/logging_files.json index d6bd0146062..10159b7f765 100644 --- a/config/example/logging_files.json +++ b/config/example/logging_files.json @@ -25,6 +25,7 @@ "harddel_log":"harddel.log", "world_paper_log":"world_paper.log", "world_manifest_log":"world_manifest.log", + "world_loadout_log":"world_loadout.log", "world_subsystems_log":"subsystems/world_subsystems.log", "world_subsystems_chemistry_log":"subsystems/chemistry.log", "world_subsystems_atlas_log":"subsystems/atlas.log", diff --git a/html/changelogs/geeves-loadout_accessorizing.yml b/html/changelogs/geeves-loadout_accessorizing.yml new file mode 100644 index 00000000000..287ddc27f03 --- /dev/null +++ b/html/changelogs/geeves-loadout_accessorizing.yml @@ -0,0 +1,8 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "You can now choose whether your loadout accessory spawns on your uniform, your suit, or gets put into the suit slot as a standalone item, such as with capes and ponchos." + - bugfix: "Fixed only one accessory being visible at a time in the loadout preview." + - bugfix: "Fixed vaurca tunnel cloaks not being visible in the loadout preview." \ No newline at end of file