mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-26 00:51:23 +00:00
## About The Pull Request #83186 made it so ghosts are fooled by disguises, like wearing a mask and an ID. This PR fixes that behavior, instead always displaying the person's real name and their face/ID name (if their face name is somehow different from real name) in brackets. Additionally, this PR makes orbit menu prioritize "real" job name and icon, aka the ones the person spawned with. If they don't have an assigned job, it will fall back to current behavior of looking it up from their ID. Also, searching people includes both their fake and real name. ## Why It's Good For The Game Ghosts really, really shouldn't be fooled by wearing a gas mask and an ID. **Especially** admin ghosts. ## Changelog 🆑 qol: Ghost orbit menu now always displays person's real name and their roundstart job and cannot be fooled by disguises. /🆑
307 lines
8.5 KiB
Plaintext
307 lines
8.5 KiB
Plaintext
GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new)
|
|
|
|
/datum/orbit_menu
|
|
///mobs worth orbiting. Because spaghetti, all mobs have the point of interest, but only some are allowed to actually show up.
|
|
///this obviously should be changed in the future, so we only add mobs as POI if they actually are interesting, and we don't use
|
|
///a typecache.
|
|
var/static/list/mob_allowed_typecache
|
|
|
|
/datum/orbit_menu/ui_state(mob/user)
|
|
return GLOB.observer_state
|
|
|
|
/datum/orbit_menu/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if (!ui)
|
|
ui = new(user, src, "Orbit")
|
|
ui.open()
|
|
|
|
/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
if("orbit")
|
|
var/ref = params["ref"]
|
|
var/auto_observe = params["auto_observe"]
|
|
var/atom/poi = SSpoints_of_interest.get_poi_atom_by_ref(ref)
|
|
|
|
if((ismob(poi) && !SSpoints_of_interest.is_valid_poi(poi, CALLBACK(src, PROC_REF(validate_mob_poi)))) \
|
|
|| !SSpoints_of_interest.is_valid_poi(poi)
|
|
)
|
|
to_chat(usr, span_notice("That point of interest is no longer valid."))
|
|
return TRUE
|
|
|
|
var/mob/dead/observer/user = usr
|
|
user.ManualFollow(poi)
|
|
user.reset_perspective(null)
|
|
user.orbiting_ref = ref
|
|
if (auto_observe)
|
|
user.do_observe(poi)
|
|
return TRUE
|
|
if ("refresh")
|
|
ui.send_full_update()
|
|
return TRUE
|
|
|
|
return FALSE
|
|
|
|
|
|
/datum/orbit_menu/ui_data(mob/user)
|
|
var/list/data = list()
|
|
|
|
if(isobserver(user))
|
|
data["orbiting"] = get_currently_orbiting(user)
|
|
|
|
return data
|
|
|
|
|
|
/datum/orbit_menu/ui_static_data(mob/user)
|
|
var/list/new_mob_pois = SSpoints_of_interest.get_mob_pois(CALLBACK(src, PROC_REF(validate_mob_poi)), append_dead_role = FALSE)
|
|
var/list/new_other_pois = SSpoints_of_interest.get_other_pois()
|
|
|
|
var/list/alive = list()
|
|
var/list/antagonists = list()
|
|
var/list/critical = list()
|
|
var/list/deadchat_controlled = list()
|
|
var/list/dead = list()
|
|
var/list/ghosts = list()
|
|
var/list/misc = list()
|
|
var/list/npcs = list()
|
|
|
|
for(var/name in new_mob_pois)
|
|
var/list/serialized = list()
|
|
var/mob/mob_poi = new_mob_pois[name]
|
|
var/number_of_orbiters = length(mob_poi.get_all_orbiters())
|
|
|
|
serialized["ref"] = REF(mob_poi)
|
|
serialized["full_name"] = name
|
|
if(number_of_orbiters)
|
|
serialized["orbiters"] = number_of_orbiters
|
|
|
|
if(mob_poi.GetComponent(/datum/component/deadchat_control))
|
|
deadchat_controlled += list(serialized)
|
|
|
|
if(isobserver(mob_poi))
|
|
ghosts += list(serialized)
|
|
continue
|
|
|
|
if(mob_poi.stat == DEAD)
|
|
dead += list(serialized)
|
|
continue
|
|
|
|
if(isnull(mob_poi.mind))
|
|
if(isliving(mob_poi))
|
|
var/mob/living/npc = mob_poi
|
|
serialized["health"] = FLOOR((npc.health / npc.maxHealth * 100), 1)
|
|
|
|
npcs += list(serialized)
|
|
continue
|
|
|
|
serialized["client"] = !!mob_poi.client
|
|
serialized["name"] = mob_poi.real_name
|
|
|
|
if(isliving(mob_poi))
|
|
serialized += get_living_data(mob_poi)
|
|
|
|
var/list/antag_data = get_antag_data(mob_poi.mind)
|
|
if(length(antag_data))
|
|
serialized += antag_data
|
|
antagonists += list(serialized)
|
|
continue
|
|
|
|
alive += list(serialized)
|
|
|
|
for(var/name in new_other_pois)
|
|
var/atom/atom_poi = new_other_pois[name]
|
|
|
|
// Deadchat Controlled objects are orbitable
|
|
if(atom_poi.GetComponent(/datum/component/deadchat_control))
|
|
var/number_of_orbiters = length(atom_poi.get_all_orbiters())
|
|
deadchat_controlled += list(list(
|
|
"ref" = REF(atom_poi),
|
|
"full_name" = name,
|
|
"orbiters" = number_of_orbiters,
|
|
))
|
|
continue
|
|
|
|
var/list/other_data = get_misc_data(atom_poi)
|
|
var/misc_data = list(other_data[1])
|
|
|
|
misc += misc_data
|
|
|
|
if(other_data[2]) // Critical = TRUE
|
|
critical += misc_data
|
|
|
|
return list(
|
|
"alive" = alive,
|
|
"antagonists" = antagonists,
|
|
"critical" = critical,
|
|
"deadchat_controlled" = deadchat_controlled,
|
|
"dead" = dead,
|
|
"ghosts" = ghosts,
|
|
"misc" = misc,
|
|
"npcs" = npcs,
|
|
)
|
|
|
|
|
|
/// Shows the UI to the specified user.
|
|
/datum/orbit_menu/proc/show(mob/user)
|
|
ui_interact(user)
|
|
|
|
|
|
/// Helper function to get threat type, group, overrides for job and icon
|
|
/datum/orbit_menu/proc/get_antag_data(datum/mind/poi_mind) as /list
|
|
var/list/serialized = list()
|
|
|
|
for(var/datum/antagonist/antag as anything in poi_mind.antag_datums)
|
|
if(!antag.show_to_ghosts)
|
|
continue
|
|
|
|
serialized["antag"] = antag.name
|
|
serialized["antag_group"] = antag.antagpanel_category
|
|
serialized["job"] = antag.name
|
|
serialized["icon"] = antag.antag_hud_name
|
|
|
|
return serialized
|
|
|
|
|
|
/// Helper to get the current thing we're orbiting (if any)
|
|
/datum/orbit_menu/proc/get_currently_orbiting(mob/dead/observer/user)
|
|
if(isnull(user.orbiting_ref))
|
|
return
|
|
|
|
var/atom/poi = SSpoints_of_interest.get_poi_atom_by_ref(user.orbiting_ref)
|
|
if(isnull(poi))
|
|
user.orbiting_ref = null
|
|
return
|
|
|
|
if((ismob(poi) && !SSpoints_of_interest.is_valid_poi(poi, CALLBACK(src, PROC_REF(validate_mob_poi)))) \
|
|
|| !SSpoints_of_interest.is_valid_poi(poi)
|
|
)
|
|
user.orbiting_ref = null
|
|
return
|
|
|
|
var/list/serialized = list()
|
|
|
|
if(!ismob(poi))
|
|
var/list/misc_info = get_misc_data(poi)
|
|
serialized += misc_info[1]
|
|
return serialized
|
|
|
|
var/mob/mob_poi = poi
|
|
serialized["full_name"] = mob_poi.name
|
|
serialized["ref"] = REF(poi)
|
|
|
|
if(mob_poi.mind)
|
|
serialized["client"] = !!mob_poi.client
|
|
serialized["name"] = mob_poi.real_name
|
|
|
|
if(isliving(mob_poi))
|
|
serialized += get_living_data(mob_poi)
|
|
|
|
return serialized
|
|
|
|
|
|
/// Helper function to get job / icon / health data for a living mob
|
|
/datum/orbit_menu/proc/get_living_data(mob/living/player) as /list
|
|
var/list/serialized = list()
|
|
|
|
serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1)
|
|
if(issilicon(player))
|
|
serialized["job"] = player.job
|
|
serialized["icon"] = "borg"
|
|
return serialized
|
|
|
|
var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE)
|
|
serialized["job"] = id_card?.get_trim_assignment()
|
|
serialized["icon"] = id_card?.get_trim_sechud_icon_state()
|
|
|
|
var/datum/job/job = player.mind?.assigned_role
|
|
if (isnull(job))
|
|
return serialized
|
|
|
|
serialized["mind_job"] = job.title
|
|
var/datum/outfit/outfit = job.get_outfit()
|
|
if (isnull(outfit))
|
|
return serialized
|
|
|
|
var/datum/id_trim/trim = outfit.id_trim
|
|
if (!isnull(trim))
|
|
serialized["mind_icon"] = trim::sechud_icon_state
|
|
return serialized
|
|
|
|
/// Gets a list: Misc data and whether it's critical. Handles all snowflakey type cases
|
|
/datum/orbit_menu/proc/get_misc_data(atom/movable/atom_poi) as /list
|
|
var/list/misc = list()
|
|
var/critical = FALSE
|
|
|
|
misc["ref"] = REF(atom_poi)
|
|
misc["full_name"] = atom_poi.name
|
|
|
|
// Display the supermatter crystal integrity
|
|
if(istype(atom_poi, /obj/machinery/power/supermatter_crystal))
|
|
var/obj/machinery/power/supermatter_crystal/crystal = atom_poi
|
|
var/integrity = round(crystal.get_integrity_percent())
|
|
misc["extra"] = "Integrity: [integrity]%"
|
|
|
|
if(integrity < 10)
|
|
critical = TRUE
|
|
|
|
return list(misc, critical)
|
|
|
|
// Display the nuke timer
|
|
if(istype(atom_poi, /obj/machinery/nuclearbomb))
|
|
var/obj/machinery/nuclearbomb/bomb = atom_poi
|
|
|
|
if(bomb.timing)
|
|
misc["extra"] = "Timer: [bomb.countdown?.displayed_text]s"
|
|
critical = TRUE
|
|
|
|
return list(misc, critical)
|
|
|
|
// Display the holder if its a nuke disk
|
|
if(istype(atom_poi, /obj/item/disk/nuclear))
|
|
var/obj/item/disk/nuclear/disk = atom_poi
|
|
var/mob/holder = disk.pulledby || get(disk, /mob)
|
|
misc["extra"] = "Location: [holder?.real_name || "Unsecured"]"
|
|
|
|
return list(misc, critical)
|
|
|
|
// Display singuloths if they exist
|
|
if(istype(atom_poi, /obj/singularity))
|
|
var/obj/singularity/singulo = atom_poi
|
|
misc["extra"] = "Energy: [round(singulo.energy)]"
|
|
|
|
if(singulo.current_size > 2)
|
|
critical = TRUE
|
|
|
|
return list(misc, critical)
|
|
|
|
return list(misc, critical)
|
|
|
|
|
|
/**
|
|
* Helper POI validation function passed as a callback to various SSpoints_of_interest procs.
|
|
*
|
|
* Provides extended validation above and beyond standard, limiting mob POIs without minds or ckeys
|
|
* unless they're mobs, camera mobs or megafauna. Also allows exceptions for mobs that are deadchat controlled.
|
|
*
|
|
* If they satisfy that requirement, falls back to default validation for the POI.
|
|
*/
|
|
/datum/orbit_menu/proc/validate_mob_poi(datum/point_of_interest/mob_poi/potential_poi)
|
|
var/mob/potential_mob_poi = potential_poi.target
|
|
if(!potential_mob_poi.mind && !potential_mob_poi.ckey)
|
|
if(!mob_allowed_typecache)
|
|
mob_allowed_typecache = typecacheof(list(
|
|
/mob/camera,
|
|
/mob/living/basic/regal_rat,
|
|
/mob/living/simple_animal/bot,
|
|
/mob/living/simple_animal/hostile/megafauna,
|
|
))
|
|
if(!is_type_in_typecache(potential_mob_poi, mob_allowed_typecache) && !potential_mob_poi.GetComponent(/datum/component/deadchat_control))
|
|
return FALSE
|
|
|
|
return potential_poi.validate()
|
|
|