mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 07:33:34 +01:00
Adds true observing -- letting you see what your target sees (#24855)
* bring it back now y'all * adds a bunch of other changes * pretty much works at this point * grep * Fixes some bugs, still chasing some down * Add observers to recursive mob check, ensuring they can see messages from their orbitted atom * tidy some things up * resolve * remove unnecessary checks * Address todos, minor cleanups * oh dear * initial testing * Fix some vulnerabilities (oops) * Fix some other bugs from testing * ci fixes * Add some contingencies against clicking things you shouldn't * fix some noted bugs * Add observe to admin jump, improve messaging * add a few more fixes that should mostly address some runtimes * oh this wasn't really great * one last thing * Fix suit inventory problem * Remove merge artifact * Add some missing parens * Prevents you from observing other ghosts, and should fix the getting stuck outside of your body issue. * we love testing * adds to player panel * Fix more bugs with observers getting stuck outside of their body * cleans up player panel, verb offerings * shit * Update code/_onclick/hud/alert.dm welp Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * Fixes some targeting issues * Fixes targeting on aobserve * Fix some weird storage bugs * clean up some doulbed up follow links * Update code/modules/admin/player_panel.dm Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * Adds some checks for ghost observe * Remove mentor debug log * ahhhhhhhhh that'll do it * Cleans up some additional checks that were not quite what they should have been * better logging, too * mochi review * one more thing * Gets robot huds mostly working * hopefully fix folks not getting observe * Fix order of operations causing a runtime on qdeleting * Remove some unnecessary stack traces * Apply suggestions from code review Co-authored-by: 1080pCat <96908085+1080pCat@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * Fix bug with items in your inventory disappearing on changing HUD modes * Fix some bugs with the observe verbs * possibly fix nullspace issues * funny review * missed one --------- Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> Co-authored-by: 1080pCat <96908085+1080pCat@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/client/proc/invisimin, /*allows our mob to go invisible/visible*/
|
||||
/datum/admins/proc/announce, /*priority announce something to all clients.*/
|
||||
/client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/
|
||||
/client/proc/admin_observe, /*allows us to freely observe mobs */
|
||||
/client/proc/admin_observe_target, /*and gives it to us on right click*/
|
||||
/client/proc/toggle_view_range, /*changes how far we can see*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
@@ -196,13 +198,17 @@ GLOBAL_LIST_INIT(admin_verbs_mod, list(
|
||||
/client/proc/dsay,
|
||||
/datum/admins/proc/show_player_panel,
|
||||
/client/proc/ban_panel,
|
||||
/client/proc/debug_variables /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/admin_observe,
|
||||
/client/proc/admin_observe_target,
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_mentor, list(
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/
|
||||
/client/proc/openMentorTicketUI,
|
||||
/client/proc/admin_observe, /* Allow mentors to observe as well, though they face some limitations */
|
||||
/client/proc/admin_observe_target,
|
||||
/client/proc/cmd_mentor_say /* mentor say*/
|
||||
// cmd_mentor_say is added/removed by the toggle_mentor_chat verb
|
||||
))
|
||||
@@ -339,13 +345,22 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Admin Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/admin_ghost()
|
||||
set category = "Admin"
|
||||
set name = "Aghost"
|
||||
/client/proc/mentor_ghost()
|
||||
var/is_mentor = check_rights(R_MENTOR, FALSE)
|
||||
var/is_full_admin = check_rights(R_ADMIN|R_MOD, FALSE)
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
if(!is_mentor && !is_full_admin)
|
||||
to_chat(src, "<span class='warning'>You aren't allowed to use this!</span>")
|
||||
return
|
||||
|
||||
// mentors are allowed only if they have the observe trait, which is given on observe.
|
||||
// they should also not be given this proc.
|
||||
if(!is_full_admin && (is_mentor && !HAS_MIND_TRAIT(mob, TRAIT_MENTOR_OBSERVING) || !is_mentor))
|
||||
return
|
||||
|
||||
do_aghost()
|
||||
|
||||
/client/proc/do_aghost()
|
||||
if(isobserver(mob))
|
||||
//re-enter
|
||||
var/mob/dead/observer/ghost = mob
|
||||
@@ -372,6 +387,134 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
|
||||
// TODO: SStgui.on_transfer() to move windows from old and new
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Aghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/admin_ghost()
|
||||
set category = "Admin"
|
||||
set name = "Aghost"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
return
|
||||
|
||||
do_aghost()
|
||||
|
||||
/// Allow an admin to observe someone.
|
||||
/// mentors are allowed to use this verb while living, but with some stipulations:
|
||||
/// if they attempt to do anything that would stop their orbit, they will immediately be returned to their body.
|
||||
/client/proc/admin_observe()
|
||||
set name = "Aobserve"
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_ADMIN|R_MOD|R_MENTOR))
|
||||
return
|
||||
|
||||
if(isnewplayer(mob))
|
||||
to_chat(src, "<span class='warning'>You cannot aobserve while in the lobby. Please join or observe first.</span>")
|
||||
return
|
||||
|
||||
var/mob/target
|
||||
|
||||
target = tgui_input_list(mob, "Select a mob to observe", "Aobserve", GLOB.player_list)
|
||||
if(isnull(target))
|
||||
return
|
||||
if(target == src)
|
||||
to_chat(src, "<span class='warning'>You can't observe yourself!</span>")
|
||||
return
|
||||
|
||||
if(isobserver(target))
|
||||
to_chat(src, "<span class='warning'>[target] is a ghost, and cannot be observed.</span>")
|
||||
return
|
||||
|
||||
if(isnewplayer(target))
|
||||
to_chat(src, "<span class='warning'>[target] is in the lobby, and cannot be observed.</span>")
|
||||
return
|
||||
|
||||
admin_observe_target(target)
|
||||
|
||||
/client/proc/cleanup_admin_observe(mob/dead/observer/ghost)
|
||||
if(!istype(ghost) || !ghost.mob_observed)
|
||||
return FALSE
|
||||
|
||||
// un-follow them
|
||||
ghost.cleanup_observe()
|
||||
// if it's a mentor, make sure they go back to their body.
|
||||
if(HAS_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING))
|
||||
// handler will handle removing the trait
|
||||
mob.stop_orbit()
|
||||
log_admin("[key_name(src)] has de-activated Aobserve")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve")
|
||||
return TRUE
|
||||
|
||||
/// targeted form of admin_observe: this should only appear in the right-click menu.
|
||||
/client/proc/admin_observe_target(mob/target as mob in GLOB.mob_list)
|
||||
set name = "\[Admin\] Aobserve"
|
||||
set category = null
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD|R_MENTOR, mob))
|
||||
return
|
||||
|
||||
var/full_admin = check_rights(R_ADMIN|R_MOD, FALSE, mob)
|
||||
|
||||
if(isnewplayer(mob))
|
||||
to_chat(src, "<span class='warning'>You cannot aobserve while in the lobby. Please join or observe first.</span>")
|
||||
return
|
||||
|
||||
if(isnewplayer(target))
|
||||
to_chat(src, "<span class='warning'>[target] is currently in the lobby.</span>")
|
||||
return
|
||||
|
||||
if(isobserver(target))
|
||||
to_chat(src, "<span class='warning'>You can't observe a ghost.</span>")
|
||||
return
|
||||
|
||||
if(cleanup_admin_observe(mob))
|
||||
return
|
||||
|
||||
if(isnull(target) || target == src)
|
||||
// let the default one find the target if there isn't one
|
||||
admin_observe()
|
||||
return
|
||||
|
||||
// observers don't need to ghost, so we don't need to worry about adding any traits
|
||||
if(isobserver(mob))
|
||||
var/mob/dead/observer/ghost = mob
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve")
|
||||
ghost.do_observe(target)
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] has Aobserved out of their body to follow [target]")
|
||||
do_aghost()
|
||||
var/mob/dead/observer/ghost = mob
|
||||
|
||||
if(!full_admin)
|
||||
// if they're a me and they're alive, add the MENTOR_OBSERVINGtrait to ensure that they can only go back to their body.
|
||||
// we need to handle this here because when you aghost, your mob gets set to the ghost. Oops!
|
||||
ADD_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING)
|
||||
RegisterSignal(ghost, COMSIG_ATOM_ORBITER_STOP, PROC_REF(on_mentor_observe_end), override = TRUE)
|
||||
to_chat(src, "<span class='notice'>You have temporarily observed [target], either move or observe again to un-observe.</span>")
|
||||
log_admin("[key_name(src)] has mobserved out of their body to follow [target].")
|
||||
else
|
||||
log_admin("[key_name(src)] is aobserving [target].")
|
||||
|
||||
|
||||
ghost.do_observe(target)
|
||||
|
||||
/client/proc/on_mentor_observe_end(atom/movable/us, atom/movable/orbited)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_ORBITER_STOP
|
||||
if(!isobserver(mob))
|
||||
log_and_message_admins("A mentor somehow managed to end observing while not being a ghost. Please investigate and notify coders.")
|
||||
return
|
||||
var/mob/dead/observer/ghost = mob
|
||||
|
||||
// just to be safe
|
||||
ghost.cleanup_observe()
|
||||
|
||||
REMOVE_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING)
|
||||
UnregisterSignal(mob, COMSIG_ATOM_ORBITER_STOP)
|
||||
|
||||
if(!ghost.reenter_corpse())
|
||||
// tell everyone since this is kinda nasty.
|
||||
log_debug("Mentor [key_name_mentor(src)] was unable to re-enter their body after mentor observing.")
|
||||
log_and_message_admins("[key_name_mentor(src)] was unable to re-enter their body after mentor observing.")
|
||||
to_chat(src, "<span class='userdanger'>Unable to return you to your body after mentor ghosting. If your body still exists, please contact a coder, and you should probably ahelp.</span>")
|
||||
|
||||
/client/proc/invisimin()
|
||||
set name = "Invisimin"
|
||||
set category = "Admin"
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
body += "<a href='byond://?src=[usr.UID()];priv_msg="+client_ckey+"'>PM</a> - "
|
||||
body += "<a href='byond://?src=[UID()];subtlemessage="+mobUID+"'>SM</a> - "
|
||||
body += "<a href='byond://?src=[UID()];adminplayerobservefollow="+mobUID+"'>FLW</a> - "
|
||||
body += "<a href='byond://?src=[UID()];adminalert="+mobUID+"'>ALERT</a>"
|
||||
body += "<a href='byond://?src=[UID()];adminalert="+mobUID+"'>ALERT</a> - "
|
||||
body += "<a href='byond://?src=[UID()];adminobserve="+mobUID+"'>OBS</a>"
|
||||
if(eyeUID)
|
||||
body += "|<a href='byond://?src=[UID()];adminplayerobservefollow="+eyeUID+"'>EYE</a>"
|
||||
body += "<br>"
|
||||
|
||||
@@ -1613,6 +1613,17 @@
|
||||
show_player_panel(H)
|
||||
//H.regenerate_icons()
|
||||
|
||||
else if(href_list["adminobserve"])
|
||||
if(!check_rights(R_ADMIN|R_MOD|R_MENTOR))
|
||||
return
|
||||
var/client/C = usr.client
|
||||
var/mob/M = locateUID(href_list["adminobserve"])
|
||||
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
C.admin_observe_target(M)
|
||||
|
||||
else if(href_list["adminplayeropts"])
|
||||
var/mob/M = locateUID(href_list["adminplayeropts"])
|
||||
|
||||
@@ -3586,3 +3597,5 @@
|
||||
var/mob/dead/observer/O = target
|
||||
if(O.mind && O.mind.current)
|
||||
. += "|[ADMIN_FLW(O.mind.current,"BDY")]"
|
||||
else if(ismob(target))
|
||||
. += "|[ADMIN_OBS(target, "OBS")]"
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(<a href='byond://?src=[pm_tracker.UID()];ping=[C.key]'>PING</a>)" : ""
|
||||
var/ticket_link
|
||||
var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(<a href='byond://?src=[pm_tracker.UID()];adminalert=[C.mob.UID()]'>ALERT</a>)" : ""
|
||||
var/observe_link = check_rights(R_MENTOR, FALSE, mob) ? "([ADMIN_OBS(C, "OBS")])" : ""
|
||||
if(ticket_id != -1)
|
||||
if(message_type == MESSAGE_TYPE_MENTORPM)
|
||||
ticket_link = "(<a href='byond://?_src_=holder;openticket=[ticket_id];is_mhelp=1'>TICKET</a>)"
|
||||
@@ -190,7 +191,7 @@
|
||||
receive_window_link = ticket_link
|
||||
else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, C.mob))
|
||||
receive_window_link = ticket_link
|
||||
receive_message = "<span class='[receive_span]'>[type] from-<b>[receive_pm_type] [C.holder ? key_name(src, TRUE, type, ticket_id = ticket_id) : key_name_hidden(src, TRUE, type, ticket_id = ticket_id)]</b>:<br><br>[emoji_msg][C.holder ? "<br>[ping_link] [receive_window_link] [alert_link]" : ""]</span>"
|
||||
receive_message = "<span class='[receive_span]'>[type] from-<b>[receive_pm_type] [C.holder ? key_name(src, TRUE, type, ticket_id = ticket_id) : key_name_hidden(src, TRUE, type, ticket_id = ticket_id)]</b>:<br><br>[emoji_msg][C.holder ? "<br>[ping_link] [receive_window_link] [alert_link] [observe_link]" : ""]</span>"
|
||||
if(message_type == MESSAGE_TYPE_MENTORPM)
|
||||
receive_message = chat_box_mhelp(receive_message)
|
||||
else
|
||||
@@ -202,7 +203,7 @@
|
||||
send_window_link = ticket_link
|
||||
else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, mob))
|
||||
send_window_link = ticket_link
|
||||
var/send_message = "<span class='[send_span]'>[send_pm_type][type] to-<b>[holder ? key_name(C, TRUE, type, ticket_id = ticket_id) : key_name_hidden(C, TRUE, type, ticket_id = ticket_id)]</b>:<br><br>[emoji_msg]</span><br>[ping_link] [send_window_link] [alert_link]"
|
||||
var/send_message = "<span class='[send_span]'>[send_pm_type][type] to-<b>[holder ? key_name(C, TRUE, type, ticket_id = ticket_id) : key_name_hidden(C, TRUE, type, ticket_id = ticket_id)]</b>:<br><br>[emoji_msg]</span><br>[ping_link] [send_window_link] [alert_link] [observe_link]"
|
||||
if(message_type == MESSAGE_TYPE_MENTORPM)
|
||||
send_message = chat_box_mhelp(send_message)
|
||||
else
|
||||
@@ -211,9 +212,9 @@
|
||||
|
||||
var/third_party_message
|
||||
if(message_type == MESSAGE_TYPE_MENTORPM)
|
||||
third_party_message = chat_box_mhelp("<span class='mentorhelp'>[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:<br><br>[emoji_msg]<br>[ping_link] [ticket_link] [alert_link]</span>")
|
||||
third_party_message = chat_box_mhelp("<span class='mentorhelp'>[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:<br><br>[emoji_msg]<br>[ping_link] [ticket_link] [alert_link] [observe_link]</span>")
|
||||
else
|
||||
third_party_message = chat_box_ahelp("<span class='adminhelp'>[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:<br><br>[emoji_msg]<br>[ping_link] [ticket_link] [alert_link]</span>")
|
||||
third_party_message = chat_box_ahelp("<span class='adminhelp'>[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:<br><br>[emoji_msg]<br>[ping_link] [ticket_link] [alert_link] [observe_link]</span>")
|
||||
|
||||
//play the recieving admin the adminhelp sound (if they have them enabled)
|
||||
//non-admins always hear the sound, as they cannot toggle it
|
||||
|
||||
@@ -1172,6 +1172,14 @@
|
||||
else
|
||||
src << link(GLOB.configuration.system.region_map[choice])
|
||||
|
||||
/client/proc/set_eye(new_eye)
|
||||
if(new_eye == eye)
|
||||
return
|
||||
eye = new_eye
|
||||
|
||||
/client/proc/clear_screen()
|
||||
for(var/object in screen)
|
||||
screen -= object
|
||||
|
||||
/client/verb/reload_graphics()
|
||||
set category = "Special Verbs"
|
||||
|
||||
@@ -20,6 +20,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new)
|
||||
move_resist = INFINITY // don't get pushed around
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
blocks_emissive = FALSE // Ghosts are transparent, duh
|
||||
hud_type = /datum/hud/ghost
|
||||
speaks_ooc = TRUE
|
||||
var/can_reenter_corpse
|
||||
var/bootime = FALSE
|
||||
var/started_as_observer //This variable is set to 1 when you enter the game as an observer.
|
||||
@@ -41,8 +43,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new)
|
||||
var/datum/orbit_menu/orbit_menu
|
||||
/// The "color" their runechat would have had
|
||||
var/alive_runechat_color = "#FFFFFF"
|
||||
hud_type = /datum/hud/ghost
|
||||
speaks_ooc = TRUE
|
||||
/// UID of the mob which we are currently observing
|
||||
var/mob_observed
|
||||
|
||||
/mob/dead/observer/New(mob/body=null, flags=1)
|
||||
set_invisibility(GLOB.observer_default_invisibility)
|
||||
@@ -120,6 +122,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new)
|
||||
if(seerads)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
remove_observer_verbs()
|
||||
if(mob_observed)
|
||||
cleanup_observe()
|
||||
return ..()
|
||||
|
||||
/mob/dead/observer/examine(mob/user)
|
||||
@@ -184,25 +188,37 @@ Works together with spawning an observer, noted above.
|
||||
return 1
|
||||
|
||||
/mob/proc/ghostize(flags = GHOST_CAN_REENTER, user_color, ghost_name)
|
||||
if(key)
|
||||
if(player_logged) //if they have disconnected we want to remove their SSD overlay
|
||||
overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
if(GLOB.non_respawnable_keys[ckey])
|
||||
flags &= ~GHOST_CAN_REENTER
|
||||
var/mob/dead/observer/ghost = new(src, flags) //Transfer safety to observer spawning proc.
|
||||
ghost.timeofdeath = src.timeofdeath //BS12 EDIT
|
||||
if(ghost.can_reenter_corpse)
|
||||
ADD_TRAIT(ghost, TRAIT_RESPAWNABLE, GHOSTED)
|
||||
else
|
||||
GLOB.non_respawnable_keys[ckey] = 1
|
||||
if(user_color)
|
||||
add_atom_colour(user_color, ADMIN_COLOUR_PRIORITY)
|
||||
ghost.color = user_color
|
||||
if(ghost_name)
|
||||
ghost.name = ghost_name
|
||||
ghost.key = key
|
||||
ghost.client?.init_verbs()
|
||||
return ghost
|
||||
if(!key)
|
||||
return
|
||||
if(player_logged) // if they have disconnected we want to remove their SSD overlay
|
||||
overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
if(GLOB.non_respawnable_keys[ckey])
|
||||
flags &= ~GHOST_CAN_REENTER
|
||||
var/mob/dead/observer/ghost = new(src, flags) // Transfer safety to observer spawning proc.
|
||||
ghost.timeofdeath = src.timeofdeath // BS12 EDIT
|
||||
if(ghost.can_reenter_corpse)
|
||||
ADD_TRAIT(ghost, TRAIT_RESPAWNABLE, GHOSTED)
|
||||
else
|
||||
GLOB.non_respawnable_keys[ckey] = 1
|
||||
|
||||
// mods, mentors, and the like will have admin observe anyway, so this is moot
|
||||
if(((key in GLOB.antag_hud_users) || (key in GLOB.roundstart_observer_keys)) && !check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE, src))
|
||||
ghost.verbs |= /mob/dead/observer/proc/do_observe
|
||||
ghost.verbs |= /mob/dead/observer/proc/observe
|
||||
if(user_color)
|
||||
add_atom_colour(user_color, ADMIN_COLOUR_PRIORITY)
|
||||
ghost.color = user_color
|
||||
if(ghost_name)
|
||||
ghost.name = ghost_name
|
||||
ghost.key = key
|
||||
|
||||
ghost.client?.init_verbs()
|
||||
|
||||
for(var/mob/dead/observer/obs in observers)
|
||||
obs.cleanup_observe()
|
||||
|
||||
|
||||
return ghost
|
||||
|
||||
/*
|
||||
This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues.
|
||||
@@ -492,52 +508,67 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
GLOB.ghost_crew_monitor.ui_interact(src)
|
||||
|
||||
/mob/dead/observer/proc/add_observer_verbs()
|
||||
verbs.Add(/mob/dead/observer/proc/ManualFollow)
|
||||
verbs.Add(
|
||||
/mob/dead/observer/proc/ManualFollow,
|
||||
)
|
||||
|
||||
/mob/dead/observer/proc/remove_observer_verbs()
|
||||
verbs.Remove(/mob/dead/observer/proc/ManualFollow)
|
||||
verbs.Remove(
|
||||
/mob/dead/observer/proc/ManualFollow,
|
||||
// these might not necessarily be here, but we want to make sure they're gonezo anyway
|
||||
/mob/dead/observer/proc/observe,
|
||||
/mob/dead/observer/proc/do_observe
|
||||
)
|
||||
|
||||
// This is the ghost's follow verb with an argument
|
||||
// This is the ghost's follow verb with an argument.
|
||||
// We need to do the usr check on this verb itself, but the logic follows.
|
||||
/mob/dead/observer/proc/ManualFollow(atom/movable/target)
|
||||
set name = "\[Observer\] Orbit"
|
||||
set desc = "Orbits the specified movable atom."
|
||||
set category = null
|
||||
|
||||
if(!target || !isobserver(usr))
|
||||
// this usr check is apparently necessary for security
|
||||
if(!isobserver(usr))
|
||||
return
|
||||
|
||||
return do_manual_follow(target)
|
||||
|
||||
// We need to check usr when calling the verb, but we still want this logic to be accessible elsewhere
|
||||
/mob/dead/observer/proc/do_manual_follow(atom/movable/target)
|
||||
if(!get_turf(target))
|
||||
return
|
||||
|
||||
if(target != src)
|
||||
if(src in target.get_orbiters())
|
||||
return
|
||||
if(!target || target == src)
|
||||
return
|
||||
|
||||
var/icon/I = icon(target.icon,target.icon_state,target.dir)
|
||||
if(src in target.get_orbiters())
|
||||
return
|
||||
|
||||
var/orbitsize = (I.Width()+I.Height())*0.5
|
||||
var/icon/I = icon(target.icon, target.icon_state, target.dir)
|
||||
|
||||
if(orbitsize == 0)
|
||||
orbitsize = 40
|
||||
var/orbitsize = (I.Width() + I.Height())*0.5
|
||||
|
||||
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
|
||||
if(orbitsize == 0)
|
||||
orbitsize = 40
|
||||
|
||||
var/rot_seg
|
||||
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
|
||||
|
||||
switch(ghost_orbit)
|
||||
if(GHOST_ORBIT_TRIANGLE)
|
||||
rot_seg = 3
|
||||
if(GHOST_ORBIT_SQUARE)
|
||||
rot_seg = 4
|
||||
if(GHOST_ORBIT_PENTAGON)
|
||||
rot_seg = 5
|
||||
if(GHOST_ORBIT_HEXAGON)
|
||||
rot_seg = 6
|
||||
else //Circular
|
||||
rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle
|
||||
var/rot_seg
|
||||
|
||||
to_chat(src, "<span class='notice'>Now following [target].</span>")
|
||||
orbit(target,orbitsize, FALSE, 20, rot_seg)
|
||||
switch(ghost_orbit)
|
||||
if(GHOST_ORBIT_TRIANGLE)
|
||||
rot_seg = 3
|
||||
if(GHOST_ORBIT_SQUARE)
|
||||
rot_seg = 4
|
||||
if(GHOST_ORBIT_PENTAGON)
|
||||
rot_seg = 5
|
||||
if(GHOST_ORBIT_HEXAGON)
|
||||
rot_seg = 6
|
||||
else // Circular
|
||||
rot_seg = 36 // 360/10 bby, smooth enough aproximation of a circle
|
||||
|
||||
to_chat(src, "<span class='notice'>Now following [target].</span>")
|
||||
orbit(target, orbitsize, FALSE, 20, rot_seg)
|
||||
|
||||
/mob/dead/observer/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lock_in_orbit = FALSE, force_move = FALSE, orbit_layer = GHOST_LAYER)
|
||||
setDir(2)//reset dir so the right directional sprites show up
|
||||
@@ -825,6 +856,102 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
/mob/dead/observer/get_runechat_color()
|
||||
return alive_runechat_color
|
||||
|
||||
/mob/dead/observer/proc/observe()
|
||||
set name = "Observe"
|
||||
set desc = "Observe a mob."
|
||||
set category = "Ghost"
|
||||
|
||||
var/list/possible_targets = list()
|
||||
for(var/mob/living/L in GLOB.player_list)
|
||||
if(!L.mind)
|
||||
continue
|
||||
possible_targets.Add(L)
|
||||
|
||||
if(!length(possible_targets))
|
||||
to_chat(src, "<span class='warning'>There's nobody for you to observe!</span>")
|
||||
return
|
||||
|
||||
var/mob/target = tgui_input_list(usr, "Please, select a player!", "Observe", possible_targets)
|
||||
if(!istype(target) || QDELETED(target))
|
||||
return
|
||||
do_observe(target)
|
||||
|
||||
/mob/dead/observer/proc/do_observe(mob/mob_eye)
|
||||
set name = "\[Observer\] Observe"
|
||||
set desc = "Observe the target mob."
|
||||
set category = null
|
||||
|
||||
if(isnewplayer(mob_eye))
|
||||
to_chat(src, "<span class='warning'>You can't observe someone in the lobby.</span>")
|
||||
return
|
||||
|
||||
if(isobserver(mob_eye))
|
||||
to_chat(src, "<span class='warning'>You can't observe a ghost.</span>")
|
||||
return
|
||||
|
||||
if(!mob_eye.mind)
|
||||
to_chat(src, "<span class='notice'>You can only observe mobs that have been or are being inhabited by a player!</span>")
|
||||
return
|
||||
|
||||
if(mob_eye == src)
|
||||
to_chat(src, "<span class='warning'>You can't observe yourself!</span>")
|
||||
return
|
||||
|
||||
if(mob_observed)
|
||||
// clean up first
|
||||
stop_orbit()
|
||||
cleanup_observe()
|
||||
|
||||
// Istype so we filter out points of interest that are not mobs
|
||||
if(client && ismob(mob_eye))
|
||||
// follow the mob so they're technically right there for visible messages n stuff
|
||||
// call the sub-proc since the base one checks for usr
|
||||
do_manual_follow(mob_eye)
|
||||
client.set_eye(mob_eye)
|
||||
add_attack_logs(src, mob_eye, "observed", ATKLOG_ALMOSTALL)
|
||||
client.perspective = EYE_PERSPECTIVE
|
||||
if(mob_eye.hud_used)
|
||||
client.clear_screen()
|
||||
LAZYOR(mob_eye.observers, src)
|
||||
mob_eye.hud_used?.show_hud(mob_eye.hud_used.hud_version, src)
|
||||
mob_observed = mob_eye.UID()
|
||||
|
||||
|
||||
// mentor observing grants you this trait, and provides its own signal handler for this
|
||||
if(!HAS_MIND_TRAIT(src, TRAIT_MENTOR_OBSERVING))
|
||||
RegisterSignal(src, COMSIG_ATOM_ORBITER_STOP, PROC_REF(on_observer_orbit_end), override = TRUE)
|
||||
else
|
||||
if(!check_rights(R_MENTOR, FALSE, src))
|
||||
log_debug("[key_name(src)] has the the mobserve trait while observing, but isn't a mentor. This is likely an error, and may result in them getting stuck")
|
||||
|
||||
/// Clean up observing
|
||||
/mob/dead/observer/proc/cleanup_observe()
|
||||
if(isnull(mob_observed))
|
||||
return
|
||||
|
||||
var/mob/target = locateUID(mob_observed)
|
||||
add_attack_logs(src, target, "un-observed", ATKLOG_ALL)
|
||||
mob_observed = null
|
||||
reset_perspective(null)
|
||||
client?.perspective = initial(client.perspective)
|
||||
set_sight(initial(sight))
|
||||
UnregisterSignal(src, COMSIG_ATOM_ORBITER_STOP)
|
||||
|
||||
if(s_active)
|
||||
var/obj/item/storage/bag = s_active
|
||||
s_active = null
|
||||
bag.update_viewers(src)
|
||||
|
||||
if(!QDELETED(target) && istype(target))
|
||||
hide_other_mob_action_buttons(target)
|
||||
target.observers -= src
|
||||
|
||||
/mob/dead/observer/proc/on_observer_orbit_end(mob/follower, atom)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_ORBITER_STOP
|
||||
if(HAS_MIND_TRAIT(src, TRAIT_MENTOR_OBSERVING))
|
||||
log_debug("[key_name(src)] ended up in regular cleanup_observe rather than the mentor cleanup observe despite having TRAIT_MENTOR_OBSERVING. This is likely a bug and may result in them being stuck outside of their bodies.")
|
||||
cleanup_observe()
|
||||
|
||||
/mob/dead/observer/proc/update_dead_radio()
|
||||
if(get_preference(PREFTOGGLE_CHAT_GHOSTRADIO))
|
||||
GLOB.deadchat_radio.listeners |= src
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/mob/dead/observer/Logout()
|
||||
if(client)
|
||||
client.images -= GLOB.ghost_images
|
||||
if(mob_observed && ismob(locateUID(mob_observed)))
|
||||
cleanup_observe()
|
||||
|
||||
..()
|
||||
spawn(0)
|
||||
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
r_hand.screen_loc = ui_rhand
|
||||
client.screen += r_hand
|
||||
|
||||
update_observer_view(r_hand)
|
||||
|
||||
/mob/living/carbon/update_inv_l_hand(ignore_cuffs)
|
||||
if(handcuffed && !ignore_cuffs)
|
||||
drop_l_hand()
|
||||
@@ -57,6 +59,7 @@
|
||||
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
|
||||
l_hand.screen_loc = ui_lhand
|
||||
client.screen += l_hand
|
||||
update_observer_view(l_hand)
|
||||
|
||||
/mob/living/carbon/update_inv_wear_mask()
|
||||
if(istype(wear_mask, /obj/item/clothing/mask))
|
||||
@@ -86,3 +89,17 @@
|
||||
/mob/living/carbon/proc/update_hud_back(obj/item/I)
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/update_observer_view(obj/item/worn_item, inventory)
|
||||
if(!length(observers))
|
||||
return
|
||||
for(var/mob/dead/observe as anything in observers)
|
||||
if(observe.client && observe.client.eye == src)
|
||||
if(observe.hud_used)
|
||||
if(inventory && !observe.hud_used.inventory_shown)
|
||||
continue
|
||||
observe.client.screen += worn_item
|
||||
else
|
||||
observers -= observe
|
||||
if(!length(observers))
|
||||
observers.Cut()
|
||||
break
|
||||
|
||||
@@ -186,6 +186,13 @@
|
||||
update_inv_r_hand()
|
||||
|
||||
I.screen_loc = null
|
||||
if(client)
|
||||
client.screen -= I
|
||||
if(length(observers))
|
||||
for(var/mob/dead/observe as anything in observers)
|
||||
if(observe.client)
|
||||
observe.client.screen -= I
|
||||
|
||||
I.forceMove(src)
|
||||
I.equipped(src, slot, initial)
|
||||
I.layer = ABOVE_HUD_LAYER
|
||||
@@ -271,8 +278,8 @@
|
||||
var/obj/item/clothing/head/hat = I
|
||||
if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha))
|
||||
update_sight()
|
||||
// this calls update_inv_head() on its own
|
||||
head_update(I)
|
||||
update_inv_head()
|
||||
if(SLOT_HUD_SHOES)
|
||||
shoes = I
|
||||
update_inv_shoes()
|
||||
|
||||
@@ -567,10 +567,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(w_uniform && istype(w_uniform, /obj/item/clothing/under))
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
w_uniform.screen_loc = ui_iclothing //...draw the item in the inventory screen
|
||||
client.screen += w_uniform //Either way, add the item to the HUD
|
||||
update_hud_uniform(w_uniform)
|
||||
|
||||
var/t_color = w_uniform.item_color
|
||||
if(!t_color)
|
||||
@@ -644,9 +641,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_id)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
wear_id.screen_loc = ui_id
|
||||
client.screen += wear_id
|
||||
update_hud_id(wear_id)
|
||||
|
||||
if(w_uniform && w_uniform:displays_id)
|
||||
overlays_standing[ID_LAYER] = mutable_appearance('icons/mob/mob.dmi', "id", layer = -ID_LAYER)
|
||||
@@ -660,10 +655,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(gloves)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
gloves.screen_loc = ui_gloves //...draw the item in the inventory screen
|
||||
client.screen += gloves //Either way, add the item to the HUD
|
||||
update_hud_gloves(gloves)
|
||||
|
||||
var/t_state = gloves.item_state
|
||||
if(!t_state) t_state = gloves.icon_state
|
||||
@@ -702,10 +694,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
if(glasses)
|
||||
var/mutable_appearance/new_glasses
|
||||
var/obj/item/organ/external/head/head_organ = get_organ("head")
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
|
||||
client.screen += glasses //Either way, add the item to the HUD
|
||||
update_hud_glasses(glasses)
|
||||
|
||||
if(glasses.icon_override)
|
||||
new_glasses = mutable_appearance(glasses.icon_override, "[glasses.icon_state]", layer = -GLASSES_LAYER)
|
||||
@@ -744,10 +733,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
|
||||
if(l_ear || r_ear)
|
||||
if(l_ear)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
l_ear.screen_loc = ui_l_ear //...draw the item in the inventory screen
|
||||
client.screen += l_ear //Either way, add the item to the HUD
|
||||
update_hud_l_ear(l_ear)
|
||||
|
||||
var/t_type = l_ear.item_state
|
||||
if(!t_type)
|
||||
@@ -761,10 +747,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
overlays_standing[EARS_LAYER] = mutable_appearance('icons/mob/clothing/ears.dmi', "[t_type]", layer = -EARS_LAYER)
|
||||
|
||||
if(r_ear)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
r_ear.screen_loc = ui_r_ear //...draw the item in the inventory screen
|
||||
client.screen += r_ear //Either way, add the item to the HUD
|
||||
update_hud_r_ear(r_ear)
|
||||
|
||||
var/t_type = r_ear.item_state
|
||||
if(!t_type)
|
||||
@@ -786,10 +769,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(shoes)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
shoes.screen_loc = ui_shoes //...draw the item in the inventory screen
|
||||
client.screen += shoes //Either way, add the item to the HUD
|
||||
update_hud_shoes(shoes)
|
||||
|
||||
if(!wear_suit || !(wear_suit.flags_inv & HIDESHOES))
|
||||
var/mutable_appearance/standing
|
||||
@@ -822,9 +802,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(s_store)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
s_store.screen_loc = ui_sstore1
|
||||
client.screen += s_store
|
||||
update_hud_s_store(s_store)
|
||||
|
||||
var/t_state = s_store.item_state
|
||||
if(!t_state)
|
||||
@@ -844,6 +822,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(head)
|
||||
update_hud_head(head)
|
||||
var/mutable_appearance/standing
|
||||
if(head.sprite_sheets && head.sprite_sheets[dna.species.sprite_sheet_name])
|
||||
standing = mutable_appearance(head.sprite_sheets[dna.species.sprite_sheet_name], "[head.icon_state]", layer = -HEAD_LAYER)
|
||||
@@ -877,6 +856,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
belt.screen_loc = ui_belt
|
||||
|
||||
if(belt)
|
||||
update_observer_view(belt)
|
||||
var/t_state = belt.item_state
|
||||
if(!t_state)
|
||||
t_state = belt.icon_state
|
||||
@@ -899,10 +879,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_suit && istype(wear_suit, /obj/item/clothing/suit))
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
|
||||
client.screen += wear_suit //Either way, add the item to the HUD
|
||||
update_hud_wear_suit(wear_suit)
|
||||
|
||||
var/mutable_appearance/standing
|
||||
if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[dna.species.sprite_sheet_name])
|
||||
@@ -950,12 +927,17 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
|
||||
if(hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(l_store)
|
||||
client.screen += l_store
|
||||
l_store.screen_loc = ui_storage1
|
||||
if(hud_used.hud_shown)
|
||||
client.screen += l_store
|
||||
update_observer_view(l_store)
|
||||
|
||||
if(r_store)
|
||||
client.screen += r_store
|
||||
r_store.screen_loc = ui_storage2
|
||||
if(hud_used.hud_shown)
|
||||
client.screen += r_store
|
||||
r_store.screen_loc = ui_storage2
|
||||
update_observer_view(r_store)
|
||||
|
||||
/mob/living/carbon/human/update_inv_wear_pda()
|
||||
if(client && hud_used)
|
||||
@@ -964,8 +946,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_pda)
|
||||
client.screen += wear_pda
|
||||
wear_pda.screen_loc = ui_pda
|
||||
update_hud_wear_pda(wear_pda)
|
||||
|
||||
/mob/living/carbon/human/update_inv_wear_mask()
|
||||
..()
|
||||
@@ -975,6 +956,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
if(inv)
|
||||
inv.update_icon()
|
||||
if(wear_mask && (istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory)))
|
||||
update_hud_wear_mask(wear_mask)
|
||||
if(!(SLOT_HUD_WEAR_MASK in check_obscured_slots()))
|
||||
var/obj/item/organ/external/head/head_organ = get_organ("head")
|
||||
if(!istype(head_organ))
|
||||
@@ -1009,6 +991,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
..()
|
||||
remove_overlay(BACK_LAYER)
|
||||
if(back)
|
||||
update_hud_back(back)
|
||||
//determine the icon to use
|
||||
var/t_state = back.item_state
|
||||
if(!t_state)
|
||||
@@ -1045,6 +1028,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
..()
|
||||
remove_overlay(R_HAND_LAYER)
|
||||
if(r_hand)
|
||||
show_hand_to_observers(r_hand, left = FALSE)
|
||||
var/t_state = r_hand.item_state
|
||||
if(!t_state)
|
||||
t_state = r_hand.icon_state
|
||||
@@ -1064,6 +1048,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
..()
|
||||
remove_overlay(L_HAND_LAYER)
|
||||
if(l_hand)
|
||||
show_hand_to_observers(l_hand, left = TRUE)
|
||||
var/t_state = l_hand.item_state
|
||||
if(!t_state)
|
||||
t_state = l_hand.icon_state
|
||||
@@ -1080,25 +1065,105 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
|
||||
//human HUD updates for items in our inventory
|
||||
|
||||
//update whether our head item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_head(obj/item/I)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown)
|
||||
I.screen_loc = ui_head
|
||||
client.screen += I
|
||||
/mob/living/carbon/human/proc/show_hand_to_observers(obj/item/worn_item, left = TRUE)
|
||||
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
|
||||
worn_item.screen_loc = ui_hand_position(left ? 1 : 2)
|
||||
client.screen += worn_item
|
||||
if(length(observers))
|
||||
for(var/mob/dead/observe in observers)
|
||||
if(observe.client && observe.client.eye == src)
|
||||
observe.client.screen += worn_item
|
||||
else
|
||||
observers -= observe
|
||||
if(!length(observers))
|
||||
observers = null
|
||||
break
|
||||
|
||||
//update whether our mask item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_wear_mask(obj/item/I)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
if(hud_used.inventory_shown)
|
||||
I.screen_loc = ui_mask
|
||||
client.screen += I
|
||||
|
||||
//update whether our back item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_back(obj/item/I)
|
||||
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
I.screen_loc = ui_back
|
||||
client.screen += I
|
||||
/mob/living/carbon/human/update_hud_wear_mask(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_mask
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_uniform(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_iclothing
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_id(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_id
|
||||
if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_wear_pda(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_pda
|
||||
if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_gloves(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_gloves
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_glasses(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_glasses
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_l_ear(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_l_ear
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_r_ear(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_r_ear
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_shoes(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_shoes
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_s_store(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_sstore1
|
||||
if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_wear_suit(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_oclothing
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_hud_belt(obj/item/worn_item)
|
||||
belt.screen_loc = ui_belt
|
||||
if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/update_hud_head(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_head
|
||||
if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown))
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/update_hud_back(obj/item/worn_item)
|
||||
worn_item.screen_loc = ui_back
|
||||
if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD)
|
||||
client.screen += worn_item
|
||||
update_observer_view(worn_item, TRUE)
|
||||
|
||||
/mob/living/carbon/human/proc/update_wing_layer()
|
||||
remove_overlay(WING_UNDERLIMBS_LAYER)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
if(mind && suiciding)
|
||||
mind.suicided = TRUE
|
||||
reset_perspective(null)
|
||||
hud_used?.reload_fullscreen()
|
||||
reload_fullscreen()
|
||||
update_sight()
|
||||
update_action_buttons_icon()
|
||||
ADD_TRAIT(src, TRAIT_FLOORED, STAT_TRAIT)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
|
||||
observer_screen_update(O, add = FALSE)
|
||||
if(client)
|
||||
client.screen -= O
|
||||
contents -= O
|
||||
@@ -78,6 +79,7 @@
|
||||
set_actions(O)
|
||||
else
|
||||
to_chat(src, "You need to disable a module first!")
|
||||
observer_screen_update(O, add = TRUE)
|
||||
check_module_damage(FALSE)
|
||||
update_icons()
|
||||
|
||||
@@ -250,3 +252,25 @@
|
||||
hands.icon_state = "nomod"
|
||||
else
|
||||
hands.icon_state = lowertext(module.module_type)
|
||||
|
||||
|
||||
/**
|
||||
* Updates the observers's screens with cyborg itemss.
|
||||
* Arguments
|
||||
* * item_module - the item being added or removed from the screen
|
||||
* * add - whether or not the item is being added, or removed.
|
||||
*/
|
||||
/mob/living/silicon/robot/proc/observer_screen_update(obj/item/item_module, add = TRUE)
|
||||
if(!length(observers))
|
||||
return
|
||||
for(var/mob/dead/observe in observers)
|
||||
if(observe.client && observe.client.eye == src)
|
||||
if(add)
|
||||
observe.client.screen += item_module
|
||||
else
|
||||
observe.client.screen -= item_module
|
||||
else
|
||||
observers -= observe
|
||||
if(!length(observers))
|
||||
observers = null
|
||||
break
|
||||
|
||||
@@ -27,10 +27,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/atom/movable/screen/lamp_button = null
|
||||
var/atom/movable/screen/thruster_button = null
|
||||
|
||||
/// Used to determine whether the robot has the module menu shown or not.
|
||||
var/shown_robot_modules = FALSE
|
||||
var/atom/movable/screen/robot_modules_background
|
||||
|
||||
// 3 Modules can be activated at any one time.
|
||||
var/obj/item/robot_module/module = null
|
||||
var/module_active = null
|
||||
@@ -172,11 +168,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
|
||||
wires = new(src)
|
||||
|
||||
robot_modules_background = new()
|
||||
robot_modules_background.icon_state = "block"
|
||||
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer 20, UI should be just below it.
|
||||
robot_modules_background.plane = HUD_PLANE
|
||||
|
||||
ident = rand(1, 999)
|
||||
rename_character(null, get_default_name())
|
||||
update_icons()
|
||||
@@ -664,9 +655,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
|
||||
/mob/living/silicon/robot/proc/reset_module()
|
||||
notify_ai(2)
|
||||
|
||||
shown_robot_modules = 0
|
||||
client?.screen -= robot_modules_background
|
||||
client?.screen -= hud_used.module_store_icon
|
||||
uneq_all()
|
||||
SStgui.close_user_uis(src)
|
||||
@@ -699,6 +687,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
|
||||
status_flags |= CANPUSH
|
||||
|
||||
hud_used.update_robot_modules_display()
|
||||
|
||||
//for borg hotkeys, here module refers to borg inv slot, not core module
|
||||
/mob/living/silicon/robot/verb/cmd_toggle_module(module as num)
|
||||
set name = "Toggle Module"
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
update_blind_effects()
|
||||
update_sight()
|
||||
updatehealth("update revive")
|
||||
hud_used?.reload_fullscreen()
|
||||
reload_fullscreen()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, updating)
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
viewing_alternate_appearances = null
|
||||
LAssailant = null
|
||||
runechat_msg_location = null
|
||||
if(length(observers))
|
||||
for(var/mob/dead/observe as anything in observers)
|
||||
observe.reset_perspective(null)
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/Initialize(mapload)
|
||||
@@ -600,7 +604,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
if(.)
|
||||
// Allows sharing HUDs with ghosts
|
||||
if(hud_used)
|
||||
client.screen = list()
|
||||
client.clear_screen()
|
||||
hud_used.show_hud(hud_used.hud_version)
|
||||
|
||||
//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine()
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
var/datum/input_focus = null
|
||||
/// Is our mob currently suiciding? Used for suicide code along with many different revival checks
|
||||
var/suiciding = FALSE
|
||||
/// Used for some screen objects, such as
|
||||
/// Used for some screen objects
|
||||
var/list/screens = list()
|
||||
/// lazy list. contains /atom/movable/screen/alert only, On /mob so clientless mobs will throw alerts properly
|
||||
var/list/alerts
|
||||
@@ -246,7 +246,8 @@
|
||||
var/next_click_modifier = 1
|
||||
/// Tracks the open UIs that a mob has, used in TGUI for various things, such as updating UIs
|
||||
var/list/open_uis = list()
|
||||
|
||||
/// List of observers currently observing us.
|
||||
var/list/mob/dead/observer/observers = list()
|
||||
/// Does this mob speak OOC?
|
||||
/// Controls whether they can say some symbols.
|
||||
var/speaks_ooc = FALSE
|
||||
|
||||
@@ -182,7 +182,10 @@
|
||||
var/period_human_readable = "within [GLOB.configuration.general.roundstart_observer_period] minute\s"
|
||||
if(GLOB.configuration.general.roundstart_observer_period == 0)
|
||||
period_human_readable = "before the round started"
|
||||
to_chat(src, "<span class='notice'>As you observed [period_human_readable], you can freely toggle antag-hud without losing respawnability.</span>")
|
||||
to_chat(src, "<span class='notice'>As you observed [period_human_readable], you can freely toggle antag-hud without losing respawnability, and can freely observe what other players see.</span>")
|
||||
if(!check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE, src))
|
||||
// admins always get aobserve
|
||||
add_verb(observer, list(/mob/dead/observer/proc/do_observe, /mob/dead/observer/proc/observe))
|
||||
observer.started_as_observer = 1
|
||||
close_spawn_windows()
|
||||
var/obj/spawn_point
|
||||
|
||||
@@ -81,6 +81,9 @@ GLOBAL_DATUM_INIT(ghost_hud_panel, /datum/ui_module/ghost_hud_panel, new)
|
||||
|
||||
GLOB.antag_hud_users |= ghost.ckey
|
||||
|
||||
if(!check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE))
|
||||
// admins always get aobserve
|
||||
add_verb(ghost, list(/mob/dead/observer/proc/do_observe, /mob/dead/observer/proc/observe))
|
||||
|
||||
ghost.antagHUD = TRUE
|
||||
for(var/datum/atom_hud/antag/H in GLOB.huds)
|
||||
|
||||
Reference in New Issue
Block a user