Skip to content

Commit

Permalink
notify ghosts (cmss13-devs#4241)
Browse files Browse the repository at this point in the history
observer qol

tgstation/tgstation#8101
tgstation/tgstation#12665
tgstation/tgstation#24836
tgstation/tgstation#40727
tgstation/tgstation#66352
tgstation/tgstation#68343

🆑 Tkdrg, many TG contributors
add: dchat notifications now have a better interface
/🆑
  • Loading branch information
harryob authored Aug 30, 2023
1 parent 9a180e2 commit 364fbf7
Show file tree
Hide file tree
Showing 24 changed files with 305 additions and 36 deletions.
6 changes: 6 additions & 0 deletions code/__DEFINES/hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@
#define APPEARANCE_UI_IGNORE_ALPHA (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE)
/// Used for HUD objects
#define APPEARANCE_UI (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE)

// Notification action types
#define NOTIFY_JUMP "jump"
#define NOTIFY_ATTACK "attack"
#define NOTIFY_ORBIT "orbit"
#define NOTIFY_JOIN_XENO "join_xeno"
1 change: 1 addition & 0 deletions code/__DEFINES/sounds.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define ITEM_EQUIP_VOLUME 50

//Reserved channels
#define SOUND_CHANNEL_NOTIFY 1016
#define SOUND_CHANNEL_VOX 1017
#define SOUND_CHANNEL_MUSIC 1018
#define SOUND_CHANNEL_AMBIENCE 1019
Expand Down
7 changes: 7 additions & 0 deletions code/_onclick/hud/_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@
#define ui_ghost_slot3 "SOUTH:6,CENTER:0"
#define ui_ghost_slot4 "SOUTH:6,CENTER+1:0"
#define ui_ghost_slot5 "SOUTH:6,CENTER+2:0"

//Upper-middle right (alerts)
#define ui_alert1 "EAST-1:28,CENTER+5:27"
#define ui_alert2 "EAST-1:28,CENTER+4:25"
#define ui_alert3 "EAST-1:28,CENTER+3:23"
#define ui_alert4 "EAST-1:28,CENTER+2:21"
#define ui_alert5 "EAST-1:28,CENTER+1:19"
37 changes: 37 additions & 0 deletions code/_onclick/hud/hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,40 @@
zone_sel.color = ui_color
zone_sel.update_icon(mymob)
static_inventory += zone_sel

// Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
/datum/hud/proc/reorganize_alerts(mob/viewmob)
var/mob/screenmob = viewmob || mymob
if(!screenmob.client)
return
var/list/alerts = mymob.alerts
if(!length(alerts))
return FALSE
if(!hud_shown)
for(var/category in alerts)
var/atom/movable/screen/alert/alert = alerts[category]
screenmob.client.screen -= alert
return TRUE
var/c = 0
for(var/category in alerts)
var/atom/movable/screen/alert/alert = alerts[category]
c++
switch(c)
if(1)
. = ui_alert1
if(2)
. = ui_alert2
if(3)
. = ui_alert3
if(4)
. = ui_alert4
if(5)
. = ui_alert5 // Right now there's 5 slots
else
. = ""
alert.screen_loc = .
screenmob.client.screen |= alert
if(!viewmob)
for(var/obs in mymob.observers)
reorganize_alerts(obs)
return TRUE
9 changes: 3 additions & 6 deletions code/datums/effects/neurotoxin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@
switch(rand(0, 100))
if(0 to 5)
if(hallu_area)
for(var/mob/dead/observer/observer as anything in GLOB.observer_list)
to_chat(observer, SPAN_DEADSAY("<b>[victim]</b> has experienced a rare neuro-induced 'Schizo Lurker Pounce' hallucination (5% chance) at \the <b>[hallu_area]</b>" + " [OBSERVER_JMP(observer, victim)]"))
notify_ghosts(header = "Hallucinating!", message = "<b>[victim]</b> has experienced a rare neuro-induced 'Schizo Lurker Pounce' hallucination (5% chance) at <b>[hallu_area]</b>.", source = victim, action = NOTIFY_ORBIT)
playsound_client(victim?.client,pick('sound/voice/alien_pounce.ogg','sound/voice/alien_pounce.ogg'))
victim.KnockDown(3)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), victim.client,"alien_claw_flesh"), 1 SECONDS)
Expand All @@ -141,17 +140,15 @@
victim.emote("pain")
if(6 to 10)
if(hallu_area)
for(var/mob/dead/observer/observer as anything in GLOB.observer_list)
to_chat(observer, SPAN_DEADSAY("<b>[victim]</b> has experienced a rare neuro-induced 'OB' hallucination (4% chance) at \the <b>[hallu_area]</b>" + " [OBSERVER_JMP(observer, victim)]"))
notify_ghosts(header = "Hallucinating!", message = "<b>[victim]</b> has experienced a rare neuro-induced 'OB' hallucination (4% chance) at <b>[hallu_area]</b>.", source = victim, action = NOTIFY_ORBIT)
playsound_client(victim.client,'sound/effects/ob_alert.ogg')
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), victim.client,'sound/weapons/gun_orbital_travel.ogg'), 2 SECONDS)
if(11 to 16)
playsound_client(victim.client,'sound/voice/alien_queen_screech.ogg')
victim.KnockDown(1)
if(17 to 24)
if(hallu_area)
for(var/mob/dead/observer/observer as anything in GLOB.observer_list)
to_chat(observer, SPAN_DEADSAY("<b>[victim]</b> has experienced a rare neuro-induced 'Fake CAS firemission' hallucination (7% chance) at \the <b>[hallu_area]</b>" + " [OBSERVER_JMP(observer, victim)]"))
notify_ghosts(header = "Hallucinating!", message = "<b>[victim]</b> has experienced a rare neuro-induced 'Fake CAS firemission' hallucination (7% chance) at <b>[hallu_area]</b>", source = victim, action = NOTIFY_ORBIT)
hallucination_fakecas_sequence(victim) //Not gonna spam a billion timers for this one so outsourcing to a proc with sleeps is a better async solution
if(25 to 42)
to_chat(victim,SPAN_HIGHDANGER("A SHELL IS ABOUT TO IMPACT [pick(SPAN_UNDERLINE("TOWARDS THE [pick("WEST","EAST","SOUTH","NORTH")]"),SPAN_UNDERLINE("RIGHT ONTOP OF YOU!"))]!"))
Expand Down
15 changes: 10 additions & 5 deletions code/modules/admin/verbs/freeforghosts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@
to_chat(src, "Only staff members may use this.")
return

