Skip to content

Commit

Permalink
Adds loadout slots / presets (on a per-character basis) (#377)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrMelbert authored Nov 20, 2023
1 parent 3db14b8 commit 18c4e41
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 63 deletions.
3 changes: 3 additions & 0 deletions code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

#define isweakref(D) (istype(D, /datum/weakref))

GLOBAL_VAR_INIT(magic_appearance_detecting_image, new /image) // appearances are awful to detect safely, but this seems to be the best way ~ninjanomnom
#define isappearance(thing) (!istype(thing, /image) && !ispath(thing) && istype(GLOB.magic_appearance_detecting_image, thing))

#define isgenerator(A) (istype(A, /generator))

//Turfs
Expand Down
4 changes: 4 additions & 0 deletions code/modules/admin/view_variables/debug_variables.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
item = "[name_part] = /icon (<span class='value'>[value]</span>)"
#endif

else if(isappearance(value))
var/image/actually_an_appearance = value
item = "[name_part] = /appearance (<span class='value'>[actually_an_appearance.icon]</span>)"

else if (isfile(value))
item = "[name_part] = <span class='value'>'[value]'</span>"

Expand Down
2 changes: 1 addition & 1 deletion code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
body = new

// Without this, it doesn't show up in the menu
body.appearance_flags &= ~KEEP_TOGETHER
// body.appearance_flags &= ~KEEP_TOGETHER // NON-MODULE CHANGE

/datum/preferences/proc/create_character_profiles()
var/list/profiles = list()
Expand Down
2 changes: 1 addition & 1 deletion code/modules/client/preferences_savefile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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 43
#define SAVEFILE_VERSION_MAX 43.1

/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
Expand Down
3 changes: 3 additions & 0 deletions maplestation_modules/code/__DEFINES/_module_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@
#define SOUND_NORMAL (1<<0)
#define SOUND_QUESTION (1<<1)
#define SOUND_EXCLAMATION (1<<2)

/// Max loadout presets available
#define MAX_LOADOUTS 5
15 changes: 14 additions & 1 deletion maplestation_modules/code/modules/client/preferences/height.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
return

// Snowflake, but otherwise the dummy in the prefs menu will be resized and you can't see anything
if(istype(target, /mob/living/carbon/human/dummy))
if(isdummy(target))
return
// Just in case
if(!ishuman(target))
Expand Down Expand Up @@ -143,6 +143,19 @@
#undef SIZE_PREF_PRIORITY
#undef HEIGHT_PREF_PRIORITY

// To speed up the preference menu, we apply 1 filter to the entire mob
/mob/living/carbon/human/dummy/regenerate_icons()
. = ..()
apply_height_filters(src, TRUE)

/mob/living/carbon/human/dummy/apply_height_filters(mutable_appearance/appearance, only_apply_in_prefs = FALSE)
if(only_apply_in_prefs)
return ..()

// Not necessary with above
/mob/living/carbon/human/dummy/apply_height_offsets(mutable_appearance/appearance, upper_torso)
return

/mob/living/carbon/human/get_mob_height()
// If you have roundstart dwarfism (IE: resized), it'll just return normal mob height, so no filters are applied
if(HAS_TRAIT_FROM_ONLY(src, TRAIT_DWARF, ROUNDSTART_TRAIT))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/datum/preference/numeric/active_loadout
savefile_key = "active_loadout"
savefile_identifier = PREFERENCE_CHARACTER
can_randomize = FALSE
minimum = 1
maximum = MAX_LOADOUTS

/datum/preference/numeric/active_loadout/create_default_value()
return minimum

/datum/preference/numeric/active_loadout/apply_to_human(mob/living/carbon/human/target, value)
return

/datum/preference/loadout
savefile_key = "loadout_list"
savefile_identifier = PREFERENCE_CHARACTER
Expand All @@ -15,21 +28,56 @@
if(!istype(target))
return // Not a crash, 'cause this proc could be passed non-humans (AIs, etc) and that's fine

for(var/datum/loadout_item/item as anything in loadout_list_to_datums(value))
var/slot = prefs.read_preference(/datum/preference/numeric/active_loadout)
for(var/datum/loadout_item/item as anything in loadout_list_to_datums(value[slot]))
item.post_equip_item(prefs, target)

/datum/preference/loadout/serialize(input, datum/preferences/preferences)
// Sanitize on save even though it's highly unlikely this will need it
return sanitize_loadout_list(input)

/datum/preference/loadout/deserialize(input, datum/preferences/preferences)
// Sanitize on load to ensure no invalid paths from older saves get in
// Pass in the prefernce owner so they can get feedback messages on stuff that failed to load (if they exist)
return sanitize_loadout_list(input, preferences.parent?.mob)
var/slot = preferences.read_preference(/datum/preference/numeric/active_loadout)

// Default value is NULL - the loadout list is a lazylist
for(var/i in 1 to length(input))
if(islist(input[i]))
// Pass in the prefernce owner so they can get feedback messages on stuff that failed to load (if they exist)
input[i] = sanitize_loadout_list(input[i], preferences.parent?.mob, slot)

return input

// 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, loadout_slot)
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))
to_chat(optional_loadout_owner, span_boldnotice("The following invalid item path was found in loadout slot [loadout_slot]: [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))
to_chat(optional_loadout_owner, span_boldnotice("The following invalid loadout item was found in loadout slot [loadout_slot]: [real_path || "null"]. \
It has been removed, renamed, or is otherwise missing - You may want to check your loadout settings."))
continue

// Set into sanitize list using converted path key
var/list/data = passed_list[path]
LAZYSET(sanitized_list, real_path, LAZYLISTDUPLICATE(data))

return sanitized_list

/datum/preferences/update_character(current_version, list/save_data)
. = ..()
if(current_version < 43.1)
save_loadout(src, save_data?["loadout_list"])
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
to_chat(user, span_warning("You already have a greyscaling window open!"))
return

var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
var/list/loadout = get_active_loadout(manager.preferences)
var/list/allowed_configs = list()
if(initial(item_path.greyscale_config))
allowed_configs += "[initial(item_path.greyscale_config)]"
Expand Down Expand Up @@ -122,7 +122,7 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
if(!istype(open_menu))
CRASH("set_slot_greyscale called without a greyscale menu!")

var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
var/list/loadout = get_active_loadout(manager.preferences)
if(!loadout?[item_path])
manager.select_item(src)

Expand All @@ -131,11 +131,11 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
return

loadout[item_path][INFO_GREYSCALE] = colors.Join("")
manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(manager.preferences, loadout)
manager.character_preview_view.update_body()

/datum/loadout_item/proc/set_name(datum/preference_middleware/loadout/manager, mob/user)
var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
var/list/loadout = get_active_loadout(manager.preferences)
var/input_name = tgui_input_text(
user = user,
message = "What name do you want to give [name]? Leave blank to clear.",
Expand All @@ -154,10 +154,10 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
else
loadout[item_path] -= INFO_NAMED

manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(manager.preferences, loadout)

/datum/loadout_item/proc/set_skin(datum/preference_middleware/loadout/manager, mob/user)
var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
var/list/loadout = get_active_loadout(manager.preferences)
var/static/list/list/cached_reskins = list()
if(!islist(cached_reskins[item_path]))
var/obj/item/item_template = new item_path()
Expand Down Expand Up @@ -185,7 +185,7 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
else
loadout[item_path][INFO_RESKIN] = input_skin

manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(manager.preferences, loadout)

/**
* Place our [var/item_path] into [outfit].
Expand Down Expand Up @@ -232,7 +232,7 @@ GLOBAL_LIST_EMPTY(all_loadout_datums)
else
// Not valid
item_details -= INFO_RESKIN
preference_source.write_preference(GLOB.preference_entries[/datum/preference/loadout], preference_list)
save_loadout(preference_source, preference_list)

return equipped_item

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
return ..()

/datum/loadout_item/accessory/proc/set_accessory_layer(datum/preference_middleware/loadout/manager, mob/user)
var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
var/list/loadout = get_active_loadout(manager.preferences)
if(!loadout?[item_path])
manager.select_item(src)

Expand All @@ -44,7 +44,7 @@

loadout[item_path][INFO_LAYER] = !loadout[item_path][INFO_LAYER]
to_chat(user, span_boldnotice("[name] will now appear [loadout[item_path][INFO_LAYER] ? "above" : "below"] suits."))
manager.preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(manager.preferences, loadout)

/datum/loadout_item/accessory/insert_path_into_outfit(datum/outfit/outfit, mob/living/carbon/human/equipper, visuals_only = FALSE)
if(outfit.accessory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())
"toggle_job_clothes" = PROC_REF(action_toggle_job_outfit),
"rotate_dummy" = PROC_REF(action_rotate_model_dir),
"pass_to_loadout_item" = PROC_REF(action_pass_to_loadout_item),
"select_slot" = PROC_REF(select_slot),
)

/// The preview dummy.
Expand Down Expand Up @@ -112,7 +113,7 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())
return TRUE

/datum/preference_middleware/loadout/proc/action_clear_all(list/params, mob/user)
preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], null)
update_loadout(preferences, null)
character_preview_view.update_body()
return TRUE

Expand Down Expand Up @@ -143,7 +144,7 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())

/// 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/loadout = get_active_loadout(preferences)
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)
Expand All @@ -153,13 +154,13 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())
return

LAZYSET(loadout, selected_item.item_path, list())
preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(preferences, 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)
var/list/loadout = get_active_loadout(preferences)
LAZYREMOVE(loadout, deselected_item.item_path)
preferences.update_preference(GLOB.preference_entries[/datum/preference/loadout], loadout)
update_loadout(preferences, loadout)

/datum/preference_middleware/loadout/proc/register_greyscale_menu(datum/greyscale_modify_menu/open_menu)
src.menu = open_menu
Expand All @@ -169,19 +170,26 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())
SIGNAL_HANDLER
menu = null

/datum/preference_middleware/loadout/proc/select_slot(list/params, mob/user)
preferences.write_preference(GLOB.preference_entries[/datum/preference/numeric/active_loadout], text2num(params["new_slot"]))
character_preview_view.update_body()
preferences.character_preview_view?.update_body()
preferences.update_static_data(user)

/datum/preference_middleware/loadout/get_ui_data(mob/user)
var/list/data = list()

if (isnull(character_preview_view))
character_preview_view = create_character_preview_view(user)

var/list/all_selected_paths = list()
for(var/path in preferences.read_preference(/datum/preference/loadout))
for(var/path in get_active_loadout(preferences))
all_selected_paths += path

data["selected_loadout"] = all_selected_paths
data["mob_name"] = preferences.read_preference(/datum/preference/name/real_name)
data["job_clothes"] = character_preview_view.view_job_clothes
data["current_slot"] = preferences.read_preference(/datum/preference/numeric/active_loadout)

return data

Expand All @@ -202,6 +210,7 @@ GLOBAL_LIST_INIT(loadout_categories, init_loadout_categories())

data["loadout_tabs"] = loadout_tabs
data["tutorial_text"] = get_tutorial_text()
data["max_loadout_slots"] = MAX_LOADOUTS
return data

/// Returns a formatted string for use in the UI.
Expand Down
Loading

0 comments on commit 18c4e41

Please sign in to comment.