From abc3ceeedc11afdf0f49a36ce86ecf5e9e299993 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 22 Dec 2024 18:56:57 -0500 Subject: [PATCH] adds a component to make it obvious what items came from a gift (#4625) --- .../traits/monkestation/declarations.dm | 2 + code/__DEFINES/~monkestation/vv.dm | 1 + code/__HELPERS/~monkestation-helpers/atoms.dm | 8 ++ code/_globalvars/traits/_traits.dm | 13 +-- code/game/objects/items/gift.dm | 1 + code/modules/admin/verbs/admingame.dm | 12 +++ .../code/datums/components/gift_item.dm | 86 +++++++++++++++++++ tgstation.dme | 2 + 8 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 code/__DEFINES/~monkestation/vv.dm create mode 100644 monkestation/code/datums/components/gift_item.dm diff --git a/code/__DEFINES/traits/monkestation/declarations.dm b/code/__DEFINES/traits/monkestation/declarations.dm index 8a07f00fb954..a26127eb0ff5 100644 --- a/code/__DEFINES/traits/monkestation/declarations.dm +++ b/code/__DEFINES/traits/monkestation/declarations.dm @@ -121,6 +121,8 @@ #define TRAIT_BYPASS_COMPRESS_CHECK "can_compress_anyways" /// This item is considered "trash" (and will be eaten by cleaner slimes) #define TRAIT_TRASH_ITEM "trash_item" +/// This item came from a gift. +#define TRAIT_GIFT_ITEM "gift_item" // /atom/movable /// Things with this trait can pass through wooden barricades. diff --git a/code/__DEFINES/~monkestation/vv.dm b/code/__DEFINES/~monkestation/vv.dm new file mode 100644 index 000000000000..8acf0c7ef495 --- /dev/null +++ b/code/__DEFINES/~monkestation/vv.dm @@ -0,0 +1 @@ +#define VV_HK_EXAMINE_GIFT "examine_gift" diff --git a/code/__HELPERS/~monkestation-helpers/atoms.dm b/code/__HELPERS/~monkestation-helpers/atoms.dm index 67b81a50dafb..44f26ac804e0 100644 --- a/code/__HELPERS/~monkestation-helpers/atoms.dm +++ b/code/__HELPERS/~monkestation-helpers/atoms.dm @@ -26,3 +26,11 @@ default_typecache ||= typecacheof(list(/obj/effect, /atom/movable/screen)) typecache = default_typecache return typecache_filter_list_reverse(src.contents, typecache) + +/// Returns a list of all items in our contents that were obtained from gifts. +/atom/proc/get_all_gift_contents() as /list + RETURN_TYPE(/list/obj/item) + . = list() + for(var/obj/item/thing as anything in get_all_contents_type(/obj/item)) + if(!QDELETED(thing) && HAS_TRAIT(thing, TRAIT_GIFT_ITEM)) + . += thing diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 7734282dd4d7..12590729049c 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -611,24 +611,31 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /obj/item = list( "TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING, + "TRAIT_ASSISTED_BREATHING" = TRAIT_ASSISTED_BREATHING, "TRAIT_BASIC_QUALITY_BAIT" = TRAIT_BASIC_QUALITY_BAIT, "TRAIT_BELT_SATCHEL" = TRAIT_BELT_SATCHEL, "TRAIT_BLIND_TOOL" = TRAIT_BLIND_TOOL, "TRAIT_BYPASS_COMPRESS_CHECK" = TRAIT_BYPASS_COMPRESS_CHECK, "TRAIT_CUSTOM_TAP_SOUND" = TRAIT_CUSTOM_TAP_SOUND, "TRAIT_DANGEROUS_OBJECT" = TRAIT_DANGEROUS_OBJECT, + "TRAIT_FEATHERED" = TRAIT_FEATHERED, "TRAIT_FISHING_BAIT" = TRAIT_FISHING_BAIT, "TRAIT_FOOD_GRILLED" = TRAIT_FOOD_GRILLED, + "TRAIT_GIFT_ITEM" = TRAIT_GIFT_ITEM, "TRAIT_GOOD_QUALITY_BAIT" = TRAIT_GOOD_QUALITY_BAIT, "TRAIT_GREAT_QUALITY_BAIT" = TRAIT_GREAT_QUALITY_BAIT, "TRAIT_HAUNTED" = TRAIT_HAUNTED, "TRAIT_HONKSPAMMING" = TRAIT_HONKSPAMMING, "TRAIT_INNATELY_FANTASTICAL_ITEM" = TRAIT_INNATELY_FANTASTICAL_ITEM, + "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS, + "TRAIT_LABOURED_BREATHING" = TRAIT_LABOURED_BREATHING, "TRAIT_MAT_TRANSMUTED" = TRAIT_MAT_TRANSMUTED, "TRAIT_MAY_CONTAIN_BLENDED_DUST" = TRAIT_MAY_CONTAIN_BLENDED_DUST, "TRAIT_NEEDS_TWO_HANDS" = TRAIT_NEEDS_TWO_HANDS, "TRAIT_NODROP" = TRAIT_NODROP, + "TRAIT_NON_IMPORTANT_SHOE_BLOCK" = TRAIT_NON_IMPORTANT_SHOE_BLOCK, "TRAIT_NO_BARCODES" = TRAIT_NO_BARCODES, + "TRAIT_NO_ORGAN_DECAY" = TRAIT_NO_ORGAN_DECAY, "TRAIT_NO_STORAGE_INSERT" = TRAIT_NO_STORAGE_INSERT, "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT, "TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT, @@ -639,17 +646,11 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_T_RAY_VISIBLE" = TRAIT_T_RAY_VISIBLE, "TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE, "TRAIT_WIELDED" = TRAIT_WIELDED, - "TRAIT_FEATHERED" = TRAIT_FEATHERED, - "TRAIT_NON_IMPORTANT_SHOE_BLOCK" = TRAIT_NON_IMPORTANT_SHOE_BLOCK, - "TRAIT_LABOURED_BREATHING" = TRAIT_LABOURED_BREATHING, - "TRAIT_ASSISTED_BREATHING" = TRAIT_ASSISTED_BREATHING, - "TRAIT_NO_ORGAN_DECAY" = TRAIT_NO_ORGAN_DECAY, /* "TRAIT_BAIT_UNCONSUMABLE" = TRAIT_BAIT_UNCONSUMABLE, */ /* "TRAIT_BAKEABLE" = TRAIT_BAKEABLE, */ /* "TRAIT_BYPASS_RANGED_ARMOR" = TRAIT_BYPASS_RANGED_ARMOR, */ /* "TRAIT_CONTRABAND_BLOCKER" = TRAIT_CONTRABAND_BLOCKER, */ /* "TRAIT_GERM_SENSITIVE" = TRAIT_GERM_SENSITIVE, */ - "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS, /* "TRAIT_ITEM_OBJECTIVE_BLOCKED" = TRAIT_ITEM_OBJECTIVE_BLOCKED, */ /* "TRAIT_NO_SIDE_KICK" = TRAIT_NO_SIDE_KICK, */ ), diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm index c1a5e10a1b38..16913a80c04d 100644 --- a/code/game/objects/items/gift.dm +++ b/code/game/objects/items/gift.dm @@ -50,6 +50,7 @@ GLOBAL_LIST_EMPTY(possible_gifts) M.investigate_log("has unwrapped a present containing [I.type].", INVESTIGATE_PRESENTS) M.put_in_hands(I) I.add_fingerprint(M) + I.AddComponent(/datum/component/gift_item, M) // monkestation edit: gift item info component else M.visible_message(span_danger("Oh no! The present that [M] opened had nothing inside it!")) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 670b2c76ec76..340cc3d17faa 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -45,6 +45,18 @@ full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" body += "
\[Byond version: [full_version]\]
" + // monkestation start: gift info + var/list/gifts = M.get_all_gift_contents() + var/gift_amt = length(gifts) + if(gift_amt) + body += "

Gift items in contents:
" + for(var/idx in 1 to gift_amt) + var/obj/item/gift = gifts[idx] + body += VV_HREF_TARGET(gift, VV_HK_EXAMINE_GIFT, "[gift.name] ([gift.type])") + if(idx < gift_amt) + body += "
" + // monkestation end + body += "

\[ " body += "VV - " diff --git a/monkestation/code/datums/components/gift_item.dm b/monkestation/code/datums/components/gift_item.dm new file mode 100644 index 000000000000..d6f82e9fa89a --- /dev/null +++ b/monkestation/code/datums/components/gift_item.dm @@ -0,0 +1,86 @@ +/// Simple thing that marks an items as having come from a gift. +/datum/component/gift_item + /// The ckey of the player who opened the gift. + var/ckey + /// Weakref to the mob who opened the gift. + var/datum/weakref/giftee + /// Weakref to the mob who opened the gift. + var/datum/weakref/mind + /// The (real) name of mob who opened the gift. + var/name + /// The `world.time` when the gift was opened. + var/open_world_time + /// The `world.timeofday` when the gift was opened. + var/open_timeofday + +/datum/component/gift_item/Initialize(mob/living/giftee) + if(!isitem(parent)) + stack_trace("Tried to assign [type] to a non-item") + return COMPONENT_INCOMPATIBLE + if(!isliving(giftee)) + stack_trace("Tried to assign [type] to something that wasn't a living mob!") + return COMPONENT_INCOMPATIBLE + if(!giftee.ckey) + stack_trace("Tried to assign [type] to a non-player mob!") + return COMPONENT_INCOMPATIBLE + src.ckey = giftee.ckey + src.giftee = WEAKREF(giftee) + src.mind = WEAKREF(giftee.mind) + src.name = "[giftee.mind?.name || giftee.real_name || giftee.name || "N/A"]" + src.open_world_time = world.time + src.open_timeofday = world.timeofday + +/datum/component/gift_item/Destroy(force) + giftee = null + mind = null + return ..() + +/datum/component/gift_item/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more)) + RegisterSignal(parent, COMSIG_VV_TOPIC, PROC_REF(handle_vv_topic)) + ADD_TRAIT(parent, TRAIT_GIFT_ITEM, type) + +/datum/component/gift_item/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_EXAMINE_MORE, COMSIG_VV_TOPIC)) + REMOVE_TRAIT(parent, TRAIT_GIFT_ITEM, type) + +/datum/component/gift_item/proc/on_examine(obj/item/source, mob/examiner, list/examine_text) + SIGNAL_HANDLER + if(check_rights_for(examiner.client, R_ADMIN)) + // ensure we always target the right mob for the admin buttons + var/mob/target_mob = resolve_opener_mob() + examine_text += "" + examine_text += span_bold("\[") + span_info(" This item came from a gift opened by [span_name(name)] ([ckey]) [ADMIN_FULLMONTY_NONAME(target_mob)] ") + span_bold("\]") + examine_text += span_bold("\[") + span_info(" It was unwrapped from a gift [span_bold(DisplayTimeText(world.time - open_world_time) + " ago")], at server time [span_bold(time2text(open_timeofday, "YYYY-MM-DD hh:mm:ss"))] ") + span_bold("\]") + examine_text += "" + else if(isobserver(examiner) || HAS_TRAIT(examiner, TRAIT_PRESENT_VISION) || SSticker.current_state >= GAME_STATE_FINISHED) + examine_text += "" + examine_text += span_bold("\[") + span_info(" This item came from a gift opened by [span_name(name)] [DisplayTimeText(world.time - open_world_time)] ago ") + span_bold("\]") + examine_text += "" + +/datum/component/gift_item/proc/on_examine_more(obj/item/source, mob/examiner, list/examine_text) + SIGNAL_HANDLER + examine_text += span_info("This item seems to have been a gift!") + +/datum/component/gift_item/proc/resolve_opener_mob() as /mob + RETURN_TYPE(/mob) + var/mob/opener = giftee.resolve() + var/datum/mind/opener_mind = mind.resolve() + if(opener?.ckey == ckey) + return opener + else if(opener_mind?.current?.ckey == ckey) + return opener_mind.current + else if(GLOB.directory[ckey]) + var/client/current_client = GLOB.directory[ckey] + return current_client.mob + else + for(var/mob/mob in GLOB.mob_list) + if(mob.ckey == ckey) + return mob + +/datum/component/gift_item/proc/handle_vv_topic(datum/source, mob/user, list/href_list) + SIGNAL_HANDLER + if(href_list[VV_HK_EXAMINE_GIFT] && check_rights(R_ADMIN)) + user.examinate(parent) + return COMPONENT_VV_HANDLED diff --git a/tgstation.dme b/tgstation.dme index 12c9484b8077..830016c00216 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -469,6 +469,7 @@ #include "code\__DEFINES\~monkestation\twitch.dm" #include "code\__DEFINES\~monkestation\uplink.dm" #include "code\__DEFINES\~monkestation\virology.dm" +#include "code\__DEFINES\~monkestation\vv.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_blueshift.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" @@ -5955,6 +5956,7 @@ #include "monkestation\code\datums\components\carbon_sprint.dm" #include "monkestation\code\datums\components\charge_adjuster.dm" #include "monkestation\code\datums\components\crafting.dm" +#include "monkestation\code\datums\components\gift_item.dm" #include "monkestation\code\datums\components\gps.dm" #include "monkestation\code\datums\components\irradiated.dm" #include "monkestation\code\datums\components\lock_on_cursor.dm"