free_for_ghosts(M)
free_for_ghosts(M, notify = TRUE)

message_admins("[key_name_admin(usr)] freed [key_name(M)] for ghosts to take.")

/client/proc/free_for_ghosts(mob/living/M in GLOB.living_mob_list)
/client/proc/free_for_ghosts(mob/living/M in GLOB.living_mob_list, notify)
if(!ismob(M))
return

M.free_for_ghosts()
M.free_for_ghosts(notify)

/mob/proc/free_for_ghosts()
/mob/proc/free_for_ghosts(notify)
if(mind || client)
ghostize(FALSE)

GLOB.freed_mob_list |= WEAKREF(src)

if(!notify)
return

notify_ghosts(header = "Freed Mob", message = "A mob is now available for ghosts. Name: [real_name], Job: [job ? job : ""]", enter_link = "claim_freed=[REF(src)]", source = src, action = NOTIFY_ORBIT)

/client/proc/free_all_mobs_in_view()
set name = "Free All Mobs"
set category = "Admin.InView"
Expand All @@ -34,6 +39,6 @@
return

for(var/mob/living/M in view())
free_for_ghosts(M)
free_for_ghosts(M, notify = FALSE)

message_admins(WRAP_STAFF_LOG(usr, "freed all mobs in [get_area(usr)] ([usr.x],[usr.y],[usr.z])"), usr.x, usr.y, usr.z)
3 changes: 3 additions & 0 deletions code/modules/client/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list(
//if(prefs.window_skin & TOGGLE_WINDOW_SKIN)
// set_night_skin()

if(!tooltips && prefs.tooltips)
tooltips = new(src)

load_player_data()

view = world_view_size
Expand Down
15 changes: 15 additions & 0 deletions code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ var/const/MAX_SAVE_SLOTS = 10
/// if this client has custom cursors enabled
var/custom_cursors = TRUE

/// if this client has tooltips enabled
var/tooltips = TRUE

/datum/preferences/New(client/C)
key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys
macros = new(C, src)
Expand Down Expand Up @@ -573,6 +576,7 @@ var/const/MAX_SAVE_SLOTS = 10
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'><b>[toggle_prefs & TOGGLE_AMBIENT_OCCLUSION ? "Enabled" : "Disabled"]</b></a><br>"
dat += "<b>Fit Viewport:</b> <a href='?_src_=prefs;preference=auto_fit_viewport'>[auto_fit_viewport ? "Auto" : "Manual"]</a><br>"
dat += "<b>Adaptive Zoom:</b> <a href='?_src_=prefs;preference=adaptive_zoom'>[adaptive_zoom ? "[adaptive_zoom * 2]x" : "Disabled"]</a><br>"
dat += "<b>Tooltips:</b> <a href='?_src_=prefs;preference=tooltips'><b>[tooltips ? "Enabled" : "Disabled"]</b></a><br>"
dat += "<b>tgui Window Mode:</b> <a href='?_src_=prefs;preference=tgui_fancy'><b>[(tgui_fancy) ? "Fancy (default)" : "Compatible (slower)"]</b></a><br>"
dat += "<b>tgui Window Placement:</b> <a href='?_src_=prefs;preference=tgui_lock'><b>[(tgui_lock) ? "Primary monitor" : "Free (default)"]</b></a><br>"
dat += "<b>Play Admin Midis:</b> <a href='?_src_=prefs;preference=hear_midis'><b>[(toggles_sound & SOUND_MIDI) ? "Yes" : "No"]</b></a><br>"
Expand Down Expand Up @@ -1862,6 +1866,17 @@ var/const/MAX_SAVE_SLOTS = 10
adaptive_zoom = 0
owner?.adaptive_zoom()

if("tooltips")
tooltips = !tooltips
save_preferences()

if(!tooltips)
closeToolTip()
return

if(!owner.tooltips)
owner.tooltips = new(owner)

if("inputstyle")
var/result = tgui_alert(user, "Which input style do you want?", "Input Style", list("Modern", "Legacy"))
if(!result)
Expand Down
2 changes: 2 additions & 0 deletions code/modules/client/preferences_savefile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
S["custom_cursors"] >> custom_cursors
S["autofit_viewport"] >> auto_fit_viewport
S["adaptive_zoom"] >> adaptive_zoom
S["tooltips"] >> tooltips

//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, CONFIG_GET(string/ooc_color_default))
Expand Down Expand Up @@ -225,6 +226,7 @@
no_radial_labels_preference = sanitize_integer(no_radial_labels_preference, FALSE, TRUE, FALSE)
auto_fit_viewport = sanitize_integer(auto_fit_viewport, FALSE, TRUE, TRUE)
adaptive_zoom = sanitize_integer(adaptive_zoom, 0, 2, 0)
tooltips = sanitize_integer(tooltips, FALSE, TRUE, TRUE)

synthetic_name = synthetic_name ? sanitize_text(synthetic_name, initial(synthetic_name)) : initial(synthetic_name)
synthetic_type = sanitize_inlist(synthetic_type, PLAYER_SYNTHS, initial(synthetic_type))
Expand Down
2 changes: 1 addition & 1 deletion code/modules/cm_aliens/structures/special/pylon_core.dm
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@
last_surge_time = world.time
linked_hive.stored_larva++
linked_hive.hijack_burrowed_left--
announce_dchat("The hive has gained another burrowed larva! Use the Join As Xeno verb to take it.", src)
notify_ghosts(header = "Claim Xeno", message = "The Hive has gained another burrowed larva! Click to take it.", source = src, action = NOTIFY_JOIN_XENO, enter_link = "join_xeno")
if(surge_cooldown > 30 SECONDS) //mostly for sanity purposes
surge_cooldown = surge_cooldown - surge_incremental_reduction //ramps up over time
if(linked_hive.hijack_burrowed_left < 1)
Expand Down
3 changes: 2 additions & 1 deletion code/modules/cm_marines/overwatch.dm
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,8 @@
return

var/ob_name = lowertext(almayer_orbital_cannon.tray.warhead.name)
announce_dchat("\A [ob_name] targeting [A.name] has been fired!", T)
var/mutable_appearance/warhead_appearance = mutable_appearance(almayer_orbital_cannon.tray.warhead.icon, almayer_orbital_cannon.tray.warhead.icon_state)
notify_ghosts(header = "Bombardment Inbound", message = "\A [ob_name] targeting [A.name] has been fired!", source = T, alert_overlay = warhead_appearance, extra_large = TRUE)
message_admins(FONT_SIZE_HUGE("ALERT: [key_name(user)] fired an orbital bombardment in [A.name] for squad '[current_squad]' [ADMIN_JMP(T)]"))
log_attack("[key_name(user)] fired an orbital bombardment in [A.name] for squad '[current_squad]'")

Expand Down
130 changes: 130 additions & 0 deletions code/modules/maptext_alerts/screen_alerts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,133 @@

if(LAZYLEN(player.screen_texts))
player.screen_texts[1].play_to_client() // Theres more?
/**
* Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already
* category is a text string. Each mob may only have one alert per category; the previous one will be replaced
* path is a type path of the actual alert type to throw
* severity is an optional number that will be placed at the end of the icon_state for this alert
* For example, high pressure's icon_state is "highpressure" and can be serverity 1 or 2 to get "highpressure1" or "highpressure2"
* new_master is optional and sets the alert's icon state to "template" in the ui_style icons with the master as an overlay.
* Clicks are forwarded to master
* Override makes it so the alert is not replaced until cleared by a clear_alert with clear_override, and it's used for hallucinations.
*/
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE)
if(!category || QDELETED(src))
return

