Files
Bubberstation/code/modules/mob/dead/observer/orbit.dm
lessthanthree 4999bdfd19 [MANUAL MIRROR] Better groups for antagonists (#18839)
* Better groups for antagonists (#72576)

Better categorizes antagonists into groups for the orbit UI, admin
traitor panel.
Permanently hostile antags were intermixed in the "Alive" section, and
it was sometimes tough to see what's going on.
To do this, many minor antags needed new antag datums which were added
with fluff objectives as a bonus.

Group Name | Antags
--- | ---
Syndicate | Nukies, battlecruiser crew, lone op
Extradimensional Abominations | Nightmare, morph, pyro
slime
Spaceborne Leviathans | Space dragon, (spawned) carps
Invasive Overgrowth | Venus human traps
Arachnid Infestation | Spiders
Eldritch Horrors | Cult constructs, revenant

( = New antag datum, proper orbit category, new objective text)

<details>
<summary>Screenshots (outdated)</summary>

Antags get more tooltip info
![Screenshot 2023-01-08
173344](https://user-images.githubusercontent.com/42397676/211233179-d0e9229c-0f2e-4cd3-838b-fc0c5255ec9c.png)

Populating space dragon + carps (now leviathans)
![Screenshot 2023-01-08
235526](https://user-images.githubusercontent.com/42397676/211267252-2a86f8bc-4b4a-4ad6-81ed-f6b2e72d8fc0.png)

Detail to distinguish job & rank
![Screenshot 2023-01-08
233608](https://user-images.githubusercontent.com/42397676/211267334-60cabefc-b768-4a8e-8d4b-74b3d4fd45b1.png)

New categories in action
![Screenshot 2023-01-09
131003](https://user-images.githubusercontent.com/42397676/211408962-2e3c3cb9-f08e-4e27-a765-6485fe5064b0.png)

Organized Traitor Panel

![Screenshot_20230109_113453](https://user-images.githubusercontent.com/42397676/211392793-a9e6c170-60de-46bc-b0b6-02d74d45e42d.png)

</details>

Better UI, observer experience, admin panel.
It's now very obvious when something is hostile from the orbit panel.

🆑
qol: The orbit menu now sorts antagonists into groups more effectively.
Some get new named groups.
admin: Traitor panel should have slightly more sane categories.
add: Many minor antagonists now have "objectives".
refactor: Refactors code in several antag datums.
/🆑

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>

* Fixes the compile issues

* Also puts the drifting contractor in the syndicate group in the antag panel

---------

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
2023-02-03 19:57:20 -05:00

186 lines
5.8 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)
if (auto_observe)
user.do_observe(poi)
return TRUE
if ("refresh")
update_static_data(usr, ui)
return TRUE
/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/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/poi_ref = REF(mob_poi)
var/number_of_orbiters = length(mob_poi.get_all_orbiters())
serialized["ref"] = poi_ref
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))
npcs += list(serialized)
continue
var/datum/mind/mind = mob_poi.mind
var/was_antagonist = FALSE
serialized["name"] = mob_poi.real_name
if(isliving(mob_poi)) // handles edge cases like blob
var/mob/living/player = mob_poi
serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1)
if(issilicon(player))
serialized["job"] = player.job
else
var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE)
serialized["job"] = id_card?.get_trim_assignment()
var/datum/id_trim/trim = id_card?.trim
serialized["job_icon"] = trim?.orbit_icon
for(var/datum/antagonist/antag_datum as anything in mind.antag_datums)
if (antag_datum.show_to_ghosts)
was_antagonist = TRUE
serialized["antag"] = antag_datum.name
serialized["antag_group"] = antag_datum.antagpanel_category
antagonists += list(serialized)
break
if(!was_antagonist)
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
misc += list(list(
"ref" = REF(atom_poi),
"full_name" = name,
))
// Display the supermatter crystal integrity
if(istype(atom_poi, /obj/machinery/power/supermatter_crystal))
var/obj/machinery/power/supermatter_crystal/crystal = atom_poi
misc[length(misc)]["extra"] = "Integrity: [round(crystal.get_integrity_percent())]%"
continue
// Display the nuke timer
if(istype(atom_poi, /obj/machinery/nuclearbomb))
var/obj/machinery/nuclearbomb/bomb = atom_poi
if(bomb.timing)
misc[length(misc)]["extra"] = "Timer: [bomb.countdown?.displayed_text]s"
continue
// 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[length(misc)]["extra"] = "Location: [holder?.real_name || "Unsecured"]"
continue
return list(
"alive" = alive,
"antagonists" = antagonists,
"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 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/living/simple_animal/bot,
/mob/camera,
/mob/living/simple_animal/hostile/megafauna,
/mob/living/simple_animal/hostile/regalrat,
))
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()