From d7585d7d4641214e56663376141efc2cb6bbf8bd Mon Sep 17 00:00:00 2001 From: Aeri <14065903+NanoCats@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:18:49 -0400 Subject: [PATCH] Fixes a duplicate sprite error primarily on firearms. (#6005) ## About The Pull Request Some guns (Probably other items too) have been seeing double for a while now and this isn't just because you're an alcoholic. With certain guns, a Miecz, a Lanca, a Renoster, a Kiboko, the VARS launcher, and the hand slot shows you two sprites offset by about eight pixels, OK actually 8 pixels exactly because that's what the code told it to do. Hold a disabler or a WT-550 and everything is perfectly fine. That was the clue. Every affected gun suffering from this defect drew from an "oversized" sprite sheet. `guns_48.dmi` is 48 pixels wide instead of 32, and a sprite that wide had to carry a negative `base_pixel_x` to sit centered on its tile. Every gun that was fine is a plain 32 by 32 vanilla one sitting at zero. TG doesn't have as many ginormous guns (actually, there are probably a few, but I didn't test every possible gun, that would take too long) **The reason that this matters**: your held item is drawn twice behind the scenes `/mob/living/carbon/human/get_held_overlays()` shoves the item onto your client's screen with a `screen_loc`, which is how hand slots used to work. Hand slots don't work that way any more; someone rewrote inventory slots which now draw the item through the slot's `vis_contents` instead, and upstream deleted their copy of this line at the time. As a downstream, Bubber did not. So both paths have been drawing your item this whole time. Anything sitting at pixel offset zero lands in exactly the same spot twice is invisible. Anything wider than a tile is shifted 8 pixels over, the two copies separate, and you get a freakish mutant ghost gun. This deletes the one line that pushes the item onto your own screen. The observer push underneath it stays so it doesn't break observing people. One line fix, a whole afternoon of fucking around to get there. ## Why It's Good For The Game Guns stop being haunted. The possibility of adding intentionally haunted guns at a later date yet remains. More usefully, this could theoretically afflict any item with a sprite bigger than one tile, not just guns. Guns are simply the most common "oversized sprite" incidence, so that's where it showed up. ## Testing Tested a wide array of items and weapons to make sure the fix works and didn't have any unforeseen negative consequences. Swapped hands, dropped and picked back up, took the item and put it on my vest and took it back out, checked items still stay in the inventory slot properly every time. Ghosted and observed a player holding a gun, still renders correctly. I will note that some sprites still sit very slightly left of centr inside the box, because they keep the offset that centres them on a tile. That's cosmetic and I think it was there before; if anyone actually turns out to care that is a separate issue that will require a separate fix. ## Changelog :cl: fix: Certain items no longer render a doubled ghost copy in your hand slot. /:cl: --- code/modules/mob/living/carbon/human/human_update_icons.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index dfbb7936009..9fda25342b3 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -663,7 +663,10 @@ There are several things that need to be remembered: var/held_index = get_held_index_of_item(worn_item) if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) worn_item.screen_loc = ui_hand_position(held_index) - client.screen += worn_item + // BUBBER EDIT REMOVAL BEGIN - pushing the held item onto our own client's screen here is how + // hand slots worked before the inventory slot rewrite. This alternate behavior is needed to stop duplicate item sprites appearing inhand. + // ORIGINAL: client.screen += worn_item + // BUBBER EDIT REMOVAL END if(observers?.len) for(var/M in observers) var/mob/dead/observe = M