Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

notify ghosts #4241

Merged
merged 10 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -862,7 +862,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