Merge remote-tracking branch 'upstream/master' into diagnostic-hud-fixes-and-upgrade

This commit is contained in:
Fox McCloud
2021-09-30 18:16:10 -04:00
3973 changed files with 268434 additions and 668287 deletions
+92 -89
View File
@@ -26,9 +26,12 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
var/image/ghostimage = null //this mobs ghost image, for deleting and stuff
var/ghostvision = TRUE //is the ghost able to see things humans can't?
var/seedarkness = TRUE
var/data_hud_seen = FALSE //this should one of the defines in __DEFINES/hud.dm
var/seerads = FALSE // can the ghost see radiation?
/// Defines from __DEFINES/hud.dm go here based on which huds the ghost has activated.
var/list/data_hud_seen = list()
var/ghost_orbit = GHOST_ORBIT_CIRCLE
var/health_scan = FALSE //does the ghost have health scanner mode on? by default it should be off
var/datum/orbit_menu/orbit_menu
/mob/dead/observer/New(mob/body=null, flags=1)
set_invisibility(GLOB.observer_default_invisibility)
@@ -41,7 +44,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
/mob/dead/observer/proc/open_spawners_menu)
// Our new boo spell.
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/boo(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/click/boo(null))
can_reenter_corpse = flags & GHOST_CAN_REENTER
started_as_observer = flags & GHOST_IS_OBSERVER
@@ -53,7 +56,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
if(ismob(body))
T = get_turf(body) //Where is the body located?
attack_log_old = body.attack_log_old //preserve our attack logs by copying them to our ghost
logs = body.logs.Copy()
var/mutable_appearance/MA = copy_appearance(body)
if(body.mind && body.mind.name)
@@ -86,7 +88,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
real_name = name
//starts ghosts off with all HUDs.
toggle_medHUD()
toggle_all_huds_on(body)
..()
/mob/dead/observer/Destroy()
@@ -94,6 +96,11 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
GLOB.ghost_images -= ghostimage
QDEL_NULL(ghostimage)
updateallghostimages()
if(orbit_menu)
SStgui.close_uis(orbit_menu)
QDEL_NULL(orbit_menu)
if (seerads)
STOP_PROCESSING(SSobj, src)
return ..()
/mob/dead/observer/examine(mob/user)
@@ -101,6 +108,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
if(!invisibility)
. += "It seems extremely obvious."
/mob/dead/observer/process()
if(seerads)
show_rads(5)
// This seems stupid, but it's the easiest way to avoid absolutely ridiculous shit from happening
// Copying an appearance directly from a mob includes it's verb list, it's invisibility, it's alpha, and it's density
// You might recognize these things as "fucking ridiculous to put in an appearance"
@@ -159,8 +170,6 @@ Works together with spawning an observer, noted above.
else
GLOB.non_respawnable_keys[ckey] = 1
ghost.key = key
if(!(ghost.client && ghost.client.holder) && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing!
return ghost
/*
@@ -284,7 +293,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return 1
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source)
/mob/dead/observer/proc/notify_cloning(message, sound, atom/source)
if(message)
to_chat(src, "<span class='ghostalert'>[message]</span>")
if(source)
@@ -307,82 +316,70 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/proc/show_me_the_hud(hud_index)
var/datum/atom_hud/H = GLOB.huds[hud_index]
H.add_hud_to(src)
data_hud_seen |= hud_index
/mob/dead/observer/proc/remove_the_hud(hud_index) //remove old huds
var/datum/atom_hud/H = GLOB.huds[hud_index]
H.remove_hud_from(src)
data_hud_seen -= hud_index
/mob/dead/observer/verb/toggle_medHUD()
/mob/dead/observer/verb/open_hud_panel()
set category = "Ghost"
set name = "Toggle All/Sec/Med/Diag HUDs"
set desc = "Toggles the HUDs."
set name = "Ghost HUD Panel"
if(!client)
return
GLOB.ghost_hud_panel.ui_interact(src)
switch(data_hud_seen) //give new huds
if(FALSE)
data_hud_seen = DATA_HUD_DIAGNOSTIC_ADVANCED + DATA_HUD_SECURITY_ADVANCED + DATA_HUD_MEDICAL_ADVANCED
show_me_the_hud(DATA_HUD_DIAGNOSTIC_ADVANCED)
show_me_the_hud(DATA_HUD_SECURITY_ADVANCED)
show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED)
to_chat(src, "<span class='notice'>All HUDs enabled.</span>")
if(DATA_HUD_DIAGNOSTIC_ADVANCED + DATA_HUD_SECURITY_ADVANCED + DATA_HUD_MEDICAL_ADVANCED)
data_hud_seen = DATA_HUD_SECURITY_ADVANCED
remove_the_hud(DATA_HUD_DIAGNOSTIC_ADVANCED)
remove_the_hud(DATA_HUD_MEDICAL_ADVANCED)
to_chat(src, "<span class='notice'>Security HUD set.</span>")
if(DATA_HUD_SECURITY_ADVANCED)
data_hud_seen = DATA_HUD_MEDICAL_ADVANCED
remove_the_hud(DATA_HUD_SECURITY_ADVANCED)
show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED)
to_chat(src, "<span class='notice'>Medical HUD set.</span>")
if(DATA_HUD_MEDICAL_ADVANCED)
data_hud_seen = DATA_HUD_DIAGNOSTIC_ADVANCED
remove_the_hud(DATA_HUD_MEDICAL_ADVANCED)
show_me_the_hud(DATA_HUD_DIAGNOSTIC_ADVANCED)
to_chat(src, "<span class='notice'>Diagnostic HUD set.</span>")
else
data_hud_seen = FALSE
remove_the_hud(DATA_HUD_MEDICAL_ADVANCED)
to_chat(src, "<span class='notice'>HUDs disabled.</span>")
/mob/dead/observer/verb/toggle_antagHUD()
set category = "Ghost"
set name = "Toggle AntagHUD"
set desc = "Toggles AntagHUD allowing you to see who is the antagonist"
if(!config.antag_hud_allowed && !client.holder)
to_chat(src, "<span class='warning'>Admins have disabled this for this round.</span>")
/**
* Toggles on all HUDs for the ghost player.
*
* Enables antag HUD only if the ghost belongs to an admin.
*
* Arguments:
* * user - A reference to the ghost's old mob. This argument is required since `src` does not have a `client` at this point.
*/
/mob/dead/observer/proc/toggle_all_huds_on(mob/user)
show_me_the_hud(DATA_HUD_DIAGNOSTIC_ADVANCED)
show_me_the_hud(DATA_HUD_SECURITY_ADVANCED)
show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED)
if(!check_rights((R_ADMIN | R_MOD), FALSE, user))
return
if(!client)
return
var/mob/dead/observer/M = src
if(jobban_isbanned(M, "AntagHUD"))
to_chat(src, "<span class='danger'>You have been banned from using this feature</span>")
return
if(config.antag_hud_restricted && !M.has_enabled_antagHUD && !check_rights(R_ADMIN|R_MOD,0))
var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No")
if(response == "No") return
M.can_reenter_corpse = 0
if(M in GLOB.respawnable_list)
GLOB.respawnable_list -= M
if(!M.has_enabled_antagHUD && !check_rights(R_ADMIN|R_MOD,0))
M.has_enabled_antagHUD = 1
antagHUD = TRUE
for(var/datum/atom_hud/antag/H in GLOB.huds)
H.add_hud_to(src)
//var/datum/atom_hud/A = huds[DATA_HUD_SECURITY_ADVANCED]
//var/adding_hud = (usr in A.hudusers) ? 0 : 1
for(var/datum/atom_hud/antag/H in (GLOB.huds))
if(!M.antagHUD)
H.add_hud_to(usr)
else
H.remove_hud_from(usr)
if(!M.antagHUD)
to_chat(usr, "AntagHud Toggled ON")
M.antagHUD = 1
/mob/dead/observer/proc/set_radiation_view(enabled)
if (enabled)
seerads = TRUE
START_PROCESSING(SSobj, src)
else
to_chat(usr, "AntagHud Toggled OFF")
M.antagHUD = 0
seerads = FALSE
STOP_PROCESSING(SSobj, src)
/mob/dead/observer/verb/set_dnr()
set name = "Set DNR"
set category = "Ghost"
set desc = "Prevent your character from being revived."
if(!isobserver(src)) // Somehow
return
if(!can_reenter_corpse)
to_chat(src, "<span class='warning'>You are already set to DNR!</span>")
return
if(!mind || QDELETED(mind.current))
to_chat(src, "<span class='warning'>You have no body.</span>")
return
if(mind.current.stat != DEAD)
to_chat(src, "<span class='warning'>Your body is still alive!</span>")
return
var/choice = alert(src, "If you enable this, your body will be unrevivable for the remainder of the round.", "Are you sure?", "Yes", "No")
if(choice == "Yes")
to_chat(src, "<span class='boldnotice'>Do Not Revive state enabled.</span>")
create_log(MISC_LOG, "DNR Enabled")
can_reenter_corpse = FALSE
if(!QDELETED(mind.current)) // Could change while they're choosing
mind.current.med_hud_set_status()
/mob/dead/observer/proc/dead_tele()
set category = "Ghost"
@@ -393,7 +390,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(usr, "Not when you're not dead!")
return
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", GLOB.ghostteleportlocs)
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", SSmapping.ghostteleportlocs)
A.on_close(CALLBACK(src, .proc/teleport))
/mob/dead/observer/proc/teleport(area/thearea)
@@ -416,9 +413,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Orbit" // "Haunt"
set desc = "Follow and orbit a mob."
var/list/mobs = getpois(FALSE, TRUE, TRUE, TRUE)
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
A.on_close(CALLBACK(src, .proc/ManualFollow))
if(!orbit_menu)
orbit_menu = new(src)
orbit_menu.ui_interact(src)
// This is the ghost's follow verb with an argument
/mob/dead/observer/proc/ManualFollow(atom/movable/target)
@@ -574,12 +572,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/verb/view_manifest()
set name = "View Crew Manifest"
set category = "Ghost"
var/dat
dat += "<h4>Crew Manifest</h4>"
dat += GLOB.data_core.get_manifest()
src << browse(dat, "window=manifest;size=370x420;can_close=1")
GLOB.generic_crew_manifest.ui_interact(usr, state = GLOB.observer_state)
//this is called when a ghost is drag clicked to something.
/mob/dead/observer/MouseDrop(atom/over)
@@ -590,7 +583,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return ..()
/proc/ghost_follow_link(var/atom/target, var/atom/ghost)
/proc/ghost_follow_link(atom/target, atom/ghost)
if((!target) || (!ghost)) return
if(isAI(target)) // AI core/eye follow links
var/mob/living/silicon/ai/A = target
@@ -624,7 +617,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(href_list["jump"])
var/mob/target = locate(href_list["jump"])
var/mob/A = usr;
var/mob/A = usr
to_chat(A, "Teleporting to [target]...")
//var/mob/living/silicon/ai/A = locate(href_list["track2"]) in GLOB.mob_list
if(target && target != usr)
@@ -648,8 +641,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Toggle Anonymous Dead-chat"
set category = "Ghost"
set desc = "Toggles showing your key in dead chat."
client.prefs.ghost_anonsay = !client.prefs.ghost_anonsay
to_chat(src, "As a ghost, your key will [(client.prefs.ghost_anonsay) ? "no longer" : "now"] be shown when you speak in dead chat.</span>")
client.prefs.toggles2 ^= PREFTOGGLE_2_ANONDCHAT
to_chat(src, "As a ghost, your key will [(client.prefs.toggles2 & PREFTOGGLE_2_ANONDCHAT) ? "no longer" : "now"] be shown when you speak in dead chat.</span>")
client.prefs.save_preferences(src)
/mob/dead/observer/verb/toggle_ghostsee()
@@ -694,6 +687,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
updateghostimages()
/mob/dead/observer/can_see_reagents()
return TRUE
/proc/updateallghostimages()
for(var/mob/dead/observer/O in GLOB.player_list)
O.updateghostimages()
@@ -735,19 +731,26 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
//overriden here and in /mob/living for different point span classes and sanity checks
/mob/dead/observer/pointed(atom/A as mob|obj|turf in view())
if(!..())
return 0
usr.visible_message("<span class='deadsay'><b>[src]</b> points to [A].</span>")
return 1
return FALSE
var/follow_link
if(invisibility) // Only show the button if the ghost is not visible to the living
follow_link = " ([ghost_follow_link(A, src)])"
usr.visible_message("<span class='deadsay'><b>[src]</b> points to [A][follow_link].</span>")
return TRUE
/mob/dead/observer/proc/incarnate_ghost()
if(!client)
return
var/mob/living/carbon/human/new_char = new(get_turf(src))
client.prefs.copy_to(new_char)
client.prefs.active_character.copy_to(new_char)
if(mind)
mind.active = TRUE
mind.transfer_to(new_char)
if(mind.vampire)
mind.vampire.owner = new_char
mind.vampire.powers.Cut()
mind.vampire.check_vampire_upgrade(FALSE)
else
new_char.key = key
+134
View File
@@ -0,0 +1,134 @@
/datum/orbit_menu
var/mob/dead/observer/owner
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "Orbit", "Orbit", 700, 500, master_ui, state)
ui.open()
/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("orbit")
var/ref = params["ref"]
var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list)
if(poi == null)
. = TRUE
return
owner.ManualFollow(poi)
. = TRUE
if("refresh")
update_static_data(owner, ui)
. = TRUE
/datum/orbit_menu/ui_static_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
var/list/ghosts = list()
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(mobs_only = FALSE, skip_mindless = FALSE)
for(var/name in pois)
var/mob/M = pois[name]
if(name == null)
if(pois[name] && M.type)
stack_trace("getpois returned something under a null name. Type: [M.type]")
else
stack_trace("getpois returned a null value")
continue
var/list/serialized = list()
serialized["name"] = "[name]" // stringify it; If it's null or something - we'd like to know it and fix getpois()
if(serialized["name"] != name)
stack_trace("getpois returned something under a non-string name [name] - [pois[name]] - [M.type]")
continue
serialized["ref"] = "\ref[M]"
if(istype(M))
if(isnewplayer(M)) // People in the lobby screen; only have their ckey as a name.
continue
if(isobserver(M) && M.client)
ghosts += list(serialized)
else if(M.mind == null)
npcs += list(serialized)
else if(M.stat == DEAD)
dead += list(serialized)
else
alive += list(serialized)
var/datum/mind/mind = M.mind
if(user.antagHUD)
// If a mind is many antags at once, we'll display all of them, each
// under their own antag sub-section.
// This is arguably better, than picking one of the antag datums at random.
// Traitors - the only antags in `.antag_datums` at the time of writing.
for(var/_A in mind.antag_datums)
var/datum/antagonist/A = _A
var/antag_serialized = serialized.Copy()
antag_serialized["antag"] = A.name
antagonists += list(antag_serialized)
// Not-very-datumized antags follow
// Associative list of antag name => whether this mind is this antag
var/other_antags = list(
"Changeling" = (mind.changeling != null),
"Vampire" = (mind.vampire != null),
)
if(SSticker && SSticker.mode)
other_antags += list(
"Blob" = (mind.special_role == SPECIAL_ROLE_BLOB),
"Cultist" = (mind in SSticker.mode.cult),
"Wizard" = (mind in SSticker.mode.wizards),
"Wizard's Apprentice" = (mind in SSticker.mode.apprentices),
"Nuclear Operative" = (mind in SSticker.mode.syndicates),
"Shadowling" = (mind in SSticker.mode.shadows),
"Shadowling Thrall" = (mind in SSticker.mode.shadowling_thralls),
"Abductor" = (mind in SSticker.mode.abductors),
"Revolutionary" = (mind in SSticker.mode.revolutionaries),
"Head Revolutionary" = (mind in SSticker.mode.head_revolutionaries)
)
for(var/antag_name in other_antags)
var/is_antag = other_antags[antag_name]
if(!is_antag)
continue
var/antag_serialized = serialized.Copy()
antag_serialized["antag"] = antag_name
antagonists += list(antag_serialized)
// Player terror spiders have their own category to help see how much there are.
// Not in the above block because terrors can be known whether AHUD is on or not.
if(isterrorspider(M))
var/list/antag_serialized = serialized.Copy()
antag_serialized["antag"] = "Terror Spider"
antagonists += list(antag_serialized)
else if(istype(M, /mob/living/simple_animal/revenant))
var/list/antag_serialized = serialized.Copy()
antag_serialized["antag"] = "Revenant"
antagonists += list(antag_serialized)
else
misc += list(serialized)
data["alive"] = alive
data["antagonists"] = antagonists
data["dead"] = dead
data["ghosts"] = ghosts
data["misc"] = misc
data["npcs"] = npcs
return data
+6 -16
View File
@@ -1,20 +1,10 @@
/mob/dead/observer/say(var/message)
/mob/dead/observer/say(message)
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
if(!message)
return
log_ghostsay(message, src)
if(src.client)
if(src.client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='warning'>You cannot talk in deadchat (muted).</span>")
return
if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
return
. = src.say_dead(message)
return say_dead(message)
/mob/dead/observer/emote(act, type, message, force)
@@ -29,7 +19,7 @@
log_ghostemote(message, src)
if(src.client)
if(src.client.prefs.muted & MUTE_DEADCHAT)
if(check_mute(client.ckey, MUTE_DEADCHAT))
to_chat(src, "<span class='warning'>You cannot emote in deadchat (muted).</span>")
return
@@ -38,11 +28,11 @@
. = src.emote_dead(message)
/mob/dead/observer/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
/mob/dead/observer/handle_track(message, verb = "says", mob/speaker = null, speaker_name, atom/follow_target, hard_to_hear)
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
/mob/dead/observer/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear)
/mob/dead/observer/handle_speaker_name(mob/speaker = null, vname, hard_to_hear)
var/speaker_name = ..()
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker) && !istype(speaker, /mob/living/automatedannouncer)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
speaker_name = "[speaker.real_name] ([speaker_name])"
return speaker_name
+22 -6
View File
@@ -9,22 +9,38 @@ GLOBAL_LIST_INIT(boo_phrases, list(
"It feels like someone's standing behind you.",
))
/obj/effect/proc_holder/spell/aoe_turf/boo
/obj/effect/proc_holder/spell/targeted/click/boo
name = "Boo!"
desc = "Fuck with the living."
selection_deactivated_message = "<span class='shadowling'>Your presence will not be known. For now.</span>"
selection_activated_message = "<span class='shadowling'>You prepare to reach across the veil. <b>Left-click to influence a target!</b></span>"
auto_target_single = FALSE
allowed_type = /atom // No subtypes are safe from spookage.
ghost = TRUE
action_icon_state = "boo"
school = "transmutation"
charge_max = 600
charge_max = 2 MINUTES
starts_charged = FALSE
clothes_req = 0
stat_allowed = 1
invocation = ""
invocation_type = "none"
range = 1 // Or maybe 3?
range = 20
// no need to spam admins regarding boo casts
create_logs = FALSE
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
T.get_spooked()
/obj/effect/proc_holder/spell/targeted/click/boo/cast(list/targets, mob/user = usr)
var/atom/target = targets[1]
ASSERT(istype(target))
if(target.get_spooked())
var/area/spook_zone = get_area(target)
if (spook_zone.is_haunted == TRUE)
to_chat(usr, "<span class='shadowling'>The veil is weak in [spook_zone], it took less effort to influence [target].</span>")
charge_counter = charge_max / 2
return
charge_counter = charge_max * 0.9 // We've targetted a non-spookable object! Try again fast!