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