var/atom/movable/screen/alert/thealert
if(alerts[category])
thealert = alerts[category]
if(thealert.override_alerts)
return FALSE
if(new_master && new_master != thealert.master)
WARNING("[src] threw alert [category] with new_master [new_master] while already having that alert with master [thealert.master]")

clear_alert(category)
return .()
else if(thealert.type != type)
clear_alert(category)
return .()
else if(!severity || severity == thealert.severity)
if(thealert.timeout)
clear_alert(category)
return .()
else //no need to update
return FALSE
else
thealert = new type()
thealert.override_alerts = override
if(override)
thealert.timeout = null
thealert.owner = src

if(new_master)
var/old_layer = new_master.layer
var/old_plane = new_master.plane
new_master.layer = FLOAT_LAYER
new_master.plane = FLOAT_PLANE
thealert.overlays += new_master
new_master.layer = old_layer
new_master.plane = old_plane
thealert.icon_state = "template" // We'll set the icon to the client's ui pref in reorganize_alerts()
thealert.master = new_master
else
thealert.icon_state = "[initial(thealert.icon_state)][severity]"
thealert.severity = severity

alerts[category] = thealert
if(client && hud_used)
hud_used.reorganize_alerts()
thealert.transform = matrix(32, 6, MATRIX_TRANSLATE)
animate(thealert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)

