From 37df0a0cbe280e2bfae74bba28ada81ef93b94cd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 27 Jan 2026 19:16:15 -0500 Subject: [PATCH] Lootpanel Improvements (#94995) ## About The Pull Request Makes the lootpanel act like you'd expect it to. ## Why It's Good For The Game You should not need to manually refresh the loot panel. You should not be able to monitor a turf on the other side of the station. ## Changelog :cl: fix: The lootpanel will now properly close with distance from the target like most other tguis. qol: The lootpanel will now automatically refresh when new items enter it. Removed the manual refresh button. /:cl: Co-authored-by: Jordan Dominion --- code/modules/lootpanel/_lootpanel.dm | 14 +++---- code/modules/lootpanel/contents.dm | 41 ++++++++++++++----- code/modules/lootpanel/misc.dm | 5 +++ .../tgui/interfaces/LootPanel/index.tsx | 14 ++----- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/code/modules/lootpanel/_lootpanel.dm b/code/modules/lootpanel/_lootpanel.dm index ab13a7c2116..c4215b60f95 100644 --- a/code/modules/lootpanel/_lootpanel.dm +++ b/code/modules/lootpanel/_lootpanel.dm @@ -38,9 +38,14 @@ ui.open() +/datum/lootpanel/ui_host(mob/user) + return source_turf + + /datum/lootpanel/ui_close(mob/user) . = ..() + UnregisterSignal(source_turf, COMSIG_ATOM_ENTERED) source_turf = null reset_contents() @@ -55,13 +60,6 @@ return data -/datum/lootpanel/ui_status(mob/user, datum/ui_state/state) - if(user.incapacitated) - return UI_DISABLED - - return UI_INTERACTIVE - - /datum/lootpanel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) @@ -70,7 +68,5 @@ switch(action) if("grab") return grab(usr, params) - if("refresh") - return populate_contents() return FALSE diff --git a/code/modules/lootpanel/contents.dm b/code/modules/lootpanel/contents.dm index 2fcd4201d8a..1fa72ae1372 100644 --- a/code/modules/lootpanel/contents.dm +++ b/code/modules/lootpanel/contents.dm @@ -21,19 +21,38 @@ if(!istype(thing)) stack_trace("Non-atom in the contents of [source_turf]!") continue - if(QDELETED(thing)) - continue - if(thing.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) - continue - if(thing.IsObscured()) - continue - if(thing.invisibility > owner.mob.see_invisible) - continue - // convert - var/datum/search_object/index = new(owner, thing) - add_to_index(index) + add_new_searchable(thing, FALSE) + queue_update() + +/datum/lootpanel/proc/on_source_turf_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) + SIGNAL_HANDLER + + // async because the same move handler we register with this can trigger on the /datum/search_object later in this event + // deleting it just as we added it + addtimer(CALLBACK(src, PROC_REF(add_new_searchable), arrived, TRUE), 0) + +/datum/lootpanel/proc/add_new_searchable(atom/movable/thing, from_signal) + if(QDELETED(thing)) + return + if(thing.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) + return + if(thing.IsObscured()) + return + if(thing.invisibility > owner.mob.see_invisible) + return + if(from_signal && (!source_turf || !(thing in source_turf.contents))) + return + + // convert + var/datum/search_object/index = new(owner, thing) + add_to_index(index) + + if(from_signal) + queue_update() + +/datum/lootpanel/proc/queue_update() var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) window?.send_update() diff --git a/code/modules/lootpanel/misc.dm b/code/modules/lootpanel/misc.dm index 4fc3af2da29..2a5123752a2 100644 --- a/code/modules/lootpanel/misc.dm +++ b/code/modules/lootpanel/misc.dm @@ -1,5 +1,10 @@ /// Helper to open the panel /datum/lootpanel/proc/open(turf/tile) + if (tile != source_turf) + if (source_turf) + UnregisterSignal(source_turf, COMSIG_ATOM_ENTERED) + RegisterSignal(tile, COMSIG_ATOM_ENTERED, PROC_REF(on_source_turf_entered)) + source_turf = tile #if !defined(OPENDREAM) && !defined(UNIT_TESTS) diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx index cd7bb56853c..f4295558725 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/index.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -1,9 +1,7 @@ -import { useState } from 'react'; -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { Button, Input, Section, Stack } from 'tgui-core/components'; import { isEscape } from 'tgui-core/keys'; import { clamp } from 'tgui-core/math'; -import type { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../../backend'; import { Window } from '../../layouts'; @@ -13,12 +11,11 @@ import type { SearchItem } from './types'; type Data = { contents: SearchItem[]; - searching: BooleanLike; }; export function LootPanel(props) { - const { act, data } = useBackend(); - const { contents = [], searching } = data; + const { data } = useBackend(); + const { contents = [] } = data; // limitations: items with different stack counts, charges etc. const contentsByPathName = useMemo(() => { @@ -71,11 +68,6 @@ export function LootPanel(props) { onClick={() => setGrouping(!grouping)} tooltip="Toggle Grouping" /> -