diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm
index 6f1740cc9f..7fe5fa4876 100644
--- a/code/__DEFINES/loadout.dm
+++ b/code/__DEFINES/loadout.dm
@@ -67,3 +67,13 @@
#define LOADOUT_LIMB_AMPUTATED "Amputated"
#define LOADOUT_LIMBS list(LOADOUT_LIMB_NORMAL,LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though
+
+//loadout saving/loading specific defines
+#define MAXIMUM_LOADOUT_SAVES 5
+#define LOADOUT_ITEM "loadout_item"
+#define LOADOUT_COLOR "loadout_color"
+
+//loadout item flags
+#define LOADOUT_CAN_NAME (1<<0) //renaming items
+#define LOADOUT_CAN_DESCRIPTION (1<<1) //adding a custom description to items
+#define LOADOUT_CAN_COLOR_POLYCHROMIC (1<<2)
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 0f936bdeff..4963e33cc3 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -670,11 +670,12 @@ SUBSYSTEM_DEF(job)
var/mob/the_mob = N
if(!the_mob)
the_mob = M // cause this doesn't get assigned if player is a latejoiner
- if(the_mob.client && the_mob.client.prefs && (the_mob.client.prefs.chosen_gear && the_mob.client.prefs.chosen_gear.len))
+ var/list/chosen_gear = the_mob.client.prefs.loadout_data["SAVE_[the_mob.client.prefs.loadout_slot]"]
+ if(the_mob.client && the_mob.client.prefs && (chosen_gear && chosen_gear.len))
if(!ishuman(M))//no silicons allowed
return
- for(var/i in the_mob.client.prefs.chosen_gear)
- var/datum/gear/G = i
+ for(var/i in chosen_gear)
+ var/datum/gear/G = istext(i[LOADOUT_ITEM]) ? text2path(i[LOADOUT_ITEM]) : i[LOADOUT_ITEM]
G = GLOB.loadout_items[initial(G.category)][initial(G.subcategory)][initial(G.name)]
if(!G)
continue
@@ -690,6 +691,19 @@ SUBSYSTEM_DEF(job)
if(!permitted)
continue
var/obj/item/I = new G.path
+ if(I && length(i[LOADOUT_COLOR])) //handle loadout colors
+ //handle polychromic items
+ if((G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) && length(G.loadout_initial_colors))
+ var/datum/element/polychromic/polychromic = I.comp_lookup["item_worn_overlays"] //stupid way to do it but GetElement does not work for this
+ if(polychromic && istype(polychromic))
+ var/list/polychromic_entry = polychromic.colors_by_atom[I]
+ if(polychromic_entry)
+ polychromic.colors_by_atom[I] = i[LOADOUT_COLOR]
+ I.update_icon()
+ else
+ //handle non-polychromic items (they only have one color)
+ I.add_atom_colour(i[LOADOUT_COLOR][1], FIXED_COLOUR_PRIORITY)
+ I.update_icon()
if(!M.equip_to_slot_if_possible(I, G.slot, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
if(iscarbon(M))
var/mob/living/carbon/C = M
diff --git a/code/datums/elements/polychromic.dm b/code/datums/elements/polychromic.dm
index 7ae0d04b05..600bf9250e 100644
--- a/code/datums/elements/polychromic.dm
+++ b/code/datums/elements/polychromic.dm
@@ -170,7 +170,7 @@
if(istype(source,/obj/item/clothing/suit/hooded)) //so how come it be like this, where toggleable headslots are named separately (helmet/hood) anyways?
var/obj/item/clothing/suit/hooded/sourcesuit = source
H = sourcesuit.hood
- else if(istype(source,/obj/item/clothing/suit/space/hardsuit))
+ else if(istype(source,/obj/item/clothing/suit/space/hardsuit))
var/obj/item/clothing/suit/space/hardsuit/sourcesuit = source
H = sourcesuit.helmet
else
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 16d6ca351d..2de91f172d 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -179,7 +179,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
///loadout stuff
var/gear_points = 10
var/list/gear_categories
- var/list/chosen_gear = list()
+ var/list/loadout_data = list()
+ var/loadout_slot = 1 //goes from 1 to MAXIMUM_LOADOUT_SAVES
var/gear_category
var/gear_subcategory
@@ -806,6 +807,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
"
if(3)
+ //calculate your gear points from the chosen item
+ gear_points = CONFIG_GET(number/initial_gear_points)
+ var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"]
+ if(chosen_gear)
+ for(var/loadout_item in chosen_gear)
+ var/loadout_item_path = loadout_item[LOADOUT_ITEM]
+ if(loadout_item_path)
+ var/datum/gear/loadout_gear = text2path(loadout_item_path)
+ if(loadout_gear)
+ gear_points -= initial(loadout_gear.cost)
+ else
+ chosen_gear = list()
+
dat += "
| [name] | " + dat += "|||
| [name][extra_color_data] | " dat += "[gear.cost] | " if(islist(gear.restricted_roles)) if(gear.restricted_roles.len) @@ -2609,8 +2635,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) current_tab = text2num(href_list["tab"]) if(href_list["preference"] == "gear") if(href_list["clear_loadout"]) - chosen_gear = list() - gear_points = CONFIG_GET(number/initial_gear_points) + loadout_data["SAVE_[loadout_slot]"] = list() save_preferences() if(href_list["select_category"]) gear_category = html_decode(href_list["select_category"]) @@ -2623,10 +2648,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!G) return var/toggle = text2num(href_list["toggle_gear"]) - if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear) - chosen_gear -= G.type - gear_points += initial(G.cost) - else if(toggle && (!(is_type_in_ref_list(G, chosen_gear)))) + if(!toggle && has_loadout_gear(loadout_slot, "[G.type]"))//toggling off and the item effectively is in chosen gear) + remove_gear_from_loadout(loadout_slot, "[G.type]") + else if(toggle && !(has_loadout_gear(loadout_slot, "[G.type]"))) if(!is_loadout_slot_available(G.category)) to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!") return @@ -2634,8 +2658,46 @@ GLOBAL_LIST_EMPTY(preferences_datums) to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") return if(gear_points >= initial(G.cost)) - chosen_gear += G.type - gear_points -= initial(G.cost) + var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]") + if(length(G.loadout_initial_colors)) + new_loadout_data[LOADOUT_COLOR] = G.loadout_initial_colors + else + new_loadout_data[LOADOUT_COLOR] = list("#FFFFFF") + if(loadout_data["SAVE_[loadout_slot]"]) + loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) //double packed because it does the union of the CONTENTS of the lists + else + loadout_data["SAVE_[loadout_slot]"] = list(new_loadout_data) //double packed because you somehow had no save slot in your loadout? + if(href_list["loadout_color"]) + var/name = html_decode(href_list["loadout_gear_name"]) + var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] + if(!G) + return + var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") + if(!user_gear) + return + if(!length(user_gear[LOADOUT_COLOR])) + user_gear[LOADOUT_COLOR] = list("#FFFFFF") + var/current_color = user_gear[LOADOUT_COLOR][1] + var/new_color = input(user, "Polychromic options", "Choose Color", current_color) as color|null + user_gear[LOADOUT_COLOR][1] = sanitize_hexcolor(new_color, 6, TRUE, current_color) + if(href_list["loadout_color_polychromic"]) + var/name = html_decode(href_list["loadout_gear_name"]) + var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] + if(!G) + return + var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") + if(!user_gear) + return + var/list/color_options = list() + for(var/i=1, i<=length(G.loadout_initial_colors), i++) + color_options += "Color [i]" + var/color_to_change = input(user, "Polychromic options", "Recolor [name]") as null|anything in color_options + if(color_to_change) + var/color_index = text2num(copytext(color_to_change, 7)) + var/current_color = user_gear[LOADOUT_COLOR][color_index] + var/new_color = input(user, "Polychromic options", "Choose [color_to_change] Color", current_color) as color|null + if(new_color) + user_gear[LOADOUT_COLOR][color_index] = sanitize_hexcolor(new_color, 6, TRUE, current_color) ShowChoices(user) return 1 @@ -2853,8 +2915,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) /datum/preferences/proc/is_loadout_slot_available(slot) var/list/L LAZYINITLIST(L) - for(var/i in chosen_gear) - var/datum/gear/G = i + for(var/i in loadout_data["SAVE_[loadout_slot]"]) + var/datum/gear/G = i[LOADOUT_ITEM] var/occupied_slots = L[initial(G.category)] ? L[initial(G.category)] + 1 : 1 LAZYSET(L, initial(G.category), occupied_slots) switch(slot) @@ -2868,6 +2930,18 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(L[slot] < DEFAULT_SLOT_AMT) return TRUE +/datum/preferences/proc/has_loadout_gear(save_slot, gear_type) + var/list/gear_list = loadout_data["SAVE_[save_slot]"] + for(var/loadout_gear in gear_list) + if(loadout_gear[LOADOUT_ITEM] == gear_type) + return loadout_gear + return FALSE + +/datum/preferences/proc/remove_gear_from_loadout(save_slot, gear_type) + var/find_gear = has_loadout_gear(save_slot, gear_type) + if(find_gear) + loadout_data["SAVE_[save_slot]"] -= list(find_gear) + #undef DEFAULT_SLOT_AMT #undef HANDS_SLOT_AMT #undef BACKPACK_SLOT_AMT diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index acc24b13bd..86f7622a93 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 46 +#define SAVEFILE_VERSION_MAX 47 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -262,6 +262,29 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["color_scheme"] = OLD_CHARACTER_COLORING //advanced is off by default + if(current_version < 47) //loadout save gets changed to json + var/text_to_load + S["loadout"] >> text_to_load + var/list/saved_loadout_paths = splittext(text_to_load, "|") + //MAXIMUM_LOADOUT_SAVES save slots per loadout now + for(var/i=1, i<= MAXIMUM_LOADOUT_SAVES, i++) + loadout_data["SAVE_[i]"] = list() + for(var/some_gear_item in saved_loadout_paths) + if(!ispath(text2path(some_gear_item))) + message_admins("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path") + continue + var/datum/gear/gear_item = text2path(some_gear_item) + if(!(initial(gear_item.loadout_flags) & LOADOUT_CAN_COLOR_POLYCHROMIC)) + loadout_data["SAVE_1"] += list(list(LOADOUT_ITEM = some_gear_item)) //for the migration we put their old save into the first save slot, which is loaded by default! + else + //the same but we setup some new polychromic data (you can't get the initial value for a list so we have to do this horrible thing here) + var/datum/gear/temporary_gear_item = new gear_item + loadout_data["SAVE_1"] += list(list(LOADOUT_ITEM = some_gear_item, LOADOUT_COLOR = temporary_gear_item.loadout_initial_colors)) + qdel(temporary_gear_item) + //it's double packed into a list because += will union the two lists contents + + S["loadout"] = safe_json_encode(loadout_data) + /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) return @@ -711,20 +734,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car var/list/json_from_file = json_decode(file2text(char_vr_path)) if(json_from_file) belly_prefs = json_from_file["belly_prefs"] + //gear loadout - var/text_to_load - S["loadout"] >> text_to_load - var/list/saved_loadout_paths = splittext(text_to_load, "|") - chosen_gear = list() - gear_points = CONFIG_GET(number/initial_gear_points) - for(var/i in saved_loadout_paths) - var/datum/gear/path = text2path(i) - if(path) - var/init_cost = initial(path.cost) - if(init_cost > gear_points) - continue - chosen_gear += path - gear_points -= init_cost + loadout_data = safe_json_decode(S["loadout"]) //try to fix any outdated data if necessary //preference updating will handle saving the updated data for us. @@ -1058,11 +1070,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //gear loadout - if(chosen_gear.len) - var/text_to_save = chosen_gear.Join("|") - S["loadout"] << text_to_save + if(length(loadout_data)) + S["loadout"] << safe_json_encode(loadout_data) else - S["loadout"] << "" //empty string to reset the value + S["loadout"] << safe_json_encode(list()) cit_character_pref_save(S) diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm index 4a21fb41fd..d58dda7f7d 100644 --- a/modular_citadel/code/modules/client/loadout/__donator.dm +++ b/modular_citadel/code/modules/client/loadout/__donator.dm @@ -287,6 +287,8 @@ slot = SLOT_IN_BACKPACK path = /obj/item/clothing/neck/cloak/polychromic/polyce ckeywhitelist = list("worksbythesea", "blakeryan") + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#808080", "#8CC6FF", "#FF3535") /datum/gear/donator/ssk name = "Stun Sword Kit" diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm index 0ebfa060f2..2a7b77bd47 100644 --- a/modular_citadel/code/modules/client/loadout/_loadout.dm +++ b/modular_citadel/code/modules/client/loadout/_loadout.dm @@ -53,6 +53,8 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) var/path //item-to-spawn path var/cost = 1 //normally, each loadout costs a single point. var/geargroupID //defines the ID that the gear inherits from the config + var/loadout_flags = 0 + var/list/loadout_initial_colors = list() //NEW DONATOR SYTSEM STUFF var/donoritem //autoset on new if null diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm index c7eff6ce78..7c3c11f25c 100644 --- a/modular_citadel/code/modules/client/loadout/neck.dm +++ b/modular_citadel/code/modules/client/loadout/neck.dm @@ -86,7 +86,11 @@ /datum/gear/neck/polycloak name = "Polychromatic Cloak" path = /obj/item/clothing/neck/cloak/polychromic + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#FFFFFF", "#808080") /datum/gear/neck/altpolycloak name = "Alternate Cloak" path = /obj/item/clothing/neck/cloak/alt/polychromic + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#676767", "#4C4C4C") diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm index d0be26a8a4..7c21ed84d0 100644 --- a/modular_citadel/code/modules/client/loadout/suit.dm +++ b/modular_citadel/code/modules/client/loadout/suit.dm @@ -101,6 +101,8 @@ name = "Polychromic winter coat" path = /obj/item/clothing/suit/hooded/wintercoat/polychromic cost = 4 //too many people with neon green coats is hard on the eyes + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#6A6964", "#C4B8A6", "#0000FF") /datum/gear/suit/coat/med name = "Medical winter coat" diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm index 76389e2015..b76e223f25 100644 --- a/modular_citadel/code/modules/client/loadout/uniform.dm +++ b/modular_citadel/code/modules/client/loadout/uniform.dm @@ -47,6 +47,8 @@ /datum/gear/uniform/maidcostume/polychromic name = "Polychromic maid costume" path = /obj/item/clothing/under/rank/civilian/janitor/maid/polychromic + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#000000") /datum/gear/uniform/mailmanuniform name = "Mailman's jumpsuit" @@ -227,36 +229,50 @@ name = "Polychromic Jumpsuit" path = /obj/item/clothing/under/misc/polyjumpsuit cost = 2 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#808080", "#353535") /datum/gear/uniform/skirt/poly name = "Polychromic Jumpskirt" path = /obj/item/clothing/under/dress/skirt/polychromic cost = 2 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#F08080", "#808080") /datum/gear/uniform/suit/poly name = "Polychromic Button-up Shirt" path = /obj/item/clothing/under/misc/poly_shirt cost = 3 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#353535", "#353535") /datum/gear/uniform/skirt/poly/pleated name = "Polychromic Pleated Sweaterskirt" path = /obj/item/clothing/under/dress/skirt/polychromic/pleated cost = 3 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#8CC6FF", "#808080", "#FF3535") /datum/gear/uniform/polykilt name = "Polychromic Kilt" path = /obj/item/clothing/under/costume/kilt/polychromic cost = 3 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#F08080") /datum/gear/uniform/shorts/poly name = "Polychromic Shorts" path = /obj/item/clothing/under/misc/polyshorts cost = 3 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#353535", "#808080", "#808080") /datum/gear/uniform/shorts/poly/athletic name = "Polychromic Athletic Shorts" path = /obj/item/clothing/under/shorts/polychromic cost = 2 + loadout_flags = LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#FFFFFF", "#F08080") /datum/gear/uniform/hopcasual name = "Casual Head of Personnel's uniform" | |