if(thealert.timeout)
addtimer(CALLBACK(src, PROC_REF(alert_timeout), thealert, category), thealert.timeout)
thealert.timeout = world.time + thealert.timeout - world.tick_lag
return thealert

/mob/proc/alert_timeout(atom/movable/screen/alert/alert, category)
if(alert.timeout && alerts[category] == alert && world.time >= alert.timeout)
clear_alert(category)

// Proc to clear an existing alert.
/mob/proc/clear_alert(category, clear_override = FALSE)
var/atom/movable/screen/alert/alert = alerts[category]
if(!alert)
return FALSE
if(alert.override_alerts && !clear_override)
return FALSE

alerts -= category
if(client && hud_used)
hud_used.reorganize_alerts()
client.screen -= alert
qdel(alert)

/atom/movable/screen/alert
icon = 'icons/mob/screen_alert.dmi'
icon_state = "default"
name = "Alert"
desc = "Something seems to have gone wrong with this alert, so report this bug please"
mouse_opacity = MOUSE_OPACITY_ICON
/// If set to a number, this alert will clear itself after that many deciseconds
var/timeout = 0
var/severity = 0
var/alerttooltipstyle = ""
/// If it is overriding other alerts of the same type
var/override_alerts = FALSE
/// Alert owner
var/mob/owner

