Skip to content

Commit

Permalink
Support for holiday loadout items (and also custom lipstick colors I …
Browse files Browse the repository at this point in the history
…guess) (#644)
  • Loading branch information
MrMelbert authored Jan 25, 2025
1 parent cb3846a commit d816694
Show file tree
Hide file tree
Showing 18 changed files with 134 additions and 82 deletions.
5 changes: 5 additions & 0 deletions code/__DEFINES/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,8 @@
#define INFO_RESKIN "reskin"
/// Handles which layer the item will be on, for accessories
#define INFO_LAYER "layer"

// Lipstick styles
#define UPPER_LIP "Upper"
#define MIDDLE_LIP "Middle"
#define LOWER_LIP "Lower"
2 changes: 1 addition & 1 deletion code/datums/components/trader/trader.dm
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Can accept both a type path, and an instance of a datum. Type path has priority.
display_names["[initial(thing.name)]"] = thing

if(!radial_icons_cache[thing])
radial_icons_cache[thing] = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state_preview) ? initial(thing.icon_state_preview) : initial(thing.icon_state))
radial_icons_cache[thing] = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state_preview) || initial(thing.icon_state))

var/image/item_image = radial_icons_cache[thing]
product_info = products[thing]
Expand Down
8 changes: 0 additions & 8 deletions code/game/objects/items/cosmetics.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
#define UPPER_LIP "Upper"
#define MIDDLE_LIP "Middle"
#define LOWER_LIP "Lower"

/obj/item/lipstick
gender = PLURAL
name = "red lipstick"
Expand Down Expand Up @@ -333,7 +329,3 @@

/obj/item/razor/surgery/get_surgery_tool_overlay(tray_extended)
return "razor"

#undef UPPER_LIP
#undef MIDDLE_LIP
#undef LOWER_LIP
1 change: 1 addition & 0 deletions code/modules/clothing/head/hat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
name = "santa hat"
desc = "On the first day of christmas my employer gave to me!"
icon_state = "santa_hat"
icon_state_preview = "santahatnorm"
greyscale_colors = "#cc0000#f8f8f8"
greyscale_config = /datum/greyscale_config/santa_hat
greyscale_config_worn = /datum/greyscale_config/santa_hat/worn
Expand Down
1 change: 1 addition & 0 deletions code/modules/clothing/masks/costume.dm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
name = "kitsune mask"
desc = "Porcelain mask made in the style of the Sol-3 region. It is painted to look like a kitsune."
icon_state = "kitsune"
icon_state_preview = "kitsune_base"
inhand_icon_state = null
w_class = WEIGHT_CLASS_SMALL
adjusted_flags = ITEM_SLOT_HEAD
Expand Down
3 changes: 3 additions & 0 deletions code/modules/clothing/suits/moth.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
name = "mothic flightsuit"
desc = "This peculiar utility harness is a common sight among the moth fleet's crews due to its ability to fasten the wings to the body without impacting mobility inside cramped ship interiors. It looks somewhat crude yet it's surprisingly comfortable."
icon_state = "mothcoat"
icon_preview = 'icons/obj/clothing/suits/moth.dmi'
icon_state_preview = "mothcoat"
greyscale_config = /datum/greyscale_config/mothcoat
greyscale_config_worn = /datum/greyscale_config/mothcoat/worn
greyscale_colors = "#eaeaea"
Expand All @@ -23,6 +25,7 @@
name = "mothic mantella"
desc = "A thick garment that keeps warm and protects those precious wings from harsh weather, also commonly used during festivities. Feels much heavier than it looks."
icon_state = "mothcoat_winter"
icon_state_preview = "mothcoat_mantle_top"
greyscale_config = /datum/greyscale_config/mothcoat_winter
greyscale_config_worn = /datum/greyscale_config/mothcoat_winter/worn
greyscale_colors = "#557979#795e55"
Expand Down
2 changes: 2 additions & 0 deletions code/modules/clothing/under/shorts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
name = "shorts"
desc = "A pair of comfy shorts."
icon_state = "shorts"
icon_preview = 'icons/obj/clothing/under/shorts_pants_shirts.dmi'
icon_state_preview = "shorts"
greyscale_config = /datum/greyscale_config/shorts
greyscale_config_worn = /datum/greyscale_config/shorts/worn
greyscale_colors = "#575757#3E3E3E#75634F"
Expand Down
6 changes: 6 additions & 0 deletions code/modules/clothing/under/skirt_dress.dm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
name = "turtleneck skirt"
desc = "A casual turtleneck skirt."
icon_state = "turtleskirt"
icon_preview = 'icons/obj/clothing/under/dress.dmi'
icon_state_preview = "turtleskirt_top"
custom_price = PAYCHECK_CREW
greyscale_colors = "#cc0000#5f5f5f"
greyscale_config = /datum/greyscale_config/turtleskirt
Expand All @@ -65,6 +67,8 @@
name = "tango dress"
desc = "Filled with Latin fire."
icon_state = "tango"
icon_preview = 'icons/obj/clothing/under/dress.dmi'
icon_state_preview = "tango_base"
custom_price = PAYCHECK_CREW
greyscale_colors = "#ff0000#1c1c1c"
greyscale_config = /datum/greyscale_config/tango
Expand All @@ -75,6 +79,8 @@
name = "sundress"
desc = "Makes you want to frolic in a field of daisies."
icon_state = "sundress"
icon_preview = 'icons/obj/clothing/under/dress.dmi'
icon_state_preview = "sundress_base"
custom_price = PAYCHECK_CREW
greyscale_colors = "#FFE60F#9194A5#1F243C"
greyscale_config = /datum/greyscale_config/sundress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,9 @@

// Sanitize on load to ensure no invalid paths from older saves get in
/datum/preference/loadout/deserialize(input, datum/preferences/preferences)
// Sanitize on load to ensure no invalid paths from older saves get in
var/slot = preferences.read_preference(/datum/preference/numeric/active_loadout)

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)
input[i] = sanitize_loadout_list(input[i])

return input

Expand All @@ -52,25 +48,14 @@
*
* Returns a list, or null if empty
*/
/datum/preference/loadout/proc/sanitize_loadout_list(list/passed_list, mob/optional_loadout_owner) as /list
/datum/preference/loadout/proc/sanitize_loadout_list(list/passed_list) as /list
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, /obj/item))
if(optional_loadout_owner)
to_chat(optional_loadout_owner, span_boldnotice("The following invalid item path was found \
in your character loadout: [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))
if(optional_loadout_owner)
to_chat(optional_loadout_owner, span_boldnotice("The following invalid loadout item was found \
in your character loadout: [real_path || "null"]. \
It has been removed, renamed, or is otherwise missing - \
You may want to check your loadout settings."))
if(!istype(GLOB.all_loadout_datums[real_path], /datum/loadout_item))
continue

// Set into sanitize list using converted path key
Expand Down
2 changes: 2 additions & 0 deletions maplestation_modules/code/modules/clothing/suits/armor.dm
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@
name = "tailored parade jacket"
desc = "No armor, all fashion, unfortunately."
icon_state = "formal"
icon_preview = 'maplestation_modules/icons/obj/clothing/suit.dmi'
icon_state_preview = "formal"
inhand_icon_state = "labcoat"
body_parts_covered = CHEST|GROIN|ARMS
allowed = list(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
icon = 'maplestation_modules/icons/obj/clothing/under/spacer_turtleneck.dmi'
worn_icon = 'maplestation_modules/icons/mob/clothing/under/spacer_turtleneck.dmi'
icon_state = "turtleneck"
icon_preview = 'maplestation_modules/icons/obj/clothing/under/spacer_turtleneck.dmi'
icon_state_preview = "greyscale_sweater"
greyscale_config = /datum/greyscale_config/spacer_turtleneck
greyscale_config_worn = /datum/greyscale_config/spacer_turtleneck_worn
greyscale_colors = "#5e483c#1c1c1c#4fb4e6"
Expand All @@ -46,6 +48,7 @@
name = "spacer's uniform"
desc = "An old ship uniform from the days of spacefarers past. In the old days, engineering wore red and command wore gold."
icon_state = "turtlefool"
icon_state_preview = "greyscale_shirt"

/obj/item/clothing/under/spacer_turtleneck/skirt
name = "spacer's skirtleneck"
Expand All @@ -59,6 +62,7 @@
name = "spacer's skirt"
desc = "An old ship uniform from the days of spacefarers past. In the old days, engineering wore red and command wore gold. And women wore less."
icon_state = "turtlefool_skirt"
icon_state_preview = "greyscale_shirt"

/obj/item/clothing/under/arbitersuit
name = "arbiter's suit"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/// Global list of ALL loadout datums instantiated.
/// Loadout datums are created by loadout categories.
GLOBAL_LIST_EMPTY(all_loadout_datums)
GLOBAL_LIST_EMPTY_TYPED(all_loadout_datums, /datum/loadout_item)

/// Global list of all loadout categories
/// Doesn't really NEED to be a global but we need to init this early for preferences,
/// as the categories instantiate all the loadout datums
GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
GLOBAL_LIST_INIT_TYPED(all_loadout_categories, /datum/loadout_category, init_loadout_categories())

/// Inits the global list of loadout category singletons
/// Also inits loadout item singletons
Expand Down Expand Up @@ -46,6 +46,8 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
/// Whether this item can be reskinned.
/// Only works if the item has a "unique reskin" list set.
var/can_be_reskinned = FALSE
/// If set, this item can only be selected during the holiday specified.
var/required_holiday
/// The abstract parent of this loadout item, to determine which items to not instantiate
var/abstract_type = /datum/loadout_item
/// The actual item path of the loadout item.
Expand Down Expand Up @@ -225,10 +227,11 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
* At this point the item is in the mob's contents
*
* Arguments:
* * equipped_item - the item that was equipped - may be null for certain items (pocket items)
* * preference_source - the datum/preferences our loadout item originated from - cannot be null
* * preference_list - what the raw loadout list looks like in the preferences
* * equipper - the mob we're equipping this item onto - cannot be null
* * visuals_only - whether or not this is only concerned with visual things (not backpack, not renaming, etc)
* * preference_list - what the raw loadout list looks like in the preferences
*
* Return a bitflag of slot flags to update
*/
Expand All @@ -239,7 +242,8 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
mob/living/carbon/human/equipper,
visuals_only = FALSE,
)
ASSERT(!isnull(equipped_item))
if(isnull(equipped_item))
return NONE

//if(!visuals_only)
// ADD_TRAIT(equipped_item, TRAIT_ITEM_OBJECTIVE_BLOCKED, "Loadout")
Expand Down Expand Up @@ -293,8 +297,15 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
formatted_item["reskins"] = get_reskin_options()
formatted_item["icon"] = ui_icon
formatted_item["icon_state"] = ui_icon_state
formatted_item["disabled"] = is_disabled()
return formatted_item

/**
* Checks if this item is disabled and cannot be selected or granted
*/
/datum/loadout_item/proc/is_disabled()
return required_holiday && !check_holidays(required_holiday)

/**
* Returns a list of information to display about this item in the loadout UI.
*
Expand All @@ -304,7 +315,11 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
SHOULD_CALL_PARENT(TRUE)
var/list/displayed_text = list()

displayed_text += (additional_displayed_text || list())
if(LAZYLEN(additional_displayed_text))
displayed_text += additional_displayed_text

if(required_holiday)
displayed_text += required_holiday

if(can_be_greyscale)
displayed_text += "Recolorable"
Expand All @@ -321,7 +336,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
* Returns a list of buttons that are shown in the loadout UI for customizing this item.
*
* Buttons contain
* - 'L'abel: The text displayed beside the button
* - Label: The text displayed beside the button
* - act_key: The key that is sent to the loadout manager when the button is clicked,
* for use in handle_loadout_action
* - button_icon: The FontAwesome icon to display on the button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,8 @@
name = "Violet Nurse Cap"
item_path = /obj/item/clothing/head/costume/vince
additional_displayed_text = list("Character Item")

/datum/loadout_item/head/santa
name = "Santa Hat"
item_path = /obj/item/clothing/head/costume/santa/gags
required_holiday = FESTIVE_SEASON
Original file line number Diff line number Diff line change
Expand Up @@ -116,42 +116,71 @@
name = "Pack of HP+ Gum"
item_path = /obj/item/storage/box/gum/happiness

/datum/loadout_item/pocket_items/lipstick_black
name = "Lipstick (Black)"
item_path = /obj/item/lipstick/black
additional_displayed_text = list("Black")

/datum/loadout_item/pocket_items/lipstick_blue
name = "Lipstick (Blue)"
item_path = /obj/item/lipstick/blue
additional_displayed_text = list("Blue")


/datum/loadout_item/pocket_items/lipstick_green
name = "Lipstick (Green)"
item_path = /obj/item/lipstick/green
additional_displayed_text = list("Green")


/datum/loadout_item/pocket_items/lipstick_jade
name = "Lipstick (Jade)"
item_path = /obj/item/lipstick/jade
additional_displayed_text = list("Jade")

/datum/loadout_item/pocket_items/lipstick_purple
name = "Lipstick (Purple)"
item_path = /obj/item/lipstick/purple
additional_displayed_text = list("Purple")

/datum/loadout_item/pocket_items/lipstick_red
name = "Lipstick (Red)"
/datum/loadout_item/pocket_items/lipstick
name = "Lipstick"
item_path = /obj/item/lipstick
additional_displayed_text = list("Red")
additional_displayed_text = list("Recolorable")

/datum/loadout_item/pocket_items/lipstick_white
name = "Lipstick (White)"
item_path = /obj/item/lipstick/white
additional_displayed_text = list("White")
/datum/loadout_item/pocket_items/lipstick/on_equip_item(
obj/item/lipstick/equipped_item,
datum/preferences/preference_source,
list/preference_list,
mob/living/carbon/human/equipper,
visuals_only,
)
. = ..()
var/picked_style = style_to_style(preference_list[item_path]?[INFO_LAYER])
var/picked_color = preference_list[item_path]?[INFO_GREYSCALE] || /obj/item/lipstick::lipstick_color
if(istype(equipped_item)) // can be null for visuals_only
equipped_item.style = picked_style
equipped_item.lipstick_color = picked_color
equipper.update_lips(picked_style, picked_color)

/// Converts style (readable) to style (internal)
/datum/loadout_item/pocket_items/lipstick/proc/style_to_style(style)
switch(style)
if(UPPER_LIP)
return "lipstick_upper"
if(LOWER_LIP)
return "lipstick_lower"
return "lipstick"

/datum/loadout_item/pocket_items/lipstick/get_ui_buttons()
. = ..()
UNTYPED_LIST_ADD(., list(
"label" = "Style",
"act_key" = "select_lipstick_style",
"button_icon" = FA_ICON_ARROWS_ROTATE,
"active_key" = INFO_LAYER,
))
UNTYPED_LIST_ADD(., list(
"label" = "Color",
"act_key" = "select_lipstick_color",
"button_icon" = FA_ICON_PALETTE,
"active_key" = INFO_GREYSCALE,
))

/datum/loadout_item/pocket_items/lipstick/handle_loadout_action(datum/preference_middleware/loadout/manager, mob/user, action, params)
switch(action)
if("select_lipstick_style")
var/old_style = get_active_loadout(manager.preferences)[item_path][INFO_LAYER] || MIDDLE_LIP
var/chosen = tgui_input_list(user, "Pick a lipstick style. This determines where it goes on your sprite.", "Pick a style", list(UPPER_LIP, MIDDLE_LIP, LOWER_LIP), old_style)
var/list/loadout = get_active_loadout(manager.preferences) // after sleep: sanity check
if(loadout?[item_path]) // Validate they still have it equipped
loadout[item_path][INFO_LAYER] = chosen
update_loadout(manager.preferences, loadout)
return TRUE // Update UI

if("select_lipstick_color")
var/old_color = get_active_loadout(manager.preferences)[item_path][INFO_GREYSCALE] || /obj/item/lipstick::lipstick_color
var/chosen = input(user, "Pick a lipstick color.", "Pick a color", old_color) as color|null
var/list/loadout = get_active_loadout(manager.preferences) // after sleep: sanity check
if(loadout?[item_path]) // Validate they still have it equipped
loadout[item_path][INFO_GREYSCALE] = chosen
update_loadout(manager.preferences, loadout)
return TRUE // Update UI

return ..()

/datum/loadout_item/pocket_items/razor
name = "Razor"
Expand Down
Loading

0 comments on commit d816694

Please sign in to comment.