Fix Zoomed Item Qdel Loop (#19523)

* lets refactor that

* unzoom fix

* taur fix
This commit is contained in:
Will
2026-06-14 02:04:58 -04:00
committed by GitHub
parent 54a68ffffc
commit d96a2fea1c
7 changed files with 42 additions and 38 deletions
+5 -5
View File
@@ -62,13 +62,10 @@
/**
* If an item is coordinating this view (scopes/binoculars)
* Handles remote views that are managed by a held item. The held item must remain in the mob's
* inventory, and will call zoom() and unzoom() when it starts and ends. Optionally showing a message.
* inventory, and will call unzoom() when it ends. Optionally showing a message.
*/
if(isitem(managing_item))
host_item = managing_item
// Unfortunately too many things read this to control item state for me to remove this.
// Oh well! better than GetComponent() everywhere. Lets just manage item/zoom in this component though...
host_item.zoom = TRUE
// Feedback
show_message = show_visible_messages
if(show_message)
@@ -96,7 +93,7 @@
/datum/component/remote_view/Destroy(force)
// Clear item
if(host_item)
host_item.zoom(host_mob)
host_item.unzoom(host_mob)
// Feedback
if(show_message)
host_mob.visible_message(span_filter_notice("[host_item.zoomdevicename ? "[host_mob] looks up from the [host_item.name]" : "[host_mob] lowers the [host_item.name]"]."))
@@ -246,6 +243,9 @@
SIGNAL_HANDLER
SHOULD_NOT_OVERRIDE(TRUE)
PRIVATE_PROC(TRUE)
// Don't forward movement to ourselves if we're using a spyglass or something
if(host_mob == remote_view_target)
return
// I'd move this into the config datum if it didn't require the component to also be passed too. Lets avoid GetComponent on a hotpath.
return settings.handle_relay_movement(src, host_mob, direction)
+23 -18
View File
@@ -61,7 +61,7 @@
var/list/allowed = null //suit storage stuff.
var/obj/item/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers.
var/zoomdevicename = null //name used for message when binoculars/scope is used
var/zoom = 0 //1 if item is actively being used to zoom. For scoped guns and binoculars.
var/zoom = FALSE // if the item is currently zoomed in with a remote view, do not set manually. Handled by remote_view component.
var/embed_chance = -1 //0 won't embed, and 100 will always embed
@@ -841,19 +841,18 @@ GLOBAL_LIST_EMPTY(blood_overlays_by_type)
if(I && !I.abstract)
I.showoff(src)
/// For zooming with scope or binoculars. Uses remote_view/item component for disabling when you move or drop the item
/obj/item/proc/zoom(mob/living/M, tileoffset = 14,viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view
/// For zooming with scope or binoculars. Starts a remote_view when called, which calls unzoom when called again or dropped
/obj/item/proc/toggle_zoom(mob/living/user, tileoffset = 14,viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view
SHOULD_CALL_PARENT(TRUE)
SIGNAL_HANDLER
if(isliving(usr)) //Always prefer usr if set
M = usr
if(!M.client)
if(!user.client)
return FALSE
if(!isliving(M))
if(!isliving(user))
return FALSE
if(isbelly(M.loc) || istype(M.loc,/obj/item/dogborg/sleeper))
if(isbelly(user.loc) || istype(user.loc,/obj/item/dogborg/sleeper))
return FALSE
if(M.is_remote_viewing())
to_chat(M, span_warning("You are too distracted to do that."))
if(user.is_remote_viewing())
to_chat(user, span_warning("You are too distracted to do that."))
return FALSE
var/devicename
@@ -863,22 +862,28 @@ GLOBAL_LIST_EMPTY(blood_overlays_by_type)
devicename = src.name
var/can_zoom = TRUE
if((M.stat && !zoom) || !(ishuman(M)))
to_chat(M, span_filter_notice("You are unable to focus through the [devicename]."))
if((user.stat && !zoom) || !(ishuman(user)))
to_chat(user, span_filter_notice("You are unable to focus through the [devicename]."))
can_zoom = FALSE
else if(!zoom && (GLOB.global_hud.darkMask[1] in M.client.screen))
to_chat(M, span_filter_notice("Your visor gets in the way of looking through the [devicename]."))
else if(!zoom && (GLOB.global_hud.darkMask[1] in user.client.screen))
to_chat(user, span_filter_notice("Your visor gets in the way of looking through the [devicename]."))
can_zoom = FALSE
else if(!zoom && M.get_active_hand() != src)
to_chat(M, span_filter_notice("You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better."))
else if(!zoom && user.get_active_hand() != src)
to_chat(user, span_filter_notice("You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better."))
can_zoom = FALSE
if(!zoom && can_zoom)
M.AddComponent(/datum/component/remote_view, focused_on = M, vconfig_path = /datum/remote_view_config/zoomed_item, managing_item = src, viewsize = viewsize, tileoffset = tileoffset, show_visible_messages = TRUE)
user.AddComponent(/datum/component/remote_view, focused_on = user, vconfig_path = /datum/remote_view_config/zoomed_item, managing_item = src, viewsize = viewsize, tileoffset = tileoffset, show_visible_messages = TRUE)
zoom = TRUE
return
zoom = FALSE
SEND_SIGNAL(src,COMSIG_REMOTE_VIEW_CLEAR)
/// Called by remote view when the view is ended. Do not call manually.
/obj/item/proc/unzoom(mob/user)
SHOULD_CALL_PARENT(TRUE)
SIGNAL_HANDLER
zoom = FALSE
/obj/item/proc/pwr_drain()
return 0 // Process Kill
@@ -17,7 +17,7 @@
. = ..(user)
if(.)
return TRUE
zoom()
toggle_zoom(user)
/obj/item/binoculars/spyglass
name = "spyglass"
+8 -9
View File
@@ -739,25 +739,24 @@
handle_click_empty(user)
return
/obj/item/gun/proc/toggle_scope(zoom_amount=2.0)
/obj/item/gun/proc/toggle_scope(mob/user, zoom_amount=2.0)
//looking through a scope limits your periphereal vision
//still, increase the view size by a tiny amount so that sniping isn't too restricted to NSEW
var/zoom_offset = round(world.view * zoom_amount)
var/view_size = round(world.view + zoom_amount)
var/scoped_accuracy_mod = zoom_offset
zoom(zoom_offset, view_size)
if(zoom)
toggle_zoom(user, zoom_offset, view_size)
if(zoom) // If zoom in was successful
accuracy = scoped_accuracy + scoped_accuracy_mod
if(recoil)
recoil = round(recoil*zoom_amount+1) //recoil is worse when looking through a scope
//make sure accuracy and recoil are reset regardless of how the item is unzoomed.
/obj/item/gun/zoom()
..()
if(!zoom)
accuracy = initial(accuracy)
recoil = initial(recoil)
/obj/item/gun/unzoom()
. = ..()
//make sure accuracy and recoil are reset regardless of how the item is unzoomed.
accuracy = initial(accuracy)
recoil = initial(recoil)
/obj/item/gun/examine(mob/user)
. = ..()
@@ -330,7 +330,7 @@
set name = "Use Scope"
set popup_menu = 1
toggle_scope(2.0)
toggle_scope(usr, 2.0)
/*
* Laser Scattergun (proof of concept)
@@ -428,7 +428,7 @@
set name = "Aim Down Sights"
set popup_menu = 1
toggle_scope(scope_multiplier)
toggle_scope(usr, scope_multiplier)
/obj/item/gun/energy/monorifle/combat
name = "combat mono-rifle"
+1 -1
View File
@@ -205,7 +205,7 @@
set name = "Use Scope"
set popup_menu = 1
toggle_scope(2.0)
toggle_scope(usr, 2.0)
/obj/item/gun/energy/locked/frontier/rifle/update_icon()
if(recharging)
@@ -73,7 +73,7 @@
set name = "Use Scope"
set popup_menu = 1
toggle_scope(2.0)
toggle_scope(usr, 2.0)
////////////// Dragunov Sniper Rifle //////////////
@@ -111,4 +111,4 @@
set name = "Use Scope"
set popup_menu = 1
toggle_scope(2.0)
toggle_scope(usr, 2.0)