Refactors unique_reskin, deletes retool kit (#93775)

## About The Pull Request

Closes #93635

`unique_reskin` is no longer a list on `/item`, now `/datum/atom_skin`

The actual reskinning behavior has been moved out to
`/datum/component/reskinable_item`

PKC reskinning is now handled via alt-click reskin, rather than via the
retooling kit. The retooling kit has been removed.
There's no limit on how many times you can reskin your PKC (though
perhaps we limit it to one reskin and keep the retooling kit as a way to
allow a miner to reskin it a second time?)

The Ashen Skull unique reskin is still a trophy, and instead unlocks its
unique reskin option in the alt-click radial.

## Why It's Good For The Game

I'm unsure why the retooling kit exists on its own, when it's relatively
cheap and just performs the behavior of alt-click reskinning.

So to keep it consistent with all other forms of reskinning I've just
made it baseline. To accomplish that I refactored reskinning.

The new form of reskinning allows for greater potential in adding
reskins, allowing far more than just an icon state change. Also we can
put it on turfs and mobs and structures now which is cool I guess

There's also the added benefit of being able to see an item's reskins
without needing to instantiate it, which the loadout menu uses to great
effect.

## Changelog

🆑 Melbert
refactor: Refactored item reskinning (the alt-click way), report any
oddities with that
del: Deleted the crusher retool kit, now you can just reskin your
crusher with alt-click. The Skull skin is still locked behind having the
Ashen Skull trophy applied.
fix: Stunswords no longer have an incorrect lore blurb
fix: Fixed loadout item reskinning's UI
/🆑
This commit is contained in:
MrMelbert
2025-11-30 19:31:29 -07:00
committed by GitHub
parent 693d94d930
commit 6ebfbccebb
34 changed files with 757 additions and 489 deletions
+3 -5
View File
@@ -24,14 +24,12 @@
#define BLOCKS_CONSTRUCTION_DIR (1<<10)
/// Can we ignore density when building on this object (for example, directional windows and grilles)
#define IGNORE_DENSITY (1<<11)
/// We can reskin this item infinitely
#define INFINITE_RESKIN (1<<12)
/// Can this object conduct electricity
#define CONDUCTS_ELECTRICITY (1<<13)
#define CONDUCTS_ELECTRICITY (1<<12)
/// Atoms don't spawn anything when deconstructed (they just vanish)
#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<14)
#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<13)
/// Flag which tells an object to hang onto an support atom on late initialize. Usefull only during mapload and supported by some atoms only
#define MOUNT_ON_LATE_INITIALIZE (1<<15)
#define MOUNT_ON_LATE_INITIALIZE (1<<14)
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
-2
View File
@@ -164,8 +164,6 @@
#define LOADOUT_FLAG_GREYSCALING_ALLOWED (1<<2)
/// Allows the item to be renamed by the player.
#define LOADOUT_FLAG_ALLOW_NAMING (1<<3)
/// Allows the item to be reskinned by the player. Only applicable to items with unique_reskin defined.
#define LOADOUT_FLAG_ALLOW_RESKIN (1<<4)
// Loadout item info keys
// Changing these will break existing loadouts
+18
View File
@@ -0,0 +1,18 @@
/// Global list of available atom skins
GLOBAL_LIST_INIT_TYPED(atom_skins, /datum/atom_skin, init_subtypes_w_path_keys(/datum/atom_skin))
/// Sets the atom's varname to newvalue if newvalue is not null, otherwise resets it to its initial value if resetcondition is true
#define APPLY_VAR_OR_RESET_INITIAL(atom, varname, newvalue, resetcondition) \
if(newvalue) {atom.##varname = (##newvalue) } else if(resetcondition) { atom.##varname = initial(atom.##varname) }
/// Sets the atom's varname to newvalue if newvalue is not null, otherwise sets it to resetvalue if resetcondition is true
#define APPLY_VAR_OR_RESET_TO(atom, varname, newvalue, resetcondition, resetvalue) \
if(newvalue) {atom.##varname = (##newvalue) } else if(resetcondition) { atom.##varname = (resetvalue) }
/// Resets the atom's varname to its initial value if oldvalue is not null
#define RESET_INITIAL_IF_SET(atom, varname, oldvalue) \
if(oldvalue) { atom.##varname = initial(atom.##varname) }
/// Sets the atom's varname to resetvalue if oldvalue is not null
#define RESET_TO_IF_SET(atom, varname, oldvalue, resetvalue) \
if(oldvalue) { atom.##varname = (resetvalue) }
+5 -13
View File
@@ -137,29 +137,21 @@
for(var/atom/req_atom as anything in recipe.structures)
atom_list |= req_atom
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/// Creates every subtype of prototype (excluding prototype and abstract types) and adds it to list L.
/// If no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
for(var/path in valid_subtypesof(prototype))
L += new path()
return L
//returns a list of paths to every subtype of prototype (excluding prototype)
//if no list/L is provided, one is created.
/proc/init_paths(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L+= path
return L
/// Functions like init_subtypes, but uses the subtype's path as a key for easy access
/// If no list/L is provided, one is created.
/proc/init_subtypes_w_path_keys(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
for(var/path in valid_subtypesof(prototype))
L[path] = new path()
return L
-1
View File
@@ -361,7 +361,6 @@ DEFINE_BITFIELD(obj_flags, list(
"BLOCKS_CONSTRUCTION" = BLOCKS_CONSTRUCTION,
"BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR,
"IGNORE_DENSITY" = IGNORE_DENSITY,
"INFINITE_RESKIN" = INFINITE_RESKIN,
"CONDUCTS_ELECTRICITY" = CONDUCTS_ELECTRICITY,
"NO_DEBRIS_AFTER_DECONSTRUCTION" = NO_DEBRIS_AFTER_DECONSTRUCTION,
))
+2 -2
View File
@@ -60,9 +60,9 @@
add_to_dart(dart, user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/component/dart_insert/proc/on_reskin(datum/source, mob/user, skin)
/datum/component/dart_insert/proc/on_reskin(datum/source, skin)
SIGNAL_HANDLER
SEND_SIGNAL(parent, COMSIG_DART_INSERT_PARENT_RESKINNED)
SEND_SIGNAL(parent, COMSIG_DART_INSERT_PARENT_RESKINNED, skin)
/datum/component/dart_insert/proc/add_to_dart(obj/item/ammo_casing/dart, mob/user)
var/obj/projectile/dart_projectile = dart.loaded_projectile
+202
View File
@@ -0,0 +1,202 @@
/**
* ### Atom skin singleton datum
*
* Simple datum which holds information about a skin that can be applied to an atom.
*/
/datum/atom_skin
abstract_type = /datum/atom_skin
/// Required, name shown in the radial menu
var/preview_name
/// If true, changing the reskin also changes the base_icon_state of the atom
var/change_base_icon_state = FALSE
/// If true, changing the reskin also changes the inhand_icon_state of the atom
var/change_inhand_icon_state = FALSE
/// If true, unset vars are reset to their original values when applying this skin
var/reset_missing = TRUE
/// Optional, name to change the atom to when applied
var/new_name
/// Optional, description to change the atom to when applied
var/new_desc
/// Optional, icon to change the atom to when applied
var/new_icon
/// Optional, icon_state to change the atom to when applied
var/new_icon_state
/**
* Applies all relevant skin changes to the given atom
* Can be overridden to add additional behavior, such as registering signals or altering other vars.
*
* * apply_to: The atom to apply the skin to
*/
/datum/atom_skin/proc/apply(atom/apply_to)
SHOULD_CALL_PARENT(TRUE)
APPLY_VAR_OR_RESET_INITIAL(apply_to, name, new_name, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, desc, new_desc, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, icon, new_icon, reset_missing)
APPLY_VAR_OR_RESET_TO(apply_to, icon_state, new_icon_state, reset_missing, initial(apply_to.post_init_icon_state) || initial(apply_to.icon_state))
if(change_base_icon_state)
APPLY_VAR_OR_RESET_INITIAL(apply_to, base_icon_state, new_icon_state, reset_missing)
if(change_inhand_icon_state && isitem(apply_to))
var/obj/item/item_apply_to = apply_to
APPLY_VAR_OR_RESET_INITIAL(item_apply_to, inhand_icon_state, new_icon_state, reset_missing)
/**
* Resets all changes this skin would have made to the given atom
* Does not verify that the skin was actually applied to the atom beforehand.
* Can be overridden to add additional behavior, such as unregistering signals or altering other vars.
*
* * clear_from: The atom to clear the skin from
*/
/datum/atom_skin/proc/clear_skin(atom/clear_from)
SHOULD_CALL_PARENT(TRUE)
RESET_INITIAL_IF_SET(clear_from, name, new_name)
RESET_INITIAL_IF_SET(clear_from, desc, new_desc)
RESET_INITIAL_IF_SET(clear_from, icon, new_icon)
RESET_TO_IF_SET(clear_from, icon_state, new_icon_state, initial(clear_from.post_init_icon_state) || initial(clear_from.icon_state))
if(change_base_icon_state)
RESET_INITIAL_IF_SET(clear_from, base_icon_state, new_icon_state)
if(change_inhand_icon_state && isitem(clear_from))
var/obj/item/item_clear_from = clear_from
RESET_INITIAL_IF_SET(item_clear_from, inhand_icon_state, new_icon_state)
/**
* ### Reskinnable atoms
*
* Simple component which lets an atom be alt-clicked to open a radial menu to choose a new skin to apply.
*/
/datum/component/reskinable_item
dupe_mode = COMPONENT_DUPE_SELECTIVE
/// Base reskin type to pull options from - all subtypes except those blacklisted are valid options
VAR_PRIVATE/base_reskin_type
/// If TRUE, the reskin option is infinite-use. If FALSE, the component is deleted on use (so you're stuck with that skin).
VAR_PRIVATE/infinite_reskin = FALSE
/// List of subtypes of /datum/atom_skin that are not allowed to be used for this item
VAR_PRIVATE/list/blacklisted_subtypes
/// Currently applied skin preview_name
VAR_PRIVATE/current_skin
/datum/component/reskinable_item/Initialize(base_reskin_type, infinite = FALSE, initial_skin, list/blacklisted_subtypes = list())
if(!isatom(parent) || isarea(parent))
return COMPONENT_INCOMPATIBLE
src.base_reskin_type = base_reskin_type
src.infinite_reskin = infinite
src.blacklisted_subtypes = blacklisted_subtypes
if(initial_skin)
set_skin_by_name(initial_skin)
var/atom/atom_parent = parent
atom_parent.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1
/datum/component/reskinable_item/RegisterWithParent()
RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE_TAGS, PROC_REF(add_tags))
RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(add_context))
/datum/component/reskinable_item/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_CLICK_ALT)
UnregisterSignal(parent, COMSIG_ATOM_EXAMINE_TAGS)
UnregisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)
/datum/component/reskinable_item/CheckDupeComponent(datum/component/comp, base_reskin_type, infinite = FALSE, initial_skin, list/blacklisted_subtypes = list())
if(src.base_reskin_type != base_reskin_type)
return FALSE // new comp - though the alt-click behavior will collide
src.infinite_reskin = infinite
src.blacklisted_subtypes = blacklisted_subtypes
set_skin_by_name(initial_skin)
return TRUE // same comp
/datum/component/reskinable_item/proc/get_skins_by_name()
var/list/reskin_options = list()
for(var/datum/atom_skin/reskin_option as anything in valid_subtypesof(base_reskin_type) - blacklisted_subtypes)
reskin_options[reskin_option::preview_name] = reskin_option
return reskin_options
/datum/component/reskinable_item/proc/set_skin_by_name(input_name)
var/list/reskin_options = get_skins_by_name()
if(current_skin)
var/datum/atom_skin/previous_skin = GLOB.atom_skins[reskin_options[current_skin]]
previous_skin.clear_skin(parent)
if(input_name)
var/datum/atom_skin/reskin_to_apply = GLOB.atom_skins[reskin_options[input_name]]
reskin_to_apply.apply(parent)
current_skin = input_name
var/atom/atom_parent = parent
atom_parent.update_appearance()
if(isitem(parent))
var/obj/item/item_parent = parent
item_parent.update_slot_icon()
SEND_SIGNAL(parent, COMSIG_OBJ_RESKIN, input_name)
/datum/component/reskinable_item/proc/add_context(atom/source, list/context, obj/item/held_item, mob/user)
SIGNAL_HANDLER
context[SCREENTIP_CONTEXT_ALT_LMB] = "Reskin"
return CONTEXTUAL_SCREENTIP_SET
/datum/component/reskinable_item/proc/add_tags(atom/source, mob/user, list/tags)
SIGNAL_HANDLER
tags["reskinnable"] = "This item is able to be reskinned! Alt-Click to do so!"
/// Called when alt clicked and the item has unique reskin options
/datum/component/reskinable_item/proc/on_click_alt_reskin(datum/source, mob/user)
SIGNAL_HANDLER
if(!user.can_perform_action(parent, NEED_DEXTERITY))
return NONE
INVOKE_ASYNC(src, PROC_REF(reskin_obj), user)
return CLICK_ACTION_SUCCESS
/**
* Reskins object based on a user's choice
*
* Arguments:
* * user The mob choosing a reskin option
*/
/datum/component/reskinable_item/proc/reskin_obj(mob/user)
var/atom/atom_parent = parent
var/list/items = list()
for(var/reskin_name, reskin_typepath in get_skins_by_name())
var/datum/atom_skin/reskin = GLOB.atom_skins[reskin_typepath]
items[reskin_name] = image(icon = reskin.new_icon || atom_parent.icon, icon_state = reskin.new_icon_state || atom_parent.icon_state)
sort_list(items)
var/pick = show_radial_menu(user, parent, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE)
if(!pick || !items[pick])
return
set_skin_by_name(pick)
to_chat(user, span_info("[parent] is now skinned as '[pick].'"))
if(!infinite_reskin)
qdel(src)
/**
* Checks if we are allowed to interact with a radial menu for reskins
*
* Arguments:
* * user The mob interacting with the menu
*/
/datum/component/reskinable_item/proc/check_reskin_menu(mob/user)
if(QDELETED(parent))
return FALSE
if(user.incapacitated)
return FALSE
return TRUE
@@ -38,10 +38,6 @@
purchase_path = /obj/item/clothing/gloves/fingerless/punch_mitts
cost_per_order = 1000
/datum/orderable_item/mining/crusher_retool_kit
purchase_path = /obj/item/crusher_trophy/retool_kit
cost_per_order = 150
/datum/orderable_item/mining/resonator
purchase_path = /obj/item/resonator
cost_per_order = 710
+36 -11
View File
@@ -159,6 +159,41 @@
SIGNAL_HANDLER
set_linked_console(null)
// Disk skins
/datum/atom_skin/dna_disk
abstract_type = /datum/atom_skin/dna_disk
/datum/atom_skin/dna_disk/red
preview_name = "Red"
new_icon_state = "datadisk0"
/datum/atom_skin/dna_disk/dark_blue
preview_name = "Dark Blue"
new_icon_state = "datadisk1"
/datum/atom_skin/dna_disk/yellow
preview_name = "Yellow"
new_icon_state = "datadisk2"
/datum/atom_skin/dna_disk/black
preview_name = "Black"
new_icon_state = "datadisk3"
/datum/atom_skin/dna_disk/green
preview_name = "Green"
new_icon_state = "datadisk4"
/datum/atom_skin/dna_disk/purple
preview_name = "Purple"
new_icon_state = "datadisk5"
/datum/atom_skin/dna_disk/grey
preview_name = "Grey"
new_icon_state = "datadisk6"
/datum/atom_skin/dna_disk/light_blue
preview_name = "Light Blue"
new_icon_state = "datadisk7"
//Just for transferring between genetics machines.
/obj/item/disk/data
@@ -168,20 +203,10 @@
var/list/mutations = list()
var/max_mutations = 6
var/read_only = FALSE //Well,it's still a floppy disk
obj_flags = parent_type::obj_flags | INFINITE_RESKIN
unique_reskin = list(
"Red" = "datadisk0",
"Dark Blue" = "datadisk1",
"Yellow" = "datadisk2",
"Black" = "datadisk3",
"Green" = "datadisk4",
"Purple" = "datadisk5",
"Grey" = "datadisk6",
"Light Blue" = "datadisk7",
)
/obj/item/disk/data/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/dna_disk, infinite = TRUE)
icon_state = "datadisk[rand(0,7)]"
add_overlay("datadisk_gene")
if(length(genetic_makeup_buffer))
-27
View File
@@ -240,14 +240,6 @@
/// A lazylist used for applying fantasy values, contains the actual modification applied to a variable.
var/list/fantasy_modifications = null
/// Has the item been reskinned?
var/current_skin
/// List of options to reskin.
var/list/unique_reskin
/// If reskins change base icon state as well
var/unique_reskin_changes_base_icon_state = FALSE
/// If reskins change inhands as well
var/unique_reskin_changes_inhand = FALSE
/// Do we apply a click cooldown when resisting this object if it is restraining them?
var/resist_cooldown = CLICK_CD_BREAKOUT
@@ -283,9 +275,6 @@
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_ITEM, src)
setup_reskinning()
/obj/item/Destroy(force)
// This var exists as a weird proxy "owner" ref
// It's used in a few places. Stop using it, and optimially replace all uses please
@@ -300,19 +289,6 @@
return ..()
/obj/item/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(!unique_reskin)
return
if(current_skin && !(obj_flags & INFINITE_RESKIN))
return
context[SCREENTIP_CONTEXT_ALT_LMB] = "Reskin"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/click_ctrl(mob/user)
SHOULD_NOT_OVERRIDE(TRUE)
@@ -458,9 +434,6 @@
else if (siemens_coefficient <= 0.5)
.["partially insulated"] = "It is made from a poor insulator that will dampen (but not fully block) electric shocks passing through it."
if(LAZYLEN(unique_reskin) && !current_skin)
.["reskinnable"] = "This item is able to be reskinned! Alt-Click to do so!"
/obj/item/examine_descriptor(mob/user)
return "item"
+19 -7
View File
@@ -764,6 +764,20 @@
/obj/item/melee/baton/security/loaded/hos
preload_cell_type = /obj/item/stock_parts/power_store/cell/super
// Stunsword Skins
/datum/atom_skin/stunsword
abstract_type = /datum/atom_skin/stunsword
change_inhand_icon_state = TRUE
change_base_icon_state = TRUE
/datum/atom_skin/stunsword/default
preview_name = "Default"
new_icon_state = "stunsword"
/datum/atom_skin/stunsword/energy
preview_name = "Energy"
new_icon_state = "stunsword_energy"
///Stun Sword
/obj/item/melee/baton/security/stunsword
name = "\improper NT-20 'Excalibur' Stunsword"
@@ -789,14 +803,12 @@
convertible = FALSE
obj_flags = UNIQUE_RENAME
unique_reskin = list(
"Default" = "stunsword",
"Energy Stunsword" = "stunsword_energy",
)
unique_reskin_changes_inhand = TRUE
unique_reskin_changes_base_icon_state = TRUE
/obj/item/melee/baton/security/stunsword/loaded/add_deep_lore()
/obj/item/melee/baton/security/stunsword/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/stunsword)
/obj/item/melee/baton/security/stunsword/add_deep_lore()
return
/obj/item/melee/baton/security/stunsword/loaded
-95
View File
@@ -1,95 +0,0 @@
/// Called when alt clicked and the item has unique reskin options
/obj/item/proc/on_click_alt_reskin(datum/source, mob/user)
SIGNAL_HANDLER
if(!user.can_perform_action(src, NEED_DEXTERITY))
return NONE
if(!(obj_flags & INFINITE_RESKIN) && current_skin)
return NONE
INVOKE_ASYNC(src, PROC_REF(reskin_obj), user)
return CLICK_ACTION_SUCCESS
/**
* Checks if we should set up reskinning,
* by default if unique_reskin is set.
*
* Called on setup_reskinning().
* Inheritors should override this to add their own checks.
*/
/obj/item/proc/check_setup_reskinning()
SHOULD_CALL_PARENT(TRUE)
if(unique_reskin)
return TRUE
return FALSE
/**
* Registers signals and context for reskinning,
* if check_setup_reskinning() passes.
*
* Called on Initialize(...).
* Inheritors should override this to add their own setup steps,
* or to avoid double calling register_context().
*/
/obj/item/proc/setup_reskinning()
SHOULD_CALL_PARENT(FALSE)
if(!check_setup_reskinning())
return
RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin))
register_context()
/**
* Reskins object based on a user's choice
*
* Arguments:
* * user The mob choosing a reskin option
*/
/obj/item/proc/reskin_obj(mob/user)
if(!LAZYLEN(unique_reskin))
return
var/list/items = list()
for(var/reskin_option in unique_reskin)
var/image/item_image = image(icon = src.icon, icon_state = unique_reskin[reskin_option])
items += list("[reskin_option]" = item_image)
sort_list(items)
var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE)
if(!pick)
return
if(!unique_reskin[pick])
return
current_skin = pick
icon_state = unique_reskin[pick]
if (unique_reskin_changes_base_icon_state)
base_icon_state = icon_state
if (unique_reskin_changes_inhand)
inhand_icon_state = icon_state
update_appearance()
to_chat(user, "[src] is now skinned as '[pick].'")
SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick)
/**
* Checks if we are allowed to interact with a radial menu for reskins
*
* Arguments:
* * user The mob interacting with the menu
*/
/obj/item/proc/check_reskin_menu(mob/user)
if(QDELETED(src))
return FALSE
if(!(obj_flags & INFINITE_RESKIN) && current_skin)
return FALSE
if(!istype(user))
return FALSE
if(user.incapacitated)
return FALSE
return TRUE
-1
View File
@@ -9,7 +9,6 @@
strip_delay = 4 SECONDS
equip_delay_other = 4 SECONDS
visor_vars_to_toggle = NONE
unique_reskin_changes_base_icon_state = TRUE
var/adjusted_flags = null
///Did we install a filtering cloth?
+27 -11
View File
@@ -1,3 +1,28 @@
// Mask skins
/datum/atom_skin/joy_mask
abstract_type = /datum/atom_skin/joy_mask
change_base_icon_state = TRUE
/datum/atom_skin/joy_mask/joy
preview_name = "Joy"
new_icon_state = "joy"
/datum/atom_skin/joy_mask/flushed
preview_name = "Flushed"
new_icon_state = "flushed"
/datum/atom_skin/joy_mask/pensive
preview_name = "Pensive"
new_icon_state = "pensive"
/datum/atom_skin/joy_mask/angry
preview_name = "Angry"
new_icon_state = "angry"
/datum/atom_skin/joy_mask/pleading
preview_name = "Pleading"
new_icon_state = "pleading"
/obj/item/clothing/mask/joy
name = "emotion mask"
desc = "Express your happiness or hide your sorrows with this cultured cutout."
@@ -5,19 +30,10 @@
base_icon_state = "joy"
clothing_flags = MASKINTERNALS
flags_inv = HIDESNOUT
obj_flags = parent_type::obj_flags | INFINITE_RESKIN
unique_reskin = list(
"Joy" = "joy",
"Flushed" = "flushed",
"Pensive" = "pensive",
"Angry" = "angry",
"Pleading" = "pleading"
)
/obj/item/clothing/mask/joy/reskin_obj(mob/user)
/obj/item/clothing/mask/joy/Initialize(mapload)
. = ..()
user.update_worn_mask()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/joy_mask, infinite = TRUE)
/obj/item/clothing/mask/mummy
name = "mummy mask"
-7
View File
@@ -73,13 +73,6 @@
. = ..()
dump_attachments()
/obj/item/clothing/under/setup_reskinning()
if(!check_setup_reskinning())
return
// We already register context in Initialize.
RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin))
/obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = ..()
@@ -31,13 +31,6 @@
. = ..()
register_context()
/obj/item/clothing/accessory/setup_reskinning()
if(!check_setup_reskinning())
return
// We already register context regardless in Initialize.
RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin))
/**
* Can we be attached to the passed clothing article?
*/
@@ -177,28 +177,51 @@
name = "Pre-Approved Cyborg Candidate dogtag"
display = "This employee has been screened for negative mental traits to an acceptable level of accuracy, and is approved for the NT Cyborg program as an alternative to medical resuscitation."
// Pride pin skins
/datum/atom_skin/pride_pin
abstract_type = /datum/atom_skin/pride_pin
/datum/atom_skin/pride_pin/gay
preview_name = "Rainbow Pride"
new_icon_state = "pride"
/datum/atom_skin/pride_pin/bi
preview_name = "Bisexual Pride"
new_icon_state = "pride_bi"
/datum/atom_skin/pride_pin/pan
preview_name = "Pansexual Pride"
new_icon_state = "pride_pan"
/datum/atom_skin/pride_pin/ace
preview_name = "Asexual Pride"
new_icon_state = "pride_ace"
/datum/atom_skin/pride_pin/enby
preview_name = "Non-binary Pride"
new_icon_state = "pride_enby"
/datum/atom_skin/pride_pin/trans
preview_name = "Transgender Pride"
new_icon_state = "pride_trans"
/datum/atom_skin/pride_pin/intersex
preview_name = "Intersex Pride"
new_icon_state = "pride_intersex"
/datum/atom_skin/pride_pin/lesbian
preview_name = "Lesbian Pride"
new_icon_state = "pride_lesbian"
/obj/item/clothing/accessory/pride
name = "pride pin"
desc = "A Nanotrasen Diversity & Inclusion Center-sponsored holographic pin to show off your pride, reminding the crew of their unwavering commitment to equity, diversity, and inclusion!"
icon_state = "pride"
obj_flags = UNIQUE_RENAME | INFINITE_RESKIN
unique_reskin = list(
"Rainbow Pride" = "pride",
"Bisexual Pride" = "pride_bi",
"Pansexual Pride" = "pride_pan",
"Asexual Pride" = "pride_ace",
"Non-binary Pride" = "pride_enby",
"Transgender Pride" = "pride_trans",
"Intersex Pride" = "pride_intersex",
"Lesbian Pride" = "pride_lesbian",
)
obj_flags = UNIQUE_RENAME
/obj/item/clothing/accessory/pride/setup_reskinning()
if(!check_setup_reskinning())
return
// We already register context regardless in Initialize.
RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin))
/obj/item/clothing/accessory/pride/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/pride_pin, infinite = TRUE)
/obj/item/clothing/accessory/deaf_pin
name = "deaf personnel pin"
+23 -7
View File
@@ -275,6 +275,26 @@
can_adjust = FALSE
resistance_flags = NONE
// Mech suit skins
/datum/atom_skin/mech_suit
abstract_type = /datum/atom_skin/mech_suit
/datum/atom_skin/mech_suit/red
preview_name = "Red"
new_icon_state = "red_mech_suit"
/datum/atom_skin/mech_suit/white
preview_name = "White"
new_icon_state = "white_mech_suit"
/datum/atom_skin/mech_suit/blue
preview_name = "Blue"
new_icon_state = "blue_mech_suit"
/datum/atom_skin/mech_suit/black
preview_name = "Black"
new_icon_state = "black_mech_suit"
/obj/item/clothing/under/costume/mech_suit
name = "mech pilot's suit"
desc = "A mech pilot's suit. Might make your butt look big."
@@ -286,13 +306,9 @@
alternate_worn_layer = GLOVES_LAYER //covers hands but gloves can go over it. This is how these things work in my head.
can_adjust = FALSE
unique_reskin = list(
"Red" = "red_mech_suit",
"White" = "white_mech_suit",
"Blue" = "blue_mech_suit",
"Black" = "black_mech_suit",
)
/obj/item/clothing/under/costume/mech_suit/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/mech_suit)
/obj/item/clothing/under/costume/russian_officer
name = "\improper Russian officer's uniform"
@@ -82,4 +82,4 @@
/datum/loadout_item/accessory/pride
name = "Pride Pin"
item_path = /obj/item/clothing/accessory/pride
loadout_flags = LOADOUT_FLAG_ALLOW_RESKIN
reskin_datum = /datum/atom_skin/pride_pin
+19 -26
View File
@@ -50,8 +50,9 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
/// Icon state for the UI to use for preview icons.
/// Set automatically if null
var/ui_icon_state
/// Reskin options of this item if it can be reskinned.
VAR_FINAL/list/cached_reskin_options
/// Base typepath to what reskin datum this item can use to reskin into
/// Doesn't verify that the item_path actually has these reskins
var/reskin_datum
/// A list of greyscale colors that are used for items that have greyscale support, but don't allow full customization.
/// This is an assoc list of /datum/job_department -> colors, or /datum/job -> colors, allowing for preset colors based on player chosen job.
/// Jobs are prioritized over departments.
@@ -81,15 +82,6 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
ui_icon = item_path::icon_preview || item_path::icon
ui_icon_state = item_path::icon_state_preview || item_path::icon_state
if(loadout_flags & LOADOUT_FLAG_ALLOW_RESKIN)
var/obj/item/dummy_item = new item_path()
if(!length(dummy_item.unique_reskin))
loadout_flags &= ~LOADOUT_FLAG_ALLOW_RESKIN
stack_trace("Loadout item [item_path] has LOADOUT_FLAG_ALLOW_RESKIN but has no unique reskins.")
else
cached_reskin_options = dummy_item.unique_reskin.Copy()
qdel(dummy_item)
/datum/loadout_item/Destroy(force, ...)
if(!force)
stack_trace("QDEL called on loadout item [type]. This shouldn't ever happen. (Use FORCE if necessary.)")
@@ -126,7 +118,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
return set_name(manager, user)
if("set_skin")
if(loadout_flags & LOADOUT_FLAG_ALLOW_RESKIN)
if(reskin_datum)
return set_skin(manager, user, params)
return TRUE
@@ -205,10 +197,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
/// Used for reskinning an item to an alt skin.
/datum/loadout_item/proc/set_skin(datum/preference_middleware/loadout/manager, mob/user, params)
var/reskin_to = params["skin"]
if(!cached_reskin_options[reskin_to])
return FALSE
var/reskin_to = params["skin"] // sanity checking isn't necessary because it's all checked when equipped anyways
var/list/loadout = manager.preferences.read_preference(/datum/preference/loadout)
if(!loadout?[item_path])
return FALSE
@@ -283,11 +272,13 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
equipped_item.name = trim(item_details[INFO_NAMED], PREVENT_CHARACTER_TRIM_LOSS(MAX_NAME_LEN))
ADD_TRAIT(equipped_item, TRAIT_WAS_RENAMED, "Loadout")
if((loadout_flags & LOADOUT_FLAG_ALLOW_RESKIN) && item_details?[INFO_RESKIN])
if(reskin_datum && item_details?[INFO_RESKIN])
var/skin_chosen = item_details[INFO_RESKIN]
if(skin_chosen in equipped_item.unique_reskin)
equipped_item.current_skin = skin_chosen
equipped_item.icon_state = equipped_item.unique_reskin[skin_chosen]
for(var/datum/atom_skin/skin_path as anything in valid_subtypesof(reskin_datum))
if(skin_path::preview_name != skin_chosen)
continue
var/datum/atom_skin/skin_instance = GLOB.atom_skins[skin_path]
skin_instance.apply(equipped_item)
if(istype(equipped_item, /obj/item/clothing/accessory))
// Snowflake handing for accessories, because we need to update the thing it's attached to instead
if(isclothing(equipped_item.loc))
@@ -296,6 +287,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
update_flag |= (ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING)
else
update_flag |= equipped_item.slot_flags
break
return update_flag
@@ -336,7 +328,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
if((loadout_flags & LOADOUT_FLAG_GREYSCALING_ALLOWED) && !(loadout_flags & LOADOUT_FLAG_JOB_GREYSCALING))
displayed_text[FA_ICON_PALETTE] = "Recolorable"
if(loadout_flags & LOADOUT_FLAG_ALLOW_RESKIN)
if(reskin_datum)
displayed_text[FA_ICON_SWATCHBOOK] = "Reskinnable"
return displayed_text
@@ -381,16 +373,17 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories())
* Returns a list of options this item can be reskinned into.
*/
/datum/loadout_item/proc/get_reskin_options() as /list
if(!(loadout_flags & LOADOUT_FLAG_ALLOW_RESKIN))
if(!reskin_datum)
return null
var/list/reskins = list()
for(var/skin in cached_reskin_options)
for(var/datum/atom_skin/skin as anything in valid_subtypesof(reskin_datum))
UNTYPED_LIST_ADD(reskins, list(
"name" = skin,
"tooltip" = skin,
"skin_icon_state" = cached_reskin_options[skin],
"name" = skin::new_name || skin::preview_name,
"tooltip" = skin::preview_name,
"skin_icon" = skin::new_icon,
"skin_icon_state" = skin::new_icon_state,
))
return reskins
@@ -12,6 +12,7 @@
suicidal miners against local fauna."
icon = 'icons/obj/mining.dmi'
icon_state = "crusher"
base_icon_state = "crusher"
inhand_icon_state = "crusher0"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi'
@@ -56,25 +57,43 @@
var/detonation_damage = 50
/// Damage that the mark additionally does when hit by the crusher via backstab
var/backstab_bonus = 30
/// Used by retool kits when changing the crusher's appearance
var/current_inhand_icon_state = "crusher"
/// The file in which our projectile icon resides
var/projectile_icon = 'icons/obj/weapons/guns/projectiles.dmi'
/// Used by retool kits when changing the crusher's projectile sprite
var/projectile_icon_state = "pulse1"
/// Wielded damage we deal, aka our "real" damage
var/force_wielded = 20
/// Set to TRUE if the last projectile fired was point-blank at a living target
var/last_projectile_pb = FALSE
/obj/item/kinetic_crusher/Initialize(mapload)
. = ..()
AddComponent(/datum/component/butchering, \
AddComponent( \
/datum/component/butchering, \
speed = 6 SECONDS, \
effectiveness = 110, \
)
update_reskin(null)
//technically it's huge and bulky, but this provides an incentive to use it
update_wielding()
register_context()
/**
* Adds or updates the reskinning component on the crusher.
*
* * default_skin_typepath: The typepath of skin to apply by default.
* Passing null will either not apply a skin or will reset it to default if one is already applied.
* If a supplied skin is blacklisted, it will be un-blacklisted.
*/
/obj/item/kinetic_crusher/proc/update_reskin(datum/atom_skin/crusher_skin/default_skin_typepath)
AddComponent( \
/datum/component/reskinable_item, \
/datum/atom_skin/crusher_skin, \
infinite = TRUE, \
initial_skin = default_skin_typepath ? default_skin_typepath::preview_name : null, \
blacklisted_subtypes = subtypesof(/datum/atom_skin/crusher_skin/locked) - default_skin_typepath, \
)
/obj/item/kinetic_crusher/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(!held_item)
@@ -236,6 +255,7 @@
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
return
last_projectile_pb = get_dist(target, user) <= 1 && isliving(target)
var/obj/projectile/destabilizer/destabilizer = new(proj_turf)
SEND_SIGNAL(src, COMSIG_CRUSHER_FIRED_BLAST, target, user, destabilizer)
destabilizer.icon = projectile_icon
@@ -281,7 +301,7 @@
return TRUE
/obj/item/kinetic_crusher/update_icon_state()
inhand_icon_state = "[current_inhand_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
return ..()
/obj/item/kinetic_crusher/update_overlays()
@@ -1,164 +1,95 @@
/*!
* Contains crusher trophies that are not obtained from fauna
*/
/// Cosmetic items for changing the crusher's look
/obj/item/crusher_trophy/retool_kit
name = "crusher retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
/// Currently picked crusher reskin
var/datum/crusher_skin/active_skin = /datum/crusher_skin/sword
/// If this kit forces some specific skin, or can pick between subtypes
var/forced_skin
/obj/item/crusher_trophy/retool_kit/Destroy(force)
if (istype(active_skin))
QDEL_NULL(active_skin)
return ..()
/obj/item/crusher_trophy/retool_kit/effect_desc()
return "the crusher to have the appearance of \a [active_skin::name]"
/obj/item/crusher_trophy/retool_kit/add_to(obj/item/kinetic_crusher/pkc, mob/user)
if (!forced_skin)
var/list/choices = list()
for (var/datum/crusher_skin/skin as anything in subtypesof(/datum/crusher_skin))
if (skin::normal_skin)
choices[skin] = icon(skin::retool_icon || 'icons/obj/mining.dmi', skin::retool_icon_state)
var/datum/crusher_skin/chosen_skin = show_radial_menu(user, src, choices, tooltips = TRUE, require_near = TRUE)
if (!chosen_skin)
return
active_skin = chosen_skin
else
active_skin = forced_skin
. = ..()
if(!.)
return
active_skin = new active_skin(pkc)
if (active_skin.retool_icon)
pkc.icon = active_skin.retool_icon
pkc.icon_state = active_skin.retool_icon_state
pkc.current_inhand_icon_state = active_skin.retool_inhand_icon
if (active_skin.retool_projectile_icon)
pkc.projectile_icon = active_skin.retool_projectile_icon
if (active_skin.retool_projectile_icon_state)
pkc.projectile_icon_state = active_skin.retool_projectile_icon_state
// Should either have both, or neither
if (active_skin.retool_lefthand_file)
pkc.lefthand_file = active_skin.retool_lefthand_file
pkc.righthand_file = active_skin.retool_righthand_file
if(active_skin.retool_worn_file)
pkc.worn_icon = active_skin.retool_worn_file
pkc.worn_icon_state = active_skin::retool_icon_state
if (active_skin.retool_inhand_x)
pkc.inhand_x_dimension = active_skin.retool_inhand_x
if (active_skin.retool_inhand_y)
pkc.inhand_y_dimension = active_skin.retool_inhand_y
pkc.update_appearance()
pkc.update_slot_icon()
/obj/item/crusher_trophy/retool_kit/remove_from(obj/item/kinetic_crusher/pkc)
var/skin_type = active_skin.type
qdel(active_skin)
active_skin = skin_type
pkc.icon = initial(pkc.icon)
pkc.icon_state = initial(pkc.icon_state)
pkc.current_inhand_icon_state = initial(pkc.current_inhand_icon_state)
pkc.projectile_icon = initial(pkc.projectile_icon)
pkc.projectile_icon_state = initial(pkc.projectile_icon_state)
pkc.lefthand_file = initial(pkc.lefthand_file)
pkc.righthand_file = initial(pkc.righthand_file)
pkc.worn_icon = initial(pkc.worn_icon)
pkc.worn_icon_state = initial(pkc.worn_icon_state)
pkc.inhand_x_dimension = initial(pkc.inhand_x_dimension)
pkc.inhand_y_dimension = initial(pkc.inhand_y_dimension)
pkc.update_appearance()
pkc.update_slot_icon()
return ..()
/// Alternate PKC skins
/datum/crusher_skin
/// Name of the modification
var/name = "error that should be reported to coders"
/// Specifies the icon file in which the crusher's new state is stored.
var/retool_icon = 'icons/obj/mining.dmi'
///Specifies the sprite/icon state which the crusher is changed to as an item. Should appear in the icons/obj/mining.dmi file with accompanying "lit" and "recharging" sprites
var/retool_icon_state = "ipickaxe"
///Specifies the icon state for the crusher's appearance in hand. Should appear in both retool_lefthand_file and retool_righthand_file.
var/retool_inhand_icon = "ipickaxe"
// Alternate PKC skins
/datum/atom_skin/crusher_skin
abstract_type = /datum/atom_skin/crusher_skin
change_base_icon_state = TRUE
new_icon = 'icons/obj/mining.dmi'
new_icon_state = "ipickaxe"
/// Specifies the icon state for the crusher's appearance in hand. Should appear in both new_lefthand_file and new_righthand_file.
var/new_inhand_icon = "ipickaxe"
/// Specifies the icon file in which the crusher's projectile sprite is located.
var/retool_projectile_icon = 'icons/obj/weapons/guns/projectiles.dmi'
///For if the retool kit changes the projectile's appearance.
var/retool_projectile_icon_state = null
var/new_projectile_icon = 'icons/obj/weapons/guns/projectiles.dmi'
/// For if the retool kit changes the projectile's appearance.
var/new_projectile_icon_state
/// Specifies the left hand inhand icon file. Don't forget to set the right hand file as well.
var/retool_lefthand_file = null
var/new_lefthand_file
/// Specifies the right hand inhand icon file. Don't forget to set the left hand file as well.
var/retool_righthand_file = null
var/new_righthand_file
/// Specifies the worn icon file.
var/retool_worn_file = null
var/new_worn_file
/// Specifies the X dimensions of the new inhand, only relevant with different inhand files.
var/retool_inhand_x = null
var/new_inhandx
/// Specifies the Y dimensions of the new inhand, only relevant with different inhand files.
var/retool_inhand_y = null
/// Can this skin be normally selected by a generic retool kit?
var/normal_skin = TRUE
/// Crusher this skin is attached to
var/obj/item/kinetic_crusher/crusher
var/new_inhandy
/datum/crusher_skin/New(obj/item/kinetic_crusher/new_crusher)
/datum/atom_skin/crusher_skin/apply(obj/item/kinetic_crusher/apply_to)
. = ..()
crusher = new_crusher
APPLY_VAR_OR_RESET_INITIAL(apply_to, inhand_icon_state, new_inhand_icon, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, projectile_icon, new_projectile_icon, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, projectile_icon_state, new_projectile_icon_state, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, lefthand_file, new_lefthand_file, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, righthand_file, new_righthand_file, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, worn_icon, new_worn_file, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, worn_icon_state, new_icon_state, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, inhand_x_dimension, new_inhandx, reset_missing)
APPLY_VAR_OR_RESET_INITIAL(apply_to, inhand_y_dimension, new_inhandy, reset_missing)
/datum/crusher_skin/Destroy(force)
crusher = null
return ..()
/datum/crusher_skin/sword
name = "sword"
retool_icon_state = "crusher_sword"
retool_inhand_icon = "crusher_sword"
/datum/crusher_skin/harpoon
name = "harpoon"
retool_icon_state = "crusher_harpoon"
retool_inhand_icon = "crusher_harpoon"
retool_projectile_icon_state = "pulse_harpoon"
/datum/crusher_skin/harpoon/New(obj/item/kinetic_crusher/new_crusher)
/datum/atom_skin/crusher_skin/clear_skin(obj/item/kinetic_crusher/clear_from)
. = ..()
RegisterSignal(crusher, COMSIG_ITEM_ATTACK_ANIMATION, PROC_REF(on_attack_animation))
RESET_INITIAL_IF_SET(clear_from, inhand_icon_state, new_inhand_icon)
RESET_INITIAL_IF_SET(clear_from, projectile_icon, new_projectile_icon)
RESET_INITIAL_IF_SET(clear_from, projectile_icon_state, new_projectile_icon_state)
RESET_INITIAL_IF_SET(clear_from, lefthand_file, new_lefthand_file)
RESET_INITIAL_IF_SET(clear_from, righthand_file, new_righthand_file)
RESET_INITIAL_IF_SET(clear_from, worn_icon, new_worn_file)
RESET_INITIAL_IF_SET(clear_from, worn_icon_state, new_icon_state)
RESET_INITIAL_IF_SET(clear_from, inhand_x_dimension, new_inhandx)
RESET_INITIAL_IF_SET(clear_from, inhand_y_dimension, new_inhandy)
/datum/crusher_skin/harpoon/Destroy(force)
UnregisterSignal(crusher, COMSIG_ITEM_ATTACK_ANIMATION)
return ..()
/datum/atom_skin/crusher_skin/sword
new_name = "proto-kinetic sword"
preview_name = "Sword"
new_icon_state = "crusher_sword"
new_inhand_icon = "crusher_sword"
/datum/crusher_skin/harpoon/proc/on_attack_animation(obj/item/source, atom/movable/attacker, atom/attacked_atom, animation_type, list/image_override, list/animation_override)
/datum/atom_skin/crusher_skin/harpoon
new_name = "proto-kinetic harpoon"
preview_name = "Harpoon"
new_icon_state = "crusher_harpoon"
new_inhand_icon = "crusher_harpoon"
new_projectile_icon_state = "pulse_harpoon"
/datum/atom_skin/crusher_skin/harpoon/apply(atom/apply_to)
. = ..()
RegisterSignal(apply_to, COMSIG_ITEM_ATTACK_ANIMATION, PROC_REF(on_attack_animation))
/datum/atom_skin/crusher_skin/harpoon/clear_skin(atom/clear_from)
. = ..()
UnregisterSignal(clear_from, COMSIG_ITEM_ATTACK_ANIMATION)
/datum/atom_skin/crusher_skin/harpoon/proc/on_attack_animation(obj/item/source, atom/movable/attacker, atom/attacked_atom, animation_type, list/image_override, list/animation_override)
SIGNAL_HANDLER
// If nothing is forcing an animation type, attack with a piercing animation because we're a harpoon
if (!animation_type)
animation_override += ATTACK_ANIMATION_PIERCE
/datum/crusher_skin/dagger
name = "dual dagger and blaster"
retool_icon_state = "crusher_dagger"
retool_inhand_icon = "crusher_dagger"
/// Are we doing a blaster animation right now?
var/blaster_strike = FALSE
/datum/atom_skin/crusher_skin/dagger
new_name = "proto-kinetic dual dagger and blaster"
preview_name = "Dagger and Blaster"
new_icon_state = "crusher_dagger"
new_inhand_icon = "crusher_dagger"
/datum/crusher_skin/dagger/New(obj/item/kinetic_crusher/new_crusher)
/datum/atom_skin/crusher_skin/dagger/apply(atom/apply_to)
. = ..()
RegisterSignal(crusher, COMSIG_ITEM_ATTACK_ANIMATION, PROC_REF(on_attack_animation))
RegisterSignal(crusher, COMSIG_CRUSHER_FIRED_BLAST, PROC_REF(on_fired_blast))
RegisterSignal(apply_to, COMSIG_ITEM_ATTACK_ANIMATION, PROC_REF(on_attack_animation))
RegisterSignal(apply_to, COMSIG_CRUSHER_FIRED_BLAST, PROC_REF(on_fired_blast))
/datum/crusher_skin/dagger/Destroy(force)
UnregisterSignal(crusher, list(COMSIG_ITEM_ATTACK_ANIMATION, COMSIG_CRUSHER_FIRED_BLAST))
return ..()
/datum/atom_skin/crusher_skin/dagger/clear_skin(atom/clear_from)
. = ..()
UnregisterSignal(clear_from, COMSIG_ITEM_ATTACK_ANIMATION)
UnregisterSignal(clear_from, COMSIG_CRUSHER_FIRED_BLAST)
/datum/crusher_skin/dagger/proc/on_attack_animation(obj/item/kinetic_crusher/source, atom/movable/attacker, atom/attacked_atom, animation_type, list/image_override, list/animation_override, list/angle_override)
/datum/atom_skin/crusher_skin/dagger/proc/on_attack_animation(obj/item/kinetic_crusher/source, atom/movable/attacker, atom/attacked_atom, animation_type, list/image_override, list/animation_override, list/angle_override)
SIGNAL_HANDLER
// If we've been forcefully assigned an animation type already, we shouldn't do the custom attack animation logic
@@ -167,11 +98,11 @@
if (isliving(attacked_atom))
var/mob/living/target = attacked_atom
if (blaster_strike)
if (source.last_projectile_pb)
image_override += image(icon = 'icons/obj/mining.dmi', icon_state = "crusher_dagger_blaster")
angle_override += 0
animation_override += ATTACK_ANIMATION_PIERCE
blaster_strike = FALSE
source.last_projectile_pb = FALSE
return
if (target.has_status_effect(/datum/status_effect/crusher_mark))
@@ -179,33 +110,62 @@
image_override += image(icon = 'icons/obj/mining.dmi', icon_state = "crusher_dagger_melee")
/datum/crusher_skin/dagger/proc/on_fired_blast(obj/item/kinetic_crusher/source, atom/target, mob/living/user, obj/projectile/destabilizer/destabilizer)
/datum/atom_skin/crusher_skin/dagger/proc/on_fired_blast(obj/item/kinetic_crusher/source, atom/target, mob/living/user, obj/projectile/destabilizer/destabilizer)
SIGNAL_HANDLER
if (isliving(target) && get_dist(target, user) <= 1)
blaster_strike = TRUE
user.do_item_attack_animation(target, used_item = source)
/datum/crusher_skin/glaive
name = "glaive"
retool_icon_state = "crusher_glaive"
retool_inhand_icon = "crusher_glaive"
retool_lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
retool_righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
retool_inhand_x = 64
retool_inhand_y = 64
/datum/atom_skin/crusher_skin/glaive
new_name = "proto-kinetic glaive"
preview_name = "Glaive"
new_icon_state = "crusher_glaive"
new_inhand_icon = "crusher_glaive"
new_lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
new_righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
new_inhandx = 64
new_inhandy = 64
// Locked skins that cannot be selected normally
/datum/atom_skin/crusher_skin/locked
abstract_type = /datum/atom_skin/crusher_skin/locked
/datum/atom_skin/crusher_skin/locked/ashen_skull
preview_name = "Skull"
new_icon_state = "crusher_skull"
new_inhand_icon = "crusher_skull"
new_projectile_icon_state = "pulse_skull"
/// Unlockable (or forced) skins
/obj/item/crusher_trophy/retool_kit
name = "crusher retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
/// What skin do we apply when attached
var/datum/atom_skin/crusher_skin/forced_skin
/obj/item/crusher_trophy/retool_kit/effect_desc()
return "the crusher to have the appearance of \a [forced_skin::preview_name]"
/obj/item/crusher_trophy/retool_kit/add_to(obj/item/kinetic_crusher/pkc, mob/user)
. = ..()
if(!.)
return
pkc.update_reskin(forced_skin)
/obj/item/crusher_trophy/retool_kit/remove_from(obj/item/kinetic_crusher/pkc)
pkc.update_reskin(null) // resets reskin component
return ..()
/obj/item/crusher_trophy/retool_kit/ashenskull
name = "ashen skull"
desc = "It burns with the flame of the necropolis, whispering in your ear. It demands to be bound to a suitable weapon."
icon_state = "retool_kit_skull"
forced_skin = /datum/crusher_skin/ashen_skull
forced_skin = /datum/atom_skin/crusher_skin/locked/ashen_skull
/obj/item/crusher_trophy/retool_kit/ashenskull/effect_desc()
return "the crusher to appear corrupted by infernal powers"
/datum/crusher_skin/ashen_skull
retool_icon_state = "crusher_skull"
retool_inhand_icon = "crusher_skull"
retool_projectile_icon_state = "pulse_skull"
normal_skin = FALSE
+18 -7
View File
@@ -1,3 +1,20 @@
// Clipboard skins
/datum/atom_skin/clipboard
abstract_type = /datum/atom_skin/clipboard
change_inhand_icon_state = TRUE
/datum/atom_skin/clipboard/brown
preview_name = "Brown"
new_icon_state = "clipboard"
/datum/atom_skin/clipboard/black
preview_name = "Black"
new_icon_state = "clipboard_black"
/datum/atom_skin/clipboard/white
preview_name = "White"
new_icon_state = "clipboard_white"
/**
* Clipboard
*/
@@ -14,13 +31,6 @@
slot_flags = ITEM_SLOT_BELT
resistance_flags = FLAMMABLE
unique_reskin = list(
"Brown" = "clipboard",
"Black" = "clipboard_black",
"White" = "clipboard_white",
)
unique_reskin_changes_inhand = TRUE
/// The stored pen
var/obj/item/pen/pen
/// Is the pen integrated?
@@ -39,6 +49,7 @@
/obj/item/clipboard/Initialize(mapload)
update_appearance()
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/clipboard)
/obj/item/clipboard/Destroy()
QDEL_NULL(pen)
+46 -24
View File
@@ -177,6 +177,38 @@
time = 3 SECONDS
category = CAT_TOOLS
// Skins for captain's fountain pen
/datum/atom_skin/cap_pen
abstract_type = /datum/atom_skin/cap_pen
/datum/atom_skin/cap_pen/apply(atom/apply_to)
. = ..()
apply_to.desc = "It's an expensive [preview_name] fountain pen. The nib is quite sharp."
/datum/atom_skin/cap_pen/clear_skin(atom/clear_from)
. = ..()
clear_from.desc = initial(clear_from.desc)
/datum/atom_skin/cap_pen/oak
preview_name = "Oak"
new_icon_state = "pen-fountain-o"
/datum/atom_skin/cap_pen/gold
preview_name = "Gold"
new_icon_state = "pen-fountain-g"
/datum/atom_skin/cap_pen/rosewood
preview_name = "Rosewood"
new_icon_state = "pen-fountain-r"
/datum/atom_skin/cap_pen/black_silver
preview_name = "Black and Silver"
new_icon_state = "pen-fountain-b"
/datum/atom_skin/cap_pen/command_blue
preview_name = "Command Blue"
new_icon_state = "pen-fountain-cb"
/obj/item/pen/fountain/captain
name = "captain's fountain pen"
desc = "It's an expensive Oak fountain pen. The nib is quite sharp."
@@ -187,22 +219,15 @@
custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT*7.5)
sharpness = SHARP_EDGED
resistance_flags = FIRE_PROOF
unique_reskin = list(
"Oak" = "pen-fountain-o",
"Gold" = "pen-fountain-g",
"Rosewood" = "pen-fountain-r",
"Black and Silver" = "pen-fountain-b",
"Command Blue" = "pen-fountain-cb"
)
embed_type = /datum/embedding/pen/captain
dart_insert_casing_icon_state = "overlay_fountainpen_gold"
dart_insert_projectile_icon_state = "overlay_fountainpen_gold_proj"
var/list/overlay_reskin = list(
"Oak" = "overlay_fountainpen_gold",
"Gold" = "overlay_fountainpen_gold",
"Rosewood" = "overlay_fountainpen_gold",
"Black and Silver" = "overlay_fountainpen",
"Command Blue" = "overlay_fountainpen_gold"
/datum/atom_skin/cap_pen/black_silver::preview_name = "overlay_fountainpen",
/datum/atom_skin/cap_pen/command_blue::preview_name = "overlay_fountainpen_gold",
/datum/atom_skin/cap_pen/gold::preview_name = "overlay_fountainpen_gold",
/datum/atom_skin/cap_pen/oak::preview_name = "overlay_fountainpen_gold",
/datum/atom_skin/cap_pen/rosewood::preview_name = "overlay_fountainpen_gold",
)
/datum/embedding/pen/captain
@@ -210,24 +235,21 @@
/obj/item/pen/fountain/captain/Initialize(mapload)
. = ..()
AddComponent(/datum/component/butchering, \
speed = 20 SECONDS, \
effectiveness = 115, \
AddComponent( \
/datum/component/butchering, \
speed = 20 SECONDS, \
effectiveness = 115, \
)
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/cap_pen)
//the pen is mightier than the sword
RegisterSignal(src, COMSIG_DART_INSERT_PARENT_RESKINNED, PROC_REF(reskin_dart_insert))
/obj/item/pen/fountain/captain/reskin_obj(mob/M)
..()
if(current_skin)
desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp."
/obj/item/pen/fountain/captain/proc/reskin_dart_insert(datum/component/dart_insert/insert_comp)
/obj/item/pen/fountain/captain/proc/reskin_dart_insert(datum/component/dart_insert/insert_comp, skin)
SIGNAL_HANDLER
if(!istype(insert_comp)) //You really shouldn't be sending this signal from anything other than a dart_insert component
return
insert_comp.casing_overlay_icon_state = overlay_reskin[current_skin]
insert_comp.projectile_overlay_icon_state = "[overlay_reskin[current_skin]]_proj"
insert_comp.casing_overlay_icon_state = overlay_reskin[skin]
insert_comp.projectile_overlay_icon_state = "[overlay_reskin[skin]]_proj"
/obj/item/pen/item_ctrl_click(mob/living/carbon/user)
if(loc != user)
@@ -9,7 +9,6 @@
pickup_sound = 'sound/items/handling/gun/gun_pick_up.ogg'
drop_sound = 'sound/items/handling/gun/gun_drop.ogg'
sound_vary = TRUE
unique_reskin_changes_base_icon_state = TRUE
///sound when inserting magazine
var/load_sound = 'sound/items/weapons/gun/general/magazine_insert_full.ogg'
@@ -97,8 +97,7 @@
. = ..()
var/live_ammo = get_ammo(FALSE, FALSE)
. += "[live_ammo ? live_ammo : "None"] of those are live rounds."
if (current_skin)
. += span_notice("It can be spun with [EXAMINE_HINT("alt-click")].")
. += span_notice("It can be spun with [EXAMINE_HINT("alt-click")].")
/obj/item/gun/ballistic/revolver/ignition_effect(atom/A, mob/user)
if(last_fire && last_fire + 15 SECONDS > world.time)
@@ -112,6 +111,47 @@
base_icon_state = "c38"
fire_sound = 'sound/items/weapons/gun/revolver/shot.ogg'
// 38 special skins
/datum/atom_skin/det_revolver
abstract_type = /datum/atom_skin/det_revolver
change_base_icon_state = TRUE
/datum/atom_skin/det_revolver/default
preview_name = "Default"
new_icon_state = "c38"
/datum/atom_skin/det_revolver/fitz_special
preview_name = "Fitz Special"
new_icon_state = "c38_fitz"
/datum/atom_skin/det_revolver/police_positive_special
preview_name = "Police Positive Special"
new_icon_state = "c38_police"
/datum/atom_skin/det_revolver/blued_steel
preview_name = "Blued Steel"
new_icon_state = "c38_blued"
/datum/atom_skin/det_revolver/stainless_steel
preview_name = "Stainless Steel"
new_icon_state = "c38_stainless"
/datum/atom_skin/det_revolver/gold_trim
preview_name = "Gold Trim"
new_icon_state = "c38_trim"
/datum/atom_skin/det_revolver/golden
preview_name = "Golden"
new_icon_state = "c38_gold"
/datum/atom_skin/det_revolver/peacemaker
preview_name = "The Peacemaker"
new_icon_state = "c38_peacemaker"
/datum/atom_skin/det_revolver/black_panther
preview_name = "Black Panther"
new_icon_state = "c38_panther"
/obj/item/gun/ballistic/revolver/c38/detective
name = "\improper Colt Detective Special"
desc = "A classic, if not outdated, law enforcement firearm. Uses .38 Special rounds. \nSome spread rumors that if you loosen the barrel with a wrench, you can \"improve\" it."
@@ -126,17 +166,10 @@
misfire_percentage_increment = 25 //about 1 in 4 rounds, which increases rapidly every shot
obj_flags = UNIQUE_RENAME
unique_reskin = list(
"Default" = "c38",
"Fitz Special" = "c38_fitz",
"Police Positive Special" = "c38_police",
"Blued Steel" = "c38_blued",
"Stainless Steel" = "c38_stainless",
"Gold Trim" = "c38_trim",
"Golden" = "c38_gold",
"The Peacemaker" = "c38_peacemaker",
"Black Panther" = "c38_panther"
)
/obj/item/gun/ballistic/revolver/c38/detective/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/det_revolver)
/obj/item/gun/ballistic/revolver/badass
name = "\improper Badass Revolver"
@@ -285,6 +285,35 @@
/obj/item/gun/ballistic/shotgun/bulldog/unrestricted
pin = /obj/item/firing_pin
// Double barrel shotgun skins
/datum/atom_skin/bar_shotgun
abstract_type = /datum/atom_skin/bar_shotgun
change_base_icon_state = TRUE
/datum/atom_skin/bar_shotgun/default
preview_name = "Standard Finish"
new_icon_state = "dshotgun"
/datum/atom_skin/bar_shotgun/dark_red
preview_name = "Dark Red Finish"
new_icon_state = "dshotgun_d"
/datum/atom_skin/bar_shotgun/ash
preview_name = "Ash"
new_icon_state = "dshotgun_f"
/datum/atom_skin/bar_shotgun/faded_grey
preview_name = "Faded Grey"
new_icon_state = "dshotgun_g"
/datum/atom_skin/bar_shotgun/maple
preview_name = "Maple"
new_icon_state = "dshotgun_l"
/datum/atom_skin/bar_shotgun/rosewood
preview_name = "Rosewood"
new_icon_state = "dshotgun_p"
/////////////////////////////
// DOUBLE BARRELED SHOTGUN //
/////////////////////////////
@@ -304,18 +333,15 @@
sawn_desc = "Omar's coming!"
obj_flags = UNIQUE_RENAME
rack_sound_volume = 0
unique_reskin = list("Default" = "dshotgun",
"Dark Red Finish" = "dshotgun_d",
"Ash" = "dshotgun_f",
"Faded Grey" = "dshotgun_g",
"Maple" = "dshotgun_l",
"Rosewood" = "dshotgun_p"
)
semi_auto = TRUE
bolt_type = BOLT_TYPE_NO_BOLT
can_be_sawn_off = TRUE
pb_knockback = 3 // it's a super shotgun!
/obj/item/gun/ballistic/shotgun/doublebarrel/Initialize(mapload)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/bar_shotgun)
/obj/item/gun/ballistic/shotgun/doublebarrel/sawoff(mob/user)
. = ..()
if(.)
@@ -1,3 +1,31 @@
// Gel skins
/datum/atom_skin/med_gel
abstract_type = /datum/atom_skin/med_gel
/datum/atom_skin/med_gel/blue
preview_name = "Blue"
new_icon_state = "medigel_blue"
/datum/atom_skin/med_gel/cyan
preview_name = "Cyan"
new_icon_state = "medigel_cyan"
/datum/atom_skin/med_gel/green
preview_name = "Green"
new_icon_state = "medigel_green"
/datum/atom_skin/med_gel/red
preview_name = "Red"
new_icon_state = "medigel_red"
/datum/atom_skin/med_gel/orange
preview_name = "Orange"
new_icon_state = "medigel_orange"
/datum/atom_skin/med_gel/purple
preview_name = "Purple"
new_icon_state = "medigel_purple"
/obj/item/reagent_containers/medigel
name = "medical gel"
desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap."
@@ -23,15 +51,11 @@
var/apply_method = "spray" //the thick gel is sprayed and then dries into patch like film.
var/self_delay = 30
custom_price = PAYCHECK_CREW * 2
unique_reskin = list(
"Blue" = "medigel_blue",
"Cyan" = "medigel_cyan",
"Green" = "medigel_green",
"Red" = "medigel_red",
"Orange" = "medigel_orange",
"Purple" = "medigel_purple"
)
/obj/item/reagent_containers/medigel/Initialize(mapload)
. = ..()
if(icon_state == "medigel") // oh yeah baby raw icon state check to make sure we can't reskin preset gels
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/med_gel)
/obj/item/reagent_containers/medigel/mode_change_message(mob/user)
var/squirt_mode = amount_per_transfer_from_this == initial(amount_per_transfer_from_this)
@@ -78,21 +102,18 @@
name = "medical gel (libital)"
desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains libital, for treating cuts and bruises. Libital does minor liver damage. Diluted with granibitaluri."
icon_state = "brutegel"
current_skin = "brutegel"
list_reagents = list(/datum/reagent/medicine/c2/libital = 24, /datum/reagent/medicine/granibitaluri = 36)
/obj/item/reagent_containers/medigel/aiuri
name = "medical gel (aiuri)"
desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains aiuri, useful for treating burns. Aiuri does minor eye damage. Diluted with granibitaluri."
icon_state = "burngel"
current_skin = "burngel"
list_reagents = list(/datum/reagent/medicine/c2/aiuri = 24, /datum/reagent/medicine/granibitaluri = 36)
/obj/item/reagent_containers/medigel/synthflesh
name = "medical gel (synthflesh)"
desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains synthflesh, a slightly toxic medicine capable of healing bruises, burns, and husks."
icon_state = "synthgel"
current_skin = "synthgel"
list_reagents = list(/datum/reagent/medicine/c2/synthflesh = 60)
list_reagents_purity = 1
amount_per_transfer_from_this = 60
@@ -117,6 +138,5 @@
name = "sterilizer gel"
desc = "gel bottle loaded with non-toxic sterilizer. Useful in preparation for surgery."
icon_state = "medigel_blue"
current_skin = "medigel_blue"
list_reagents = list(/datum/reagent/space_cleaner/sterilizine = 60)
custom_price = PAYCHECK_CREW * 2
@@ -420,6 +420,23 @@
. = ..()
icon_state = pick("sprayer_sus_1", "sprayer_sus_2", "sprayer_sus_3", "sprayer_sus_4", "sprayer_sus_5","sprayer_sus_6", "sprayer_sus_7", "sprayer_sus_8")
// Spray bottle skins
/datum/atom_skin/med_spray
abstract_type = /datum/atom_skin/med_spray
change_inhand_icon_state = TRUE
/datum/atom_skin/med_spray/red
preview_name = "Red"
new_icon_state = "sprayer_med_red"
/datum/atom_skin/med_spray/yellow
preview_name = "Yellow"
new_icon_state = "sprayer_med_yellow"
/datum/atom_skin/med_spray/blue
preview_name = "Blue"
new_icon_state = "sprayer_med_blue"
/obj/item/reagent_containers/spray/medical
name = "medical spray bottle"
icon = 'icons/obj/medical/chemical.dmi'
@@ -428,20 +445,10 @@
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
volume = 100
unique_reskin = list("Red" = "sprayer_med_red",
"Yellow" = "sprayer_med_yellow",
"Blue" = "sprayer_med_blue")
/obj/item/reagent_containers/spray/medical/reskin_obj(mob/M)
..()
switch(icon_state)
if("sprayer_med_red")
inhand_icon_state = "sprayer_med_red"
if("sprayer_med_yellow")
inhand_icon_state = "sprayer_med_yellow"
if("sprayer_med_blue")
inhand_icon_state = "sprayer_med_blue"
M.update_held_items()
/obj/item/reagent_containers/spray/medical/Initialize(mapload, vol)
. = ..()
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/med_spray)
/obj/item/reagent_containers/spray/hercuri
name = "medical spray (hercuri)"
+1
View File
@@ -266,6 +266,7 @@
#include "recycle_recycling.dm"
#include "required_map_items.dm"
#include "resist.dm"
#include "reskin_validation.dm"
#include "reta_system.dm"
#include "say.dm"
#include "screenshot_airlocks.dm"
@@ -0,0 +1,15 @@
/datum/unit_test/reskin_validation
/datum/unit_test/reskin_validation/Run()
var/list/known_names = list()
for(var/datum/atom_skin/skin as anything in valid_subtypesof(/datum/atom_skin))
if(isnull(skin::preview_name))
TEST_FAIL("Reskin [skin] is missing a preview_name.")
// preview names are bundled by abstract types
else if(known_names["[skin::preview_name]-[skin::abstract_type]"])
TEST_FAIL("Reskin [skin] has a duplicate preview_name [skin::preview_name].")
else
known_names["[skin::preview_name]-[skin::abstract_type]"] = TRUE
if(skin::new_icon && skin::new_icon_state && !icon_exists(skin::new_icon, skin::new_icon_state))
TEST_FAIL("Reskin [skin] has a new_icon_state [skin::new_icon_state] that does not exist in file [skin::new_icon].")
+2 -1
View File
@@ -209,6 +209,7 @@
#include "code\__DEFINES\regex.dm"
#include "code\__DEFINES\religion.dm"
#include "code\__DEFINES\research.dm"
#include "code\__DEFINES\reskin.dm"
#include "code\__DEFINES\resonator.dm"
#include "code\__DEFINES\revolution.dm"
#include "code\__DEFINES\robots.dm"
@@ -1271,6 +1272,7 @@
#include "code\datums\components\regenerator.dm"
#include "code\datums\components\religious_tool.dm"
#include "code\datums\components\rename.dm"
#include "code\datums\components\reskinnable_atom.dm"
#include "code\datums\components\revenge_ability.dm"
#include "code\datums\components\rot.dm"
#include "code\datums\components\rotation.dm"
@@ -2371,7 +2373,6 @@
#include "code\game\objects\buckling.dm"
#include "code\game\objects\empulse.dm"
#include "code\game\objects\items.dm"
#include "code\game\objects\items_reskin.dm"
#include "code\game\objects\obj_defense.dm"
#include "code\game\objects\objs.dm"
#include "code\game\objects\structures.dm"
@@ -104,7 +104,7 @@ function LoadoutModifyButtons(props: ButtonsProps) {
<LabeledList>
{!!modifyItemDimmer.reskins && (
<LabeledList.Item label="Styles" verticalAlign="middle">
<Flex wrap width="50%">
<Flex wrap width="100%">
{modifyItemDimmer.reskins.map((reskin) => (
<Flex.Item key={reskin.tooltip} mr={1} mb={1}>
<Button
@@ -123,7 +123,7 @@ function LoadoutModifyButtons(props: ButtonsProps) {
{modifyItemDimmer.icon ? (
<DmIcon
fallback={<Icon name="spinner" spin color="gray" />}
icon={modifyItemDimmer.icon}
icon={reskin.skin_icon || modifyItemDimmer.icon}
icon_state={reskin.skin_icon_state}
style={{
transform: `scale(2) translateY(2px)`,
@@ -194,9 +194,10 @@ export function LoadoutModifyDimmer(props: DimmerProps) {
position: 'relative',
display: 'inline-block',
padding: '5px',
boxShadow: '0px 4px 8px 3px rgba(0, 0, 0, 0.7)',
}}
>
<Stack.Item height="20px">
<Stack.Item height="20px" p={0.5} mb={1}>
<Flex justify="flex-end">
<Flex.Item>
<Button
@@ -225,7 +226,7 @@ export function LoadoutModifyDimmer(props: DimmerProps) {
</Flex>
</Stack.Item>
<Stack.Item>
<Stack justify="center">
<Stack justify="center" p={0.5}>
<Button
onClick={() => {
setModifyItemDimmer(null);
@@ -20,7 +20,8 @@ export type LoadoutList = Record<typePath, LoadoutListInfo>;
export type ReskinOption = {
name: string;
tooltip: string;
skin_icon_state: DmIconState; // The icon is the same as the item icon
skin_icon: DmIconFile | null;
skin_icon_state: DmIconState;
};
export type LoadoutTooltip = {