mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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?
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
+5
-4
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user