[MIRROR] Separate init_possible_values() from icon generation [MDB IGNORE] (#23221)

* Separate init_possible_values() from icon generation

* Update clothing.dm

* Update lizard.dm

* Modular

* Runtime fix

* Modular adjustments

* Fixes icon offset for undershirt

* Update mutant_parts.dm

* Update mutant_parts.dm

* Fix a merge skew

* Update mutant_parts.dm

* More of a catch-all solution

* Update _preference.dm

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-08-25 03:44:13 +02:00
committed by GitHub
parent 0e518798f9
commit 57abd05851
22 changed files with 342 additions and 341 deletions

View File

@@ -135,14 +135,18 @@ Choiced preferences can generate icons. This is how the clothing/species prefere
savefile_key = "favorite_drink"
should_generate_icons = TRUE // NEW! This is necessary.
// Instead of returning a flat list, this now returns an assoc list
// of values to icons.
/datum/preference/choiced/favorite_drink/init_possible_values()
return list(
"Milk" = icon('drinks.dmi', "milk"),
"Cola" = icon('drinks.dmi', "cola"),
"Water" = icon('drinks.dmi', "water"),
)
return list("Milk", "Cola", "Water")
// New! This proc will get called for every value.
/datum/preference/choiced/favorite_drink/icon_for(value)
switch (value)
if ("Milk")
return icon('drinks.dmi', "milk")
if ("Cola")
return icon('drinks.dmi', "cola")
if ("Water")
return icon('drinks.dmi', "water")
```
Then, change your `.tsx` file to look like:

View File

@@ -347,9 +347,8 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
/// A preference that is a choice of one option among a fixed set.
/// Used for preferences such as clothing.
/datum/preference/choiced
/// If this is TRUE, icons will be generated.
/// This is necessary for if your `init_possible_values()` override
/// returns an assoc list of names to atoms/icons.
/// If this is TRUE, an icon will be generated for every value.
/// If you implement this, you must implement `icon_for(value)` for every possible value.
var/should_generate_icons = FALSE
var/list/cached_values
@@ -376,34 +375,31 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
return cached_values
/// Returns a list of every possible value, serialized.
/// Return value can be in the form of:
/// - A flat list of serialized values, such as list(MALE, FEMALE, PLURAL).
/// - An assoc list of serialized values to atoms/icons.
/datum/preference/choiced/proc/get_choices_serialized()
// Override `init_values()` instead.
SHOULD_NOT_OVERRIDE(TRUE)
var/list/serialized_choices = list()
var/choices = get_choices()
if (should_generate_icons)
for (var/choice in choices)
serialized_choices[serialize(choice)] = choices[choice]
else
for (var/choice in choices)
for (var/choice in get_choices())
serialized_choices += serialize(choice)
return serialized_choices
/// Returns a list of every possible value.
/// This must be overriden by `/datum/preference/choiced` subtypes.
/// Return value can be in the form of:
/// - A flat list of raw values, such as list(MALE, FEMALE, PLURAL).
/// - An assoc list of raw values to atoms/icons, in which case
/// icons will be generated.
/// If `should_generate_icons` is TRUE, then you will also need to implement `icon_for(value)`
/// for every possible value.
/datum/preference/choiced/proc/init_possible_values()
CRASH("`init_possible_values()` was not implemented for [type]!")
/// When `should_generate_icons` is TRUE, this proc is called for every value.
/// It can return either an icon or a typepath to an atom to create.
/datum/preference/choiced/proc/icon_for(value)
SHOULD_CALL_PARENT(FALSE)
SHOULD_NOT_SLEEP(TRUE)
CRASH("`icon_for()` was not implemented for [type], even though should_generate_icons = TRUE!")
/datum/preference/choiced/is_valid(value)
return value in get_choices()
@@ -453,51 +449,6 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
/datum/preference/color/is_valid(value)
return findtext(value, GLOB.is_color)
/// Takes an assoc list of names to /datum/sprite_accessory and returns a value
/// fit for `/datum/preference/init_possible_values()`
/proc/possible_values_for_sprite_accessory_list(list/datum/sprite_accessory/sprite_accessories)
var/list/possible_values = list()
for (var/name in sprite_accessories)
var/datum/sprite_accessory/sprite_accessory = sprite_accessories[name]
if (istype(sprite_accessory))
possible_values[name] = icon(sprite_accessory.icon, sprite_accessory.icon_state)
else
// This means it didn't have an icon state
possible_values[name] = icon('icons/mob/landmarks.dmi', "x")
return possible_values
/// Takes an assoc list of names to /datum/sprite_accessory and returns a value
/// fit for `/datum/preference/init_possible_values()`
/// Different from `possible_values_for_sprite_accessory_list` in that it takes a list of layers
/// such as BEHIND, FRONT, and ADJ.
/// It also takes a "body part name", such as body_markings, moth_wings, etc
/// They are expected to be in order from lowest to top.
/proc/possible_values_for_sprite_accessory_list_for_body_part(
list/datum/sprite_accessory/sprite_accessories,
body_part,
list/layers,
)
var/list/possible_values = list()
for (var/name in sprite_accessories)
var/datum/sprite_accessory/sprite_accessory = sprite_accessories[name]
if(sprite_accessory.locked)
continue
var/icon/final_icon
for (var/layer in layers)
var/icon/icon = icon(sprite_accessory.icon, "m_[body_part]_[sprite_accessory.icon_state]_[layer]")
if (isnull(final_icon))
final_icon = icon
else
final_icon.Blend(icon, ICON_OVERLAY)
possible_values[name] = final_icon
return possible_values
/// A numeric preference with a minimum and maximum value
/datum/preference/numeric
/// The minimum value

View File

@@ -6,14 +6,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/ai_core_display/init_possible_values()
var/list/values = list()
return GLOB.ai_core_display_screens - "Portrait"
values["Random"] = icon('icons/mob/silicon/ai.dmi', "questionmark")
for (var/screen in GLOB.ai_core_display_screens - "Portrait" - "Random")
values[screen] = icon('icons/mob/silicon/ai.dmi', resolve_ai_icon_sync(screen))
return values
/datum/preference/choiced/ai_core_display/icon_for(value)
if (value == "Random")
return icon('icons/mob/silicon/ai.dmi', "questionmark")
else
return icon('icons/mob/silicon/ai.dmi', resolve_ai_icon_sync(value))
/datum/preference/choiced/ai_core_display/is_accessible(datum/preferences/preferences)
if (!..(preferences))

View File

@@ -6,15 +6,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/ai_emote_display/init_possible_values()
var/list/values = list()
return assoc_to_keys(GLOB.ai_status_display_emotes)
values["Random"] = icon('icons/mob/silicon/ai.dmi', "questionmark")
for(var/emote in GLOB.ai_status_display_emotes)
var/emote_icon = GLOB.ai_status_display_emotes[emote]
values[emote] = icon('icons/obj/machines/status_display.dmi', emote_icon)
return values
/datum/preference/choiced/ai_emote_display/icon_for(value)
if (value == "Random")
return icon('icons/mob/silicon/ai.dmi', "questionmark")
else
return icon('icons/obj/machines/status_display.dmi', GLOB.ai_status_display_emotes[value])
/datum/preference/choiced/ai_emote_display/is_accessible(datum/preferences/preferences)
if (!..(preferences))

View File

@@ -6,14 +6,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/ai_hologram_display/init_possible_values()
var/list/values = list()
return assoc_to_keys(GLOB.ai_hologram_icons) + "Random"
values["Random"] = icon('icons/mob/silicon/ai.dmi', "questionmark")
for(var/hologram in GLOB.ai_hologram_icons - "Random")
values[hologram] = icon(GLOB.ai_hologram_icons[hologram], GLOB.ai_hologram_icon_state[hologram])
return values
/datum/preference/choiced/ai_hologram_display/icon_for(value)
if (value == "Random")
return icon('icons/mob/silicon/ai.dmi', "questionmark")
else
return icon(GLOB.ai_hologram_icons[value], GLOB.ai_hologram_icon_state[value])
/datum/preference/choiced/ai_hologram_display/is_accessible(datum/preferences/preferences)
if (!..(preferences))

View File

@@ -15,9 +15,8 @@
if (!preference.should_generate_icons)
continue
var/list/choices = preference.get_choices_serialized()
for (var/preference_value in choices)
var/create_icon_of = choices[preference_value]
for (var/preference_value in preference.get_choices())
var/create_icon_of = preference.icon_for(preference_value)
var/icon/icon
var/icon_state
@@ -31,7 +30,7 @@
else
CRASH("[create_icon_of] is an invalid preference value (from [preference_key]:[preference_value]).")
to_insert[preference.get_spritesheet_key(preference_value)] = list(icon, icon_state)
to_insert[preference.get_spritesheet_key(preference.serialize(preference_value))] = list(icon, icon_state)
for (var/spritesheet_key in to_insert)
var/list/inserting = to_insert[spritesheet_key]

View File

@@ -1,28 +1,16 @@
/proc/generate_values_for_underwear(list/accessory_list, list/icons, color, icon_offset) //SKYRAT EDIT CHANGE - Colorable Undershirt/Socks
var/icon/lower_half = icon('icons/blanks/32x32.dmi', "nothing")
/proc/generate_underwear_icon(datum/sprite_accessory/accessory, icon/base_icon, color, icon_offset = 0) //SKYRAT EDIT CHANGE : adds icon_offset - Colorable Undershirt/Socks
var/icon/final_icon = new(base_icon)
for (var/icon in icons)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', icon), ICON_OVERLAY)
var/list/values = list()
for (var/accessory_name in accessory_list)
var/icon/icon_with_socks = new(lower_half)
var/datum/sprite_accessory/accessory = accessory_list[accessory_name]
//SKYRAT EDIT CHANGE
if (accessory_name != "Nude" && accessory)
var/icon/accessory_icon = icon(accessory.icon, accessory.icon_state)
//SKYRAT EDIT CHANGE END
if (!isnull(accessory))
var/icon/accessory_icon = icon(accessory.icon, accessory.icon_state) // SKYRAT EDIT CHANGE: ORIGINAL - var/icon/accessory_icon = icon('icons/mob/clothing/underwear.dmi', accessory.icon_state)
if (color && !accessory.use_static)
accessory_icon.Blend(color, ICON_MULTIPLY)
icon_with_socks.Blend(accessory_icon, ICON_OVERLAY)
icon_with_socks.Crop(10, 1+icon_offset, 22, 13+icon_offset) //SKYRAT EDIT CHANGE - Colorable Undershirt/Socks
final_icon.Blend(accessory_icon, ICON_OVERLAY)
icon_with_socks.Scale(32, 32)
final_icon.Crop(10, 1+icon_offset, 22, 13+icon_offset) //SKYRAT EDIT CHANGE : adds icon_offset - Colorable Undershirt/Socks
final_icon.Scale(32, 32)
values[accessory_name] = icon_with_socks
return values
return final_icon
/// Backpack preference
/datum/preference/choiced/backpack
@@ -33,22 +21,37 @@
should_generate_icons = TRUE
/datum/preference/choiced/backpack/init_possible_values()
var/list/values = list()
return list(
GBACKPACK,
GSATCHEL,
LSATCHEL,
GDUFFELBAG,
DBACKPACK,
DSATCHEL,
DDUFFELBAG,
)
values[GBACKPACK] = /obj/item/storage/backpack
values[GSATCHEL] = /obj/item/storage/backpack/satchel
values[LSATCHEL] = /obj/item/storage/backpack/satchel/leather
values[GDUFFELBAG] = /obj/item/storage/backpack/duffelbag
/datum/preference/choiced/backpack/icon_for(value)
switch (value)
if (GBACKPACK)
return /obj/item/storage/backpack
if (GSATCHEL)
return /obj/item/storage/backpack/satchel
if (LSATCHEL)
return /obj/item/storage/backpack/satchel/leather
if (GDUFFELBAG)
return /obj/item/storage/backpack/duffelbag
// In a perfect world, these would be your department's backpack.
// However, this doesn't factor in assistants, or no high slot, and would
// also increase the spritesheet size a lot.
// I play medical doctor, and so medical doctor you get.
values[DBACKPACK] = /obj/item/storage/backpack/medic
values[DSATCHEL] = /obj/item/storage/backpack/satchel/med
values[DDUFFELBAG] = /obj/item/storage/backpack/duffelbag/med
return values
if (DBACKPACK)
return /obj/item/storage/backpack/medic
if (DSATCHEL)
return /obj/item/storage/backpack/satchel/med
if (DDUFFELBAG)
return /obj/item/storage/backpack/duffelbag/med
/datum/preference/choiced/backpack/apply_to_human(mob/living/carbon/human/target, value)
target.backpack = value
@@ -62,12 +65,17 @@
should_generate_icons = TRUE
/datum/preference/choiced/jumpsuit/init_possible_values()
var/list/values = list()
return list(
PREF_SUIT,
PREF_SKIRT,
)
values[PREF_SUIT] = /obj/item/clothing/under/color/grey
values[PREF_SKIRT] = /obj/item/clothing/under/color/jumpskirt/grey
return values
/datum/preference/choiced/jumpsuit/icon_for(value)
switch (value)
if (PREF_SUIT)
return /obj/item/clothing/under/color/grey
if (PREF_SKIRT)
return /obj/item/clothing/under/color/jumpskirt/grey
/datum/preference/choiced/jumpsuit/apply_to_human(mob/living/carbon/human/target, value)
target.jumpsuit_style = value
@@ -81,7 +89,17 @@
should_generate_icons = TRUE
/datum/preference/choiced/socks/init_possible_values()
return generate_values_for_underwear(GLOB.socks_list, list("human_r_leg", "human_l_leg"))
return assoc_to_keys_features(GLOB.socks_list)
/datum/preference/choiced/socks/icon_for(value)
var/static/icon/lower_half
if (isnull(lower_half))
lower_half = icon('icons/blanks/32x32.dmi', "nothing")
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY)
return generate_underwear_icon(GLOB.socks_list[value], lower_half)
/datum/preference/choiced/socks/apply_to_human(mob/living/carbon/human/target, value)
target.socks = value
@@ -95,7 +113,12 @@
should_generate_icons = TRUE
/datum/preference/choiced/undershirt/init_possible_values()
var/icon/body = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg")
return assoc_to_keys_features(GLOB.undershirt_list)
/datum/preference/choiced/undershirt/icon_for(value)
var/static/icon/body
if (isnull(body))
body = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg")
body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY)
body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_arm"), ICON_OVERLAY)
body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_arm"), ICON_OVERLAY)
@@ -103,20 +126,15 @@
body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_hand"), ICON_OVERLAY)
body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_chest_m"), ICON_OVERLAY)
var/list/values = list()
for (var/accessory_name in GLOB.undershirt_list)
var/icon/icon_with_undershirt = icon(body)
if (accessory_name != "Nude")
var/datum/sprite_accessory/accessory = GLOB.undershirt_list[accessory_name]
icon_with_undershirt.Blend(icon('icons/mob/clothing/underwear.dmi', accessory.icon_state), ICON_OVERLAY)
if (value != "Nude")
var/datum/sprite_accessory/accessory = GLOB.undershirt_list[value]
icon_with_undershirt.Blend(icon(accessory.icon, accessory.icon_state), ICON_OVERLAY) // SKYRAT EDIT CHANGE: ORIGINAL - icon_with_undershirt.Blend(icon('icons/mob/clothing/underwear.dmi', accessory.icon_state), ICON_OVERLAY)
icon_with_undershirt.Crop(9, 9, 23, 23)
icon_with_undershirt.Crop(10, 11, 22, 23) // SKYRAT EDIT CHANGE : ORIGINAL - icon_with_undershirt.Crop(9, 9, 23, 23)
icon_with_undershirt.Scale(32, 32)
values[accessory_name] = icon_with_undershirt
return values
return icon_with_undershirt
/datum/preference/choiced/undershirt/apply_to_human(mob/living/carbon/human/target, value)
target.undershirt = value
@@ -130,7 +148,18 @@
should_generate_icons = TRUE
/datum/preference/choiced/underwear/init_possible_values()
return generate_values_for_underwear(GLOB.underwear_list, list("human_chest_m", "human_r_leg", "human_l_leg"), COLOR_ALMOST_BLACK)
return assoc_to_keys_features(GLOB.underwear_list)
/datum/preference/choiced/underwear/icon_for(value)
var/static/icon/lower_half
if (isnull(lower_half))
lower_half = icon('icons/blanks/32x32.dmi', "nothing")
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_chest_m"), ICON_OVERLAY)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY)
return generate_underwear_icon(GLOB.underwear_list[value], lower_half, COLOR_ALMOST_BLACK, icon_offset = 5) // SKYRAT EDIT CHANGE : ICON_OFFSET
/datum/preference/choiced/underwear/apply_to_human(mob/living/carbon/human/target, value)
target.underwear = value

View File

@@ -71,12 +71,10 @@
)
/datum/preference/choiced/ghost_form/init_possible_values()
var/list/values = list()
return assoc_to_keys(ghost_forms)
for (var/ghost_form in ghost_forms)
values[ghost_form] = icon('icons/mob/simple/mob.dmi', ghost_form)
return values
/datum/preference/choiced/ghost_form/icon_for(value)
return icon('icons/mob/simple/mob.dmi', value)
/datum/preference/choiced/ghost_form/create_default_value()
return "ghost"

View File

@@ -5,14 +5,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/glasses/init_possible_values()
var/list/values = list()
return assoc_to_keys(GLOB.nearsighted_glasses) + "Random"
values["Random"] = icon('icons/effects/random_spawners.dmi', "questionmark")
for(var/glass_design in GLOB.nearsighted_glasses - "Random")
values[glass_design] = icon('icons/obj/clothing/glasses.dmi', "glasses_[lowertext(glass_design)]")
return values
/datum/preference/choiced/glasses/icon_for(value)
if (value == "Random")
return icon('icons/effects/random_spawners.dmi', "questionmark")
else
return icon('icons/obj/clothing/glasses.dmi', "glasses_[lowertext(value)]")
/datum/preference/choiced/glasses/is_accessible(datum/preferences/preferences)
if (!..(preferences))

View File

@@ -1,26 +1,24 @@
/proc/generate_possible_values_for_sprite_accessories_on_head(accessories)
var/list/values = possible_values_for_sprite_accessory_list(accessories)
var/icon/head_icon = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_head_m")
/proc/generate_icon_with_head_accessory(datum/sprite_accessory/sprite_accessory)
var/static/icon/head_icon
if (isnull(head_icon))
head_icon = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_head_m")
head_icon.Blend(skintone2hex("caucasian1"), ICON_MULTIPLY)
for (var/name in values)
var/datum/sprite_accessory/accessory = accessories[name]
if (accessory == null || accessory.icon_state == null)
continue
if (isnull(sprite_accessory))
return head_icon
ASSERT(istype(sprite_accessory))
var/icon/final_icon = new(head_icon)
var/icon/beard_icon = values[name]
beard_icon.Blend(COLOR_DARK_BROWN, ICON_MULTIPLY)
final_icon.Blend(beard_icon, ICON_OVERLAY)
var/icon/head_accessory_icon = icon(sprite_accessory.icon, sprite_accessory.icon_state)
head_accessory_icon.Blend(COLOR_DARK_BROWN, ICON_MULTIPLY)
final_icon.Blend(head_accessory_icon, ICON_OVERLAY)
final_icon.Crop(10, 19, 22, 31)
final_icon.Scale(32, 32)
values[name] = final_icon
return values
return final_icon
/datum/preference/color/eye_color
priority = PREFERENCE_PRIORITY_BODYPARTS
@@ -64,7 +62,10 @@
relevant_head_flag = HEAD_FACIAL_HAIR
/datum/preference/choiced/facial_hairstyle/init_possible_values()
return generate_possible_values_for_sprite_accessories_on_head(GLOB.facial_hairstyles_list)
return assoc_to_keys_features(GLOB.facial_hairstyles_list)
/datum/preference/choiced/facial_hairstyle/icon_for(value)
return generate_icon_with_head_accessory(GLOB.facial_hairstyles_list[value])
/datum/preference/choiced/facial_hairstyle/apply_to_human(mob/living/carbon/human/target, value)
target.set_facial_hairstyle(value, update = FALSE)
@@ -137,7 +138,10 @@
relevant_head_flag = HEAD_HAIR
/datum/preference/choiced/hairstyle/init_possible_values()
return generate_possible_values_for_sprite_accessories_on_head(GLOB.hairstyles_list)
return assoc_to_keys_features(GLOB.hairstyles_list)
/datum/preference/choiced/hairstyle/icon_for(value)
return generate_icon_with_head_accessory(GLOB.hairstyles_list[value])
/datum/preference/choiced/hairstyle/apply_to_human(mob/living/carbon/human/target, value)
target.set_hairstyle(value, update = FALSE)

View File

@@ -6,9 +6,12 @@
should_generate_icons = TRUE
/datum/preference/choiced/ethereal_color/init_possible_values()
var/list/values = list()
return assoc_to_keys(GLOB.color_list_ethereal)
var/icon/ethereal_base = icon('icons/mob/human/species/ethereal/bodyparts.dmi', "ethereal_head")
/datum/preference/choiced/ethereal_color/icon_for(value)
var/static/icon/ethereal_base
if (isnull(ethereal_base))
ethereal_base = icon('icons/mob/human/species/ethereal/bodyparts.dmi', "ethereal_head")
ethereal_base.Blend(icon('icons/mob/human/species/ethereal/bodyparts.dmi', "ethereal_chest"), ICON_OVERLAY)
ethereal_base.Blend(icon('icons/mob/human/species/ethereal/bodyparts.dmi', "ethereal_l_arm"), ICON_OVERLAY)
ethereal_base.Blend(icon('icons/mob/human/species/ethereal/bodyparts.dmi', "ethereal_r_arm"), ICON_OVERLAY)
@@ -20,14 +23,9 @@
ethereal_base.Scale(64, 64)
ethereal_base.Crop(15, 64, 15 + 31, 64 - 31)
for (var/name in GLOB.color_list_ethereal)
var/color = GLOB.color_list_ethereal[name]
var/icon/icon = new(ethereal_base)
icon.Blend(color, ICON_MULTIPLY)
values[name] = icon
return values
icon.Blend(GLOB.color_list_ethereal[value], ICON_MULTIPLY)
return icon
/datum/preference/choiced/ethereal_color/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["ethcolor"] = GLOB.color_list_ethereal[value]

View File

@@ -1,21 +1,20 @@
/* SKYRAT EDIT REMOVAL
/proc/generate_lizard_side_shots(list/sprite_accessories, key, include_snout = TRUE)
var/list/values = list()
/proc/generate_lizard_side_shot(datum/sprite_accessory/sprite_accessory, key, include_snout = TRUE)
var/static/icon/lizard
var/static/icon/lizard_with_snout
var/icon/lizard = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_head", EAST)
if (isnull(lizard))
lizard = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_head", EAST)
var/icon/eyes = icon('icons/mob/human/human_face.dmi', "eyes", EAST)
eyes.Blend(COLOR_GRAY, ICON_MULTIPLY)
lizard.Blend(eyes, ICON_OVERLAY)
if (include_snout)
lizard.Blend(icon('icons/mob/human/species/lizard/lizard_misc.dmi', "m_snout_round_ADJ", EAST), ICON_OVERLAY)
lizard_with_snout = icon(lizard)
lizard_with_snout.Blend(icon('icons/mob/human/species/lizard/lizard_misc.dmi', "m_snout_round_ADJ", EAST), ICON_OVERLAY)
for (var/name in sprite_accessories)
var/datum/sprite_accessory/sprite_accessory = sprite_accessories[name]
var/icon/final_icon = include_snout ? icon(lizard_with_snout) : icon(lizard)
var/icon/final_icon = icon(lizard)
if (sprite_accessory.icon_state != "none")
if (!isnull(sprite_accessory))
var/icon/accessory_icon = icon(sprite_accessory.icon, "m_[key]_[sprite_accessory.icon_state]_ADJ", EAST)
final_icon.Blend(accessory_icon, ICON_OVERLAY)
@@ -23,9 +22,7 @@
final_icon.Scale(32, 32)
final_icon.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
values[name] = final_icon
return values
return final_icon
/datum/preference/choiced/lizard_body_markings
savefile_key = "feature_lizard_body_markings"
@@ -36,14 +33,12 @@
relevant_mutant_bodypart = "body_markings"
/datum/preference/choiced/lizard_body_markings/init_possible_values()
var/list/values = list()
return assoc_to_keys_features(GLOB.body_markings_list)
var/icon/lizard = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m")
/datum/preference/choiced/lizard_body_markings/icon_for(value)
var/datum/sprite_accessory/sprite_accessory = GLOB.body_markings_list[value]
for (var/name in GLOB.body_markings_list)
var/datum/sprite_accessory/sprite_accessory = GLOB.body_markings_list[name]
var/icon/final_icon = icon(lizard)
var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m")
if (sprite_accessory.icon_state != "none")
var/icon/body_markings_icon = icon(
@@ -58,9 +53,7 @@
final_icon.Scale(26, 32)
final_icon.Crop(-2, 1, 29, 32)
values[name] = final_icon
return values
return final_icon
/datum/preference/choiced/lizard_body_markings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["body_markings"] = value
@@ -73,7 +66,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_frills/init_possible_values()
return generate_lizard_side_shots(GLOB.frills_list, "frills")
return assoc_to_keys_features(GLOB.frills_list)
/datum/preference/choiced/lizard_frills/icon_for(value)
return generate_lizard_side_shot(GLOB.frills_list[value], "frills")
/datum/preference/choiced/lizard_frills/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["frills"] = value
@@ -86,7 +82,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_horns/init_possible_values()
return generate_lizard_side_shots(GLOB.horns_list, "horns")
return assoc_to_keys_features(GLOB.horns_list)
/datum/preference/choiced/lizard_horns/icon_for(value)
return generate_lizard_side_shot(GLOB.horns_list[value], "horns")
/datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["horns"] = value
@@ -111,7 +110,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_snout/init_possible_values()
return generate_lizard_side_shots(GLOB.snouts_list, "snout", include_snout = FALSE)
return assoc_to_keys_features(GLOB.snouts_list)
/datum/preference/choiced/lizard_snout/icon_for(value)
return generate_lizard_side_shot(GLOB.snouts_list[value], "snout", include_snout = FALSE)
/datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["snout"] = value

View File

@@ -7,24 +7,24 @@
should_generate_icons = TRUE
/datum/preference/choiced/moth_antennae/init_possible_values()
var/list/values = list()
return assoc_to_keys_features(GLOB.moth_antennae_list)
var/icon/moth_head = icon('icons/mob/human/species/moth/bodyparts.dmi', "moth_head")
moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes"), ICON_OVERLAY)
/datum/preference/choiced/moth_antennae/icon_for(value)
var/static/icon/moth_head
for (var/antennae_name in GLOB.moth_antennae_list)
var/datum/sprite_accessory/antennae = GLOB.moth_antennae_list[antennae_name]
if(antennae.locked)
continue
if (isnull(moth_head))
moth_head = icon('icons/mob/human/species/moth/bodyparts.dmi', "moth_head")
moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY)
moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY)
var/datum/sprite_accessory/antennae = GLOB.moth_antennae_list[value]
var/icon/icon_with_antennae = new(moth_head)
icon_with_antennae.Blend(icon(antennae.icon, "m_moth_antennae_[antennae.icon_state]_FRONT"), ICON_OVERLAY)
icon_with_antennae.Scale(64, 64)
icon_with_antennae.Crop(15, 64, 15 + 31, 64 - 31)
values[antennae.name] = icon_with_antennae
return values
return icon_with_antennae
/datum/preference/choiced/moth_antennae/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_antennae"] = value
@@ -38,34 +38,34 @@
relevant_mutant_bodypart = "moth_markings"
/datum/preference/choiced/moth_markings/init_possible_values()
var/list/values = list()
return assoc_to_keys_features(GLOB.moth_markings_list)
var/icon/moth_body = icon('icons/blanks/32x32.dmi', "nothing")
moth_body.Blend(icon('icons/mob/human/species/moth/moth_wings.dmi', "m_moth_wings_plain_BEHIND"), ICON_OVERLAY)
var/list/body_parts = list(
/datum/preference/choiced/moth_markings/icon_for(value)
var/static/list/body_parts = list(
/obj/item/bodypart/head/moth,
/obj/item/bodypart/chest/moth,
/obj/item/bodypart/arm/left/moth,
/obj/item/bodypart/arm/right/moth,
)
for (var/obj/item/bodypart/body_part in body_parts)
var/gender = (initial(body_part.is_dimorphic)) ? "_m" : ""
moth_body.Blend(icon('icons/mob/human/species/moth/bodyparts.dmi', "moth_[body_part][gender]"), ICON_OVERLAY)
var/static/icon/moth_body
if (isnull(moth_body))
moth_body = icon('icons/blanks/32x32.dmi', "nothing")
moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes"), ICON_OVERLAY)
moth_body.Blend(icon('icons/mob/human/species/moth/moth_wings.dmi', "m_moth_wings_plain_BEHIND"), ICON_OVERLAY)
for (var/markings_name in GLOB.moth_markings_list)
var/datum/sprite_accessory/markings = GLOB.moth_markings_list[markings_name]
if(markings.locked)
continue
for (var/obj/item/bodypart/body_part as anything in body_parts)
moth_body.Blend(icon('icons/mob/human/species/moth/bodyparts.dmi', initial(body_part.icon_state)), ICON_OVERLAY)
moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY)
moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY)
var/datum/sprite_accessory/markings = GLOB.moth_markings_list[value]
var/icon/icon_with_markings = new(moth_body)
if (markings_name != "None")
for (var/body_part in body_parts)
var/icon/body_part_icon = icon(markings.icon, "[markings.icon_state]_[body_part]")
if (value != "None")
for (var/obj/item/bodypart/body_part as anything in body_parts)
var/icon/body_part_icon = icon(markings.icon, "[markings.icon_state]_[initial(body_part.body_zone)]")
body_part_icon.Crop(1, 1, 32, 32)
icon_with_markings.Blend(body_part_icon, ICON_OVERLAY)
@@ -76,9 +76,7 @@
icon_with_markings.Scale(64, 64)
icon_with_markings.Crop(15, 64, 15 + 31, 64 - 31)
values[markings.name] = icon_with_markings
return values
return icon_with_markings
/datum/preference/choiced/moth_markings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_markings"] = value
@@ -91,11 +89,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/moth_wings/init_possible_values()
return possible_values_for_sprite_accessory_list_for_body_part(
GLOB.moth_wings_list,
"moth_wings",
list("BEHIND", "FRONT"),
)
return assoc_to_keys_features(GLOB.moth_wings_list)
/datum/preference/choiced/moth_wings/icon_for(value)
var/datum/sprite_accessory/moth_wings = GLOB.moth_wings_list[value]
var/icon/final_icon = icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_BEHIND")
final_icon.Blend(icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_FRONT"), ICON_OVERLAY)
return final_icon
/datum/preference/choiced/moth_wings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_wings"] = value

View File

@@ -8,16 +8,13 @@
should_generate_icons = TRUE
/datum/preference/choiced/pod_hair/init_possible_values()
var/list/values = list()
return assoc_to_keys_features(GLOB.pod_hair_list)
var/icon/pod_head = icon('icons/mob/human/bodyparts_greyscale.dmi', "pod_head_m")
/datum/preference/choiced/pod_hair/icon_for(value)
var/datum/sprite_accessory/pod_hair = GLOB.pod_hair_list[value]
for (var/pod_name in GLOB.pod_hair_list)
var/datum/sprite_accessory/pod_hair = GLOB.pod_hair_list[pod_name]
if(pod_hair.locked)
continue
var/icon/icon_with_hair = icon('icons/mob/human/bodyparts_greyscale.dmi', "pod_head_m")
var/icon/icon_with_hair = new(pod_head)
var/icon/icon_adj = icon(pod_hair.icon, "m_pod_hair_[pod_hair.icon_state]_ADJ")
var/icon/icon_front = icon(pod_hair.icon, "m_pod_hair_[pod_hair.icon_state]_FRONT")
icon_adj.Blend(icon_front, ICON_OVERLAY)
@@ -26,9 +23,7 @@
icon_with_hair.Crop(15, 64, 15 + 31, 64 - 31)
icon_with_hair.Blend(COLOR_GREEN, ICON_MULTIPLY)
values[pod_hair.name] = icon_with_hair
return values
return icon_with_hair
/datum/preference/choiced/pod_hair/create_default_value()
return pick(assoc_to_keys_features(GLOB.pod_hair_list))

View File

@@ -11,12 +11,14 @@
return "Inoculated" //eh, have em try out the mechanic first
/datum/preference/choiced/vampire_status/init_possible_values()
var/list/values = list()
return list("Inoculated", "Outcast")
values["Inoculated"] = icon('icons/obj/drinks/drinks.dmi', "bloodglass")
values["Outcast"] = icon('icons/obj/medical/bloodpack.dmi', "generic_bloodpack")
return values
/datum/preference/choiced/vampire_status/icon_for(value)
switch (value)
if ("Inoculated")
return icon('icons/obj/drinks/drinks.dmi', "bloodglass")
if ("Outcast")
return icon('icons/obj/medical/bloodpack.dmi', "generic_bloodpack")
///list that stores a vampire house name for each department
GLOBAL_LIST_EMPTY(vampire_houses)

View File

@@ -6,18 +6,16 @@
should_generate_icons = TRUE
/datum/preference/choiced/ui_style/init_possible_values()
var/list/values = list()
return assoc_to_keys(GLOB.available_ui_styles)
for (var/style in GLOB.available_ui_styles)
var/icon/icons = GLOB.available_ui_styles[style]
/datum/preference/choiced/ui_style/icon_for(value)
var/icon/icons = GLOB.available_ui_styles[value]
var/icon/icon = icon(icons, "hand_r")
icon.Crop(1, 1, world.icon_size * 2, world.icon_size)
icon.Blend(icon(icons, "hand_l"), ICON_OVERLAY, world.icon_size)
values[style] = icon
return values
return icon
/datum/preference/choiced/ui_style/create_default_value()
return GLOB.available_ui_styles[1]

View File

@@ -258,7 +258,7 @@
/obj/item/modular_computer/pda/shaftminer
name = "shaft miner PDA"
greyscale_config = /datum/greyscale_config/tablet/stripe_thick
greyscale_colors = "#927444#D6B328#6C3BA1"
greyscale_colors = "#927444#8b4c31#4c202d"
starting_programs = list(
/datum/computer_file/program/skill_tracker,
)

View File

@@ -49,3 +49,29 @@
continue
TEST_ASSERT(!isnull(preference.main_feature_name), "Preference [preference_type] does not have a main_feature_name set!")
/// Validates that every choiced preference with should_generate_icons implements icon_for,
/// and that every one that doesn't, doesn't.
/datum/unit_test/preferences_should_generate_icons_sanity
/datum/unit_test/preferences_should_generate_icons_sanity/Run()
for (var/preference_type in GLOB.preference_entries)
var/datum/preference/choiced/choiced_preference = GLOB.preference_entries[preference_type]
if (!istype(choiced_preference) || choiced_preference.abstract_type == preference_type)
continue
var/list/values = choiced_preference.get_choices()
if (choiced_preference.should_generate_icons)
for (var/value in values)
var/icon = choiced_preference.icon_for(value)
TEST_ASSERT(istype(icon, /icon) || ispath(icon), "[preference_type] gave [icon] as an icon for [value], which is not a valid value")
else
var/errored = FALSE
try
choiced_preference.icon_for(values[1])
catch
errored = TRUE
TEST_ASSERT(errored, "[preference_type] implemented icon_for, but does not have should_generate_icons = TRUE")

View File

@@ -108,7 +108,7 @@
savefile_identifier = PREFERENCE_CHARACTER
/// Path to the default sprite accessory
var/datum/sprite_accessory/default_accessory_type
var/datum/sprite_accessory/default_accessory_type = /datum/sprite_accessory/blank
/// Path to the corresponding /datum/preference/toggle to check if part is enabled.
var/datum/preference/toggle/type_to_check
/// Generates icons from the provided mutant bodypart for use in icon-enabled selection boxes in the prefs window.
@@ -124,6 +124,15 @@
var/part_enabled = is_part_enabled(preferences)
return (passed_initial_check || overriding) && part_enabled
// icons are cached
/datum/preference/choiced/mutant_choice/icon_for(value)
if(!should_generate_icons)
// because of the way the unit tests are set up, we need this to crash here
CRASH("`icon_for()` was not implemented for [type], even though should_generate_icons = TRUE!")
var/list/cached_icons = get_choices()
return cached_icons[value]
/// Allows for dynamic assigning of icon states.
/datum/preference/choiced/mutant_choice/proc/generate_icon_state(datum/sprite_accessory/sprite_accessory, original_icon_state)
return original_icon_state
@@ -160,7 +169,7 @@
return list_of_accessories
/datum/preference/choiced/mutant_choice/create_default_value()
return initial(default_accessory_type?.name) || "None"
return initial(default_accessory_type.name)
/**
* Is this part enabled by the player?
@@ -204,6 +213,9 @@
if(!bodypart_is_visible)
value = create_default_value()
if(value == "None")
return bodypart_is_visible
if(!target.dna.mutant_bodyparts[relevant_mutant_bodypart])
target.dna.mutant_bodyparts[relevant_mutant_bodypart] = list(MUTANT_INDEX_NAME = value, MUTANT_INDEX_COLOR_LIST = list("#FFFFFF", "#FFFFFF", "#FFFFFF"), MUTANT_INDEX_EMISSIVE_LIST = list(FALSE, FALSE, FALSE))
return bodypart_is_visible

View File

@@ -1,6 +1,3 @@
/datum/preference/choiced/socks/init_possible_values()
return generate_values_for_underwear(GLOB.socks_list, list("human_r_leg", "human_l_leg"), COLOR_ALMOST_BLACK, 0)
/datum/preference/choiced/socks/compile_constant_data()
var/list/data = ..()
@@ -16,9 +13,6 @@
var/datum/species/species = new species_type
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/choiced/undershirt/init_possible_values()
return generate_values_for_underwear(GLOB.undershirt_list, list("human_chest_m", "human_r_arm", "human_l_arm", "human_r_leg", "human_l_leg", "human_r_hand", "human_l_hand"), COLOR_ALMOST_BLACK, 10)
/datum/preference/choiced/undershirt/compile_constant_data()
var/list/data = ..()
@@ -34,9 +28,6 @@
var/datum/species/species = new species_type
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/choiced/underwear/init_possible_values()
return generate_values_for_underwear(GLOB.underwear_list, list("human_chest_m", "human_r_leg", "human_l_leg"), COLOR_ALMOST_BLACK, 5)
/datum/preference/choiced/underwear/is_accessible(datum/preferences/preferences)
if (!..(preferences))
return FALSE

View File

@@ -68,7 +68,7 @@
return (savefile_key in species.get_features())
/datum/preference/choiced/genital/create_default_value()
return initial(default_accessory_type?.name) || "None"
return initial(default_accessory_type.name)
/datum/preference/choiced/genital/init_possible_values()
return assoc_to_keys_features(GLOB.sprite_accessories[relevant_mutant_bodypart])

View File

@@ -81,7 +81,6 @@
/datum/preference/toggle/mutant_toggle/body_markings/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
return FALSE
/datum/preference/choiced/mutant_choice/body_markings
savefile_key = "feature_body_markings"
relevant_mutant_bodypart = "body_markings"
@@ -95,7 +94,6 @@
/datum/preference/choiced/mutant_choice/body_markings/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
return FALSE
/datum/preference/tri_color/body_markings
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
@@ -124,7 +122,6 @@
/datum/preference/tri_bool/body_markings/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
return FALSE
/// Tails
/datum/preference/toggle/mutant_toggle/tail