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 += "" dat += "" dat += "" @@ -861,15 +875,27 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(donoritem && !gear.donator_ckey_check(user.ckey)) continue var/class_link = "" - if(gear.type in chosen_gear) + var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.type]") + var/extra_color_data = "" + if(loadout_item) class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'" + if(gear.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) + extra_color_data += "
Color" + for(var/loadout_color in loadout_item[LOADOUT_COLOR]) + extra_color_data += "   " + else + var/loadout_color_non_poly = "#FFFFFF" + if(length(loadout_item[LOADOUT_COLOR])) + loadout_color_non_poly = loadout_item[LOADOUT_COLOR][1] + extra_color_data += "
Color" + extra_color_data += "   " else if(gear_points <= 0) class_link = "style='white-space:normal;' class='linkOff'" else if(donoritem) class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" else class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" - dat += "" + dat += "" dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can only choose one item per category, unless it's an item that spawns in your backpack or hands.
[name]
[name][extra_color_data][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"