Files
GS13NG/code/datums/elements/object_reskinning.dm
2023-10-03 14:29:17 -03:00

119 lines
4.1 KiB
Plaintext

/*
* # Element: Object Reskinning
*
* Allows players to modify the appearance of their object (and other attributes if possible)
* PLEASE DO NOT HAVE INVALID VALUES IN unique_reskin I DON'T EVEN WANT TO KNOW WHAT HAPPENS.
* USAGE:
* unique_reskins = list(
* "skin 1" = list(
* "desc" = "very cool description",
* "icon" = 'very_cool_icon.dmi'
* ),
* "skin 2" = list(
* "desc" = "not as cool description",
* "icon" = 'the_boring_skin.dmi'
* )
* )
*/
/datum/element/object_reskinning
element_flags = ELEMENT_DETACH
/datum/element/object_reskinning/Attach(obj/target)
. = ..()
if(!istype(target))
return ELEMENT_INCOMPATIBLE
if(!islist(target.unique_reskin) || !length(target.unique_reskin))
message_admins("[src] was given to an object without any unique reskins, if you really need to, give it a couple skins first.")
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(target, target.reskin_binding, .proc/reskin)
RegisterSignal(target, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, .proc/on_requesting_context_from_item)
/datum/element/object_reskinning/Detach(obj/source, force)
UnregisterSignal(source, list(COMSIG_PARENT_EXAMINE, source.reskin_binding, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM))
return ..()
/datum/element/object_reskinning/proc/on_examine(obj/obj, mob/user, list/examine_list)
examine_list += span_notice("[capitalize(replacetext(obj.reskin_binding, "_", "-"))] to reskin it ([length(obj.unique_reskin)] possible styles).")
if(obj.always_reskinnable)
examine_list += span_notice("It has no limit to reskinning.")
/*
* Reskins an object according to user's choice.
* Will detach itself if there's no skins or if done successfully but not always reskinnable.
*
* Arguments:
* * to_reskin The object we will be reskinning
* * user The user who wants to choose a skin for the object
*/
/datum/element/object_reskinning/proc/reskin(obj/to_reskin, mob/user)
// Just stop early
if(!LAZYLEN(to_reskin.unique_reskin))
message_admins("[ADMIN_LOOKUPFLW(user)] attempted to reskin an object that has no skins!")
Detach(to_reskin)
return FALSE
// Can't use
if(!user.canUseTopic(to_reskin, BE_CLOSE, NO_DEXTERY, NO_TK))
return FALSE
// Get our choices
var/list/items = list()
for(var/reskin_option in to_reskin.unique_reskin)
var/image/item_image = image(
icon = to_reskin.unique_reskin[reskin_option]["icon"] ? to_reskin.unique_reskin[reskin_option]["icon"] : to_reskin.icon,
icon_state = to_reskin.unique_reskin[reskin_option]["icon_state"] ? to_reskin.unique_reskin[reskin_option]["icon_state"] : to_reskin.icon_state)
items += list("[reskin_option]" = item_image)
sortList(items)
// Display to the user
var/pick = show_radial_menu(user, to_reskin, items, custom_check = CALLBACK(src, .proc/check_reskin_menu, user, to_reskin), radius = 38, require_near = TRUE)
if(!pick)
return FALSE
// Finish the work
to_reskin.current_skin = pick
for(var/reskin_var in to_reskin.unique_reskin[pick])
to_reskin.vars[reskin_var] = to_reskin.unique_reskin[pick][reskin_var]
to_chat(user, "[to_reskin] is now skinned as '[pick].'")
to_reskin.reskin_obj(user)
// Only once or always?
if(!to_reskin.always_reskinnable)
Detach(to_reskin)
return TRUE
/**
* Checks if we are allowed to interact with a radial menu for reskins
*
* Arguments:
* * user The mob interacting with the menu
* * obj The obj to be checking against
*/
/datum/element/object_reskinning/proc/check_reskin_menu(mob/user, obj/obj)
if(QDELETED(obj))
return FALSE
if(!obj.always_reskinnable && obj.current_skin)
return FALSE
if(!istype(user))
return FALSE
if(user.incapacitated())
return FALSE
return TRUE
/datum/element/object_reskinning/proc/on_requesting_context_from_item(
obj/source,
list/context,
obj/item/held_item,
mob/living/user,
)
SIGNAL_HANDLER
switch(source.reskin_binding)
if(COMSIG_CLICK_CTRL_SHIFT)
LAZYSET(context[SCREENTIP_CONTEXT_CTRL_SHIFT_LMB], INTENT_ANY, "Reskin PDA")
else
LAZYSET(context[SCREENTIP_CONTEXT_ALT_LMB], INTENT_ANY, "Reskin [source]")
return CONTEXTUAL_SCREENTIP_SET