From 987290fcd4369dc2d000f020ecf74710f1c02bcc Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:22:18 +0000 Subject: [PATCH 1/7] Version 1 (index) --- code/_onclick/hud/screen_objects.dm | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index e4e8ff64c19c..989681f1d10c 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -519,12 +519,15 @@ return FALSE if(mods["alt"]) var/list/options = list() + /* ---- Queen ---- */ if(user.hive.living_xeno_queen) options["Queen"] = list(TRACKER_QUEEN, 0) + /* ---- Hive Core ---- */ if(user.hive.hive_location) options["Hive Core"] = list(TRACKER_HIVE, 0) + /* ---- Leaders ---- */ var/xeno_leader_index = 1 for(var/xeno in user.hive.xeno_leader_list) var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[xeno_leader_index] @@ -532,11 +535,22 @@ options["Xeno Leader [xeno_lead]"] = list(TRACKER_LEADER, xeno_leader_index) xeno_leader_index++ + /* ---- Tunnels ---- */ + // Assoc list of '{tunnel: the tunnel's index in `hive.tunnels`}'. + var/list/tunnel_to_index = list() + for(var/I in 1 to length(user.hive.tunnels)) + tunnel_to_index[user.hive.tunnels[I]] = I + + // A copy of `hive.tunnels`, but sorted by each tunnel's distance to the user. var/list/sorted_tunnels = sort_list_dist(user.hive.tunnels, get_turf(user)) - var/tunnel_index = 1 - for(var/obj/structure/tunnel/tunnel in sorted_tunnels) - options["Tunnel [tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, tunnel_index) - tunnel_index++ + + // The `tunnel_to_index` assoc list, but in the order of `sorted_tunnels`. + var/list/sorted_tunnel_to_index = list() + for(var/tunnel in sorted_tunnels) + sorted_tunnel_to_index[tunnel] = tunnel_to_index[tunnel] + + for(var/obj/structure/tunnel/tunnel in sorted_tunnel_to_index) + options["Tunnel [tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, sorted_tunnel_to_index[tunnel]) var/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) if(selected) From b7f0fdedbcef03e406c9d0609ac68a767bdbea4b Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:22:28 +0000 Subject: [PATCH 2/7] Revert "Version 1 (index)" This reverts commit 987290fcd4369dc2d000f020ecf74710f1c02bcc. --- code/_onclick/hud/screen_objects.dm | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 989681f1d10c..e4e8ff64c19c 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -519,15 +519,12 @@ return FALSE if(mods["alt"]) var/list/options = list() - /* ---- Queen ---- */ if(user.hive.living_xeno_queen) options["Queen"] = list(TRACKER_QUEEN, 0) - /* ---- Hive Core ---- */ if(user.hive.hive_location) options["Hive Core"] = list(TRACKER_HIVE, 0) - /* ---- Leaders ---- */ var/xeno_leader_index = 1 for(var/xeno in user.hive.xeno_leader_list) var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[xeno_leader_index] @@ -535,22 +532,11 @@ options["Xeno Leader [xeno_lead]"] = list(TRACKER_LEADER, xeno_leader_index) xeno_leader_index++ - /* ---- Tunnels ---- */ - // Assoc list of '{tunnel: the tunnel's index in `hive.tunnels`}'. - var/list/tunnel_to_index = list() - for(var/I in 1 to length(user.hive.tunnels)) - tunnel_to_index[user.hive.tunnels[I]] = I - - // A copy of `hive.tunnels`, but sorted by each tunnel's distance to the user. var/list/sorted_tunnels = sort_list_dist(user.hive.tunnels, get_turf(user)) - - // The `tunnel_to_index` assoc list, but in the order of `sorted_tunnels`. - var/list/sorted_tunnel_to_index = list() - for(var/tunnel in sorted_tunnels) - sorted_tunnel_to_index[tunnel] = tunnel_to_index[tunnel] - - for(var/obj/structure/tunnel/tunnel in sorted_tunnel_to_index) - options["Tunnel [tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, sorted_tunnel_to_index[tunnel]) + var/tunnel_index = 1 + for(var/obj/structure/tunnel/tunnel in sorted_tunnels) + options["Tunnel [tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, tunnel_index) + tunnel_index++ var/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) if(selected) From 0c0fe20b0b525606ba6f0e1d8ec963c90193244f Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:33:51 +0000 Subject: [PATCH 3/7] Version 2 (weakref) --- code/_onclick/hud/screen_objects.dm | 39 +++++++---- .../mob/living/carbon/xenomorph/life.dm | 68 ++++--------------- 2 files changed, 40 insertions(+), 67 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index e4e8ff64c19c..fbe531faa581 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -505,7 +505,11 @@ name = "queen locator" icon = 'icons/mob/hud/alien_standard.dmi' icon_state = "trackoff" - var/list/track_state = list(TRACKER_QUEEN, 0) + /// A weak reference to the atom currently being tracked. + /// (Note: This is null for `TRACKER_QUEEN` and `TRACKER_HIVE`, as those are accessed through the user's hive datum.) + var/datum/weakref/tracking_ref = null + /// The 'category' of the atom currently being tracked. (Defaults to `TRACKER_QUEEN`) + var/tracker_type = TRACKER_QUEEN /atom/movable/screen/queen_locator/clicked(mob/living/carbon/xenomorph/user, mods) if(!istype(user)) @@ -520,28 +524,29 @@ if(mods["alt"]) var/list/options = list() if(user.hive.living_xeno_queen) - options["Queen"] = list(TRACKER_QUEEN, 0) + // Don't need weakrefs to this or the hive core, since there's only one possible target. + options["Queen"] = list(null, TRACKER_QUEEN) if(user.hive.hive_location) - options["Hive Core"] = list(TRACKER_HIVE, 0) + options["Hive Core"] = list(null, TRACKER_HIVE) - var/xeno_leader_index = 1 - for(var/xeno in user.hive.xeno_leader_list) - var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[xeno_leader_index] + for(var/leader_slot in user.hive.xeno_leader_list) + var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[leader_slot] + // If there's a leader assigned to the slot. if(xeno_lead) - options["Xeno Leader [xeno_lead]"] = list(TRACKER_LEADER, xeno_leader_index) - xeno_leader_index++ + options["Xeno Leader [xeno_lead]"] = list(WEAKREF(xeno_lead), TRACKER_LEADER) var/list/sorted_tunnels = sort_list_dist(user.hive.tunnels, get_turf(user)) - var/tunnel_index = 1 - for(var/obj/structure/tunnel/tunnel in sorted_tunnels) - options["Tunnel [tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, tunnel_index) - tunnel_index++ + for(var/obj/structure/tunnel/tunnel as anything in sorted_tunnels) + options["Tunnel [tunnel.tunnel_desc]"] = list(WEAKREF(tunnel), TRACKER_TUNNEL) - var/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) + var/list/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) if(selected) - track_state = options[selected] + var/selected_data = options[selected] + tracking_ref = selected_data[1] // Weakref to the tracked atom, or null + tracker_type = selected_data[2] // Tracker category return + if(!user.hive.living_xeno_queen) to_chat(user, SPAN_WARNING("Our hive doesn't have a living queen!")) return FALSE @@ -549,6 +554,12 @@ return FALSE user.overwatch(user.hive.living_xeno_queen) +// Reset to the defaults +/atom/movable/screen/queen_locator/proc/stop_tracking() + icon_state = "trackoff" + tracking_ref = null + tracker_type = TRACKER_QUEEN + /atom/movable/screen/xenonightvision icon = 'icons/mob/hud/alien_standard.dmi' name = "toggle night vision" diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index aab61776118d..f4d39f634f00 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -391,75 +391,37 @@ Make sure their actual health updates immediately.*/ hud_set_plasma() //update plasma amount on the plasma mob_hud /mob/living/carbon/xenomorph/proc/queen_locator() - if(!hud_used || !hud_used.locate_leader) + if(!hud_used?.locate_leader) return - var/atom/movable/screen/queen_locator/QL = hud_used.locate_leader - if(!loc) - QL.icon_state = "trackoff" + var/atom/movable/screen/queen_locator/locator = hud_used.locate_leader + if(!loc || !hive) + locator.stop_tracking() return var/atom/tracking_atom - switch(QL.track_state[1]) + switch(locator.tracker_type) if(TRACKER_QUEEN) - if(!hive || !hive.living_xeno_queen) - QL.icon_state = "trackoff" - return tracking_atom = hive.living_xeno_queen if(TRACKER_HIVE) - if(!hive || !hive.hive_location) - QL.icon_state = "trackoff" - return tracking_atom = hive.hive_location - if(TRACKER_LEADER) - if(!QL.track_state[2]) - QL.icon_state = "trackoff" - return - - var/leader_tracker = QL.track_state[2] - - if(!hive || !hive.xeno_leader_list) - QL.icon_state = "trackoff" - return - if(leader_tracker > hive.xeno_leader_list.len) - QL.icon_state = "trackoff" - return - if(!hive.xeno_leader_list[leader_tracker]) - QL.icon_state = "trackoff" - return - tracking_atom = hive.xeno_leader_list[leader_tracker] - if(TRACKER_TUNNEL) - if(!QL.track_state[2]) - QL.icon_state = "trackoff" - return - - var/tunnel_tracker = QL.track_state[2] - - if(!hive || !hive.tunnels) - QL.icon_state = "trackoff" - return - if(tunnel_tracker > hive.tunnels.len) - QL.icon_state = "trackoff" - return - if(!hive.tunnels[tunnel_tracker]) - QL.icon_state = "trackoff" - return - tracking_atom = hive.tunnels[tunnel_tracker] + if(TRACKER_LEADER, TRACKER_TUNNEL) + tracking_atom = locator.tracking_ref.resolve() if(!tracking_atom) - QL.icon_state = "trackoff" + locator.stop_tracking() return if(tracking_atom.loc.z != loc.z || get_dist(src, tracking_atom) < 1 || src == tracking_atom) - QL.icon_state = "trackondirect" + locator.icon_state = "trackondirect" else - var/area/A = get_area(loc) - var/area/QA = get_area(tracking_atom.loc) - if(A.fake_zlevel == QA.fake_zlevel) - QL.setDir(Get_Compass_Dir(src, tracking_atom)) - QL.icon_state = "trackon" + var/area/our_area = get_area(loc) + var/area/target_area = get_area(tracking_atom.loc) + if(our_area.fake_zlevel == target_area.fake_zlevel) + locator.setDir(Get_Compass_Dir(src, tracking_atom)) + locator.icon_state = "trackon" else - QL.icon_state = "trackondirect" + locator.icon_state = "trackondirect" /mob/living/carbon/xenomorph/proc/mark_locator() if(!hud_used || !hud_used.locate_marker || !tracked_marker.loc || !loc) From 58c059460222986a6934e77df9e6024adec31f5b Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:24:33 +0000 Subject: [PATCH 4/7] Xeno leader fix I misunderstood how the `xeno_leader_list` works. (It isn't associative, just fixed length.) --- code/_onclick/hud/screen_objects.dm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index fbe531faa581..680316536e28 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -530,11 +530,8 @@ if(user.hive.hive_location) options["Hive Core"] = list(null, TRACKER_HIVE) - for(var/leader_slot in user.hive.xeno_leader_list) - var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[leader_slot] - // If there's a leader assigned to the slot. - if(xeno_lead) - options["Xeno Leader [xeno_lead]"] = list(WEAKREF(xeno_lead), TRACKER_LEADER) + for(var/mob/living/carbon/xenomorph/leader in user.hive.xeno_leader_list) + options["Xeno Leader [leader]"] = list(WEAKREF(leader), TRACKER_LEADER) var/list/sorted_tunnels = sort_list_dist(user.hive.tunnels, get_turf(user)) for(var/obj/structure/tunnel/tunnel as anything in sorted_tunnels) From 3056491d78a86a4c9904e80f8d31b7cb8312bf31 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:12:29 +0000 Subject: [PATCH 5/7] Better weakrefs Plus a fix for if someone got de-leadered --- code/_onclick/hud/screen_objects.dm | 6 +++--- code/modules/mob/living/carbon/xenomorph/life.dm | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 680316536e28..f7638a8e9e76 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -531,16 +531,16 @@ options["Hive Core"] = list(null, TRACKER_HIVE) for(var/mob/living/carbon/xenomorph/leader in user.hive.xeno_leader_list) - options["Xeno Leader [leader]"] = list(WEAKREF(leader), TRACKER_LEADER) + options["Xeno Leader [leader]"] = list(leader, TRACKER_LEADER) var/list/sorted_tunnels = sort_list_dist(user.hive.tunnels, get_turf(user)) for(var/obj/structure/tunnel/tunnel as anything in sorted_tunnels) - options["Tunnel [tunnel.tunnel_desc]"] = list(WEAKREF(tunnel), TRACKER_TUNNEL) + options["Tunnel [tunnel.tunnel_desc]"] = list(tunnel, TRACKER_TUNNEL) var/list/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) if(selected) var/selected_data = options[selected] - tracking_ref = selected_data[1] // Weakref to the tracked atom, or null + tracking_ref = WEAKREF(selected_data[1]) // Weakref to the tracked atom (or null) tracker_type = selected_data[2] // Tracker category return diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index f4d39f634f00..2b6623d6c516 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -405,8 +405,13 @@ Make sure their actual health updates immediately.*/ tracking_atom = hive.living_xeno_queen if(TRACKER_HIVE) tracking_atom = hive.hive_location - if(TRACKER_LEADER, TRACKER_TUNNEL) - tracking_atom = locator.tracking_ref.resolve() + if(TRACKER_LEADER) + var/atom/leader = locator.tracking_ref?.resolve() + // If the leader exists, and is actually in the leader list. + if(leader && (leader in hive.xeno_leader_list)) + tracking_atom = leader + if(TRACKER_TUNNEL) + tracking_atom = locator.tracking_ref?.resolve() if(!tracking_atom) locator.stop_tracking() From 586921103df93d09bc7e6237d5e859260046e2c0 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:41:58 +0000 Subject: [PATCH 6/7] Smoother failure state Rather than the tracker going blank for one life tick if it can't find `tracking_atom`, this makes it immediately swap to the queen. --- code/_onclick/hud/screen_objects.dm | 2 +- code/modules/mob/living/carbon/xenomorph/life.dm | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index f7638a8e9e76..1eb555fceaf7 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -552,7 +552,7 @@ user.overwatch(user.hive.living_xeno_queen) // Reset to the defaults -/atom/movable/screen/queen_locator/proc/stop_tracking() +/atom/movable/screen/queen_locator/proc/reset_tracking() icon_state = "trackoff" tracking_ref = null tracker_type = TRACKER_QUEEN diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 2b6623d6c516..0f230afeec15 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -396,7 +396,7 @@ Make sure their actual health updates immediately.*/ var/atom/movable/screen/queen_locator/locator = hud_used.locate_leader if(!loc || !hive) - locator.stop_tracking() + locator.reset_tracking() return var/atom/tracking_atom @@ -413,8 +413,17 @@ Make sure their actual health updates immediately.*/ if(TRACKER_TUNNEL) tracking_atom = locator.tracking_ref?.resolve() + // If the atom can't be found/has been deleted. if(!tracking_atom) - locator.stop_tracking() + var/already_tracking_queen = (locator.tracker_type == TRACKER_QUEEN) + + // Reset the tracker back to the queen. + locator.reset_tracking() + + // If it wasn't the queen that couldn't be found above, try again with her as the target. + // (There's no risk of an infinite loop here since `locator.tracker_type` just got set to `TRACKER_QUEEN`.) + if(!already_tracking_queen) + queen_locator() return if(tracking_atom.loc.z != loc.z || get_dist(src, tracking_atom) < 1 || src == tracking_atom) From 93684768a8326be4f0fcbc38ca64bc5001fb2738 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Thu, 25 Jan 2024 19:42:09 +0000 Subject: [PATCH 7/7] Clarification --- code/modules/mob/living/carbon/xenomorph/life.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 0f230afeec15..d5ca8a41fa39 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -421,6 +421,7 @@ Make sure their actual health updates immediately.*/ locator.reset_tracking() // If it wasn't the queen that couldn't be found above, try again with her as the target. + // This is just to avoid the tracker going blank for one life tick. // (There's no risk of an infinite loop here since `locator.tracker_type` just got set to `TRACKER_QUEEN`.) if(!already_tracking_queen) queen_locator()