/atom/movable/screen/alert/MouseEntered(location,control,params)
. = ..()
if(!QDELETED(src))
openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle)

/atom/movable/screen/alert/notify_action
name = "Notification"
desc = "A new notification. You can enter it."
icon_state = "template"
timeout = 15 SECONDS
var/atom/target = null
var/action = NOTIFY_JUMP

/atom/movable/screen/alert/notify_action/Click()
var/mob/dead/observer/ghost_user = usr
if(!istype(ghost_user) || usr != owner)
return
if(!ghost_user.client)
return
if(!target)
return
switch(action)
if(NOTIFY_ATTACK)
target.attack_ghost(ghost_user)
if(NOTIFY_JUMP)
var/turf/gotten_turf = get_turf(target)
if(gotten_turf)
ghost_user.forceMove(gotten_turf)
if(NOTIFY_ORBIT)
ghost_user.ManualFollow(target)
if(NOTIFY_JOIN_XENO)
ghost_user.join_as_alien()
20 changes: 14 additions & 6 deletions code/modules/mob/dead/observer/observer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@
A.JumpToCoord(x, y, z)
if(href_list["joinresponseteam"])
JoinResponseTeam()
if(href_list["claim_freed"])
handle_joining_as_freed_mob(locate(href_list["claim_freed"]))
if(href_list["join_xeno"])
join_as_alien()

/mob/dead/observer/proc/set_huds_from_prefs()
if(!client || !client.prefs)
Expand Down Expand Up @@ -907,19 +911,23 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return

var/mob/living/L = freed_mob_choices[choice]
if(!L || !(WEAKREF(L) in GLOB.freed_mob_list))

handle_joining_as_freed_mob(L)

/mob/dead/proc/handle_joining_as_freed_mob(mob/living/freed_mob)
if(!freed_mob || !(WEAKREF(freed_mob) in GLOB.freed_mob_list))
return

if(!istype(L))
if(!istype(freed_mob))
return

if(QDELETED(L) || L.client)
GLOB.freed_mob_list -= WEAKREF(L)
if(QDELETED(freed_mob) || freed_mob.client)
GLOB.freed_mob_list -= WEAKREF(freed_mob)
to_chat(src, SPAN_WARNING("Something went wrong."))
return

GLOB.freed_mob_list -= WEAKREF(L)
M.mind.transfer_to(L, TRUE)
GLOB.freed_mob_list -= WEAKREF(freed_mob)
mind.transfer_to(freed_mob, TRUE)

/mob/dead/verb/join_as_hellhound()
set category = "Ghost.Join"
Expand Down
Loading

0 comments on commit 364fbf7

Please sign in to comment.