Files
CHOMPStation2/code/_onclick/hud/alert.dm
CHOMPStation2StaffMirrorBot 8d0febfbb6 [MIRROR] next grep, no spaces (#10548)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
2025-03-29 22:13:04 +01:00

489 lines
16 KiB
Plaintext

//A system to manage and display alerts on screen without needing you to do it yourself
//PUBLIC - call these wherever you want
/mob/proc/throw_alert(category, type, severity, obj/new_master)
/** 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
*/
if(!category)
return
var/obj/screen/alert/alert
if(alerts[category])
alert = alerts[category]
if(new_master && new_master != alert.master)
WARNING("[src] threw alert [category] with new_master [new_master] while already having that alert with master [alert.master]")
clear_alert(category)
return .()
else if(alert.type != type)
clear_alert(category)
return .()
else if(!severity || severity == alert.severity)
if(alert.timeout)
clear_alert(category)
return .()
else //no need to update
return 0
else
alert = new type
if(new_master)
alert.icon_state = "itembased"
var/image/I = image(icon = new_master.icon, icon_state = new_master.icon_state, dir = SOUTH)
I.plane = PLANE_PLAYER_HUD_ABOVE
I.color = new_master.color
alert.add_overlay(I)
alert.master = new_master
else
alert.icon_state = "[initial(alert.icon_state)][severity]"
alert.severity = severity
alerts[category] = alert
if(client && hud_used)
hud_used.reorganize_alerts()
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
animate(alert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
if(alert.timeout)
addtimer(CALLBACK(src, PROC_REF(alert_timeout), alert, category), alert.timeout)
alert.timeout = world.time + alert.timeout - world.tick_lag
return alert
/mob/proc/alert_timeout(obj/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)
var/obj/screen/alert/alert = alerts[category]
if(!alert)
return 0
alerts -= category
if(client && hud_used)
hud_used.reorganize_alerts()
client.screen -= alert
qdel(alert)
/obj/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 = 1
var/timeout = 0 //If set to a number, this alert will clear itself after that many deciseconds
var/severity = 0
var/alerttooltipstyle = ""
var/no_underlay // Don't underlay the UI style's blank template icon under this
/obj/screen/alert/MouseEntered(location,control,params)
openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle)
/obj/screen/alert/MouseExited()
closeToolTip(usr)
//Gas alerts
/obj/screen/alert/not_enough_oxy
name = "Choking (No O2)"
desc = "You're not getting enough oxygen. Find some good air before you pass out! \
The box in your backpack has an oxygen tank and breath mask in it."
icon_state = "not_enough_oxy"
/obj/screen/alert/too_much_oxy
name = "Choking (O2)"
desc = "There's too much oxygen in the air, and you're breathing it in! Find some good air before you pass out!"
icon_state = "too_much_oxy"
/obj/screen/alert/not_enough_nitro
name = "Choking (No N)"
desc = "You're not getting enough nitrogen. Find some good air before you pass out!"
icon_state = "not_enough_nitro"
/obj/screen/alert/too_much_nitro
name = "Choking (N)"
desc = "There's too much nitrogen in the air, and you're breathing it in! Find some good air before you pass out!"
icon_state = "too_much_nitro"
/obj/screen/alert/not_enough_co2
name = "Choking (No CO2)"
desc = "You're not getting enough carbon dioxide. Find some good air before you pass out!"
icon_state = "not_enough_co2"
/obj/screen/alert/too_much_co2
name = "Choking (CO2)"
desc = "There's too much carbon dioxide in the air, and you're breathing it in! Find some good air before you pass out!"
icon_state = "too_much_co2"
/obj/screen/alert/too_much_co2/plant
name = "Livin' the good life"
desc = "There's so much carbon dioxide in the air, you're in fucking heaven. Watch out for passed out fleshies, though."
icon_state = "too_much_co2"
/obj/screen/alert/not_enough_tox
name = "Choking (No Phoron)"
desc = "You're not getting enough phoron. Find some good air before you pass out!"
icon_state = "not_enough_tox"
/obj/screen/alert/tox_in_air // CHOMP EDIT : Oxygen is toxic to phoron breathers and nitrogen breathers. I'm tired of seeing "You're choking on phoron!" when it's not phoron.
name = "Choking (Toxic)" // CHOMP EDIT
desc = "There's a dangerous toxin in the air and you're breathing it in. Find some fresh air. \
Your emergency supply kit should have an air tank and gas mask in it!" // CHOMP EDIT
icon_state = "too_much_tox"
/obj/screen/alert/not_enough_fuel
name = "Choking (No Volatile fuel)"
desc = "You're not getting enough volatile fuel. Find some good air before you pass out!"
icon_state = "not_enough_tox"
/obj/screen/alert/not_enough_n2o
name = "Choking (No Sleeping Gas)"
desc = "You're not getting enough sleeping gas. Find some good air before you pass out!"
icon_state = "not_enough_tox"
/obj/screen/alert/not_enough_atmos
name = "Choking (No Breath)"
desc = "The atmosphere around you lacks any form of breathable air! Find some good air before you pass out!"
icon_state = "not_enough_oxy"
//End gas alerts
/obj/screen/alert/fat
name = "Full"
desc = "You've eaten more than you can handle, maybe you should slow down?"
icon_state = "fat"
/obj/screen/alert/fat/vampire
desc = "You've had more than enough blood, for now."
icon_state = "v_fat"
/obj/screen/alert/fat/synth
desc = "Your battery is full! Don't overvolt it."
icon_state = "c_fat"
/obj/screen/alert/hungry
name = "Hungry"
desc = "Some food would be good right about now."
icon_state = "hungry"
/obj/screen/alert/hungry/vampire
desc = "You could go for a bite right now..."
icon_state = "v_hungry"
/obj/screen/alert/hungry/synth
desc = "Battery's running a bit low, could use a topoff."
icon_state = "c_hungry"
/obj/screen/alert/starving
name = "Very Hungry"
desc = "You're starving. You barely have enough energy to move around."
icon_state = "starving"
/obj/screen/alert/starving/vampire
desc = "You *need* blood; go rip out someone's throat already!"
icon_state = "v_starving"
/obj/screen/alert/starving/synth
desc = "Your battery is about to die! Charge it ASAP!"
icon_state = "c_starving"
/obj/screen/alert/warm
name = "Too Warm"
desc = "You're uncomfortably warm. Take off some clothes or tweak the thermostat a few degrees cooler."
icon_state = "mildhot"
/obj/screen/alert/hot
name = "Too Hot"
desc = "You're flaming hot! Get somewhere cooler and take off any insulating clothing like a fire suit."
icon_state = "hot"
/obj/screen/alert/hot/robot
desc = "The air around you is too hot for a humanoid. Be careful to avoid exposing them to this enviroment."
/obj/screen/alert/chilly
name = "Too Chilly"
desc = "You're uncomfortably cold. Rug up or tweak the thermostat a few degrees higher."
icon_state = "mildcold"
/obj/screen/alert/cold
name = "Too Cold"
desc = "You're freezing cold! Get somewhere warmer and take off any insulating clothing like a space suit."
icon_state = "cold"
/obj/screen/alert/cold/robot
desc = "The air around you is too cold for a humanoid. Be careful to avoid exposing them to this enviroment."
/obj/screen/alert/lowpressure
name = "Low Pressure"
desc = "The air around you is hazardously thin. A space suit would protect you."
icon_state = "lowpressure"
/obj/screen/alert/highpressure
name = "High Pressure"
desc = "The air around you is hazardously thick. A fire suit would protect you."
icon_state = "highpressure"
/obj/screen/alert/blind
name = "Blind"
desc = "You can't see! This may be caused by a genetic defect, eye trauma, being unconscious, \
or something covering your eyes."
icon_state = "blind"
/obj/screen/alert/stunned
name = "Stunned"
desc = "You're temporarily stunned! You'll have trouble moving or performing actions, but it should clear up on it's own."
icon_state = "stun"
/obj/screen/alert/paralyzed
name = "Paralyzed"
desc = "You're paralyzed! This could be due to drugs or serious injury. You'll be unable to move or perform actions."
icon_state = "paralysis"
/obj/screen/alert/weakened
name = "Weakened"
desc = "You're weakened! This could be a temporary issue due to injury or the result of drugs or drinking."
icon_state = "weaken"
/obj/screen/alert/confused
name = "Confused"
desc = "You're confused, and may stumble into things! This may be from concussive effects, drugs, or dizzyness. Walking will help reduce incidents."
icon_state = "confused"
/obj/screen/alert/high
name = "High"
desc = "Whoa, you're tripping balls!"
icon_state = "high"
/obj/screen/alert/embeddedobject
name = "Embedded Object"
desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \
If you're feeling frisky, right click on yourself and select \"Remove embedded object\" to pull the object out."
icon_state = "embeddedobject"
/obj/screen/alert/embeddedobject/Click()
if(isliving(usr))
var/mob/living/carbon/human/M = usr
return M.help_shake_act(M)
/obj/screen/alert/asleep
name = "Asleep"
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
/obj/screen/alert/weightless
name = "Weightless"
desc = "Gravity has ceased affecting you, and you're floating around aimlessly. You'll need something large and heavy, like a \
wall or lattice, to push yourself off if you want to move. A jetpack would enable free range of motion. A pair of \
magboots would let you walk around normally on the floor. Barring those, you can throw things, use a fire extinguisher, \
or shoot a gun to move around via Newton's 3rd Law of Motion."
icon_state = "weightless"
/obj/screen/alert/fire
name = "On Fire"
desc = "You're on fire. Stop, drop and roll to put the fire out or move to a vacuum area."
icon_state = "fire"
/obj/screen/alert/fire/Click()
if(isliving(usr))
var/mob/living/L = usr
return L.resist()
//ALIENS
/obj/screen/alert/alien_tox
name = "Phoron"
desc = "There's flammable phoron in the air. If it lights up, you'll be toast."
icon_state = "alien_tox"
alerttooltipstyle = "alien"
/obj/screen/alert/alien_fire
// This alert is temporarily gonna be thrown for all hot air but one day it will be used for literally being on fire
name = "Too Hot"
desc = "It's too hot! Flee to space or at least away from the flames. Standing on weeds will heal you."
icon_state = "alien_fire"
alerttooltipstyle = "alien"
/obj/screen/alert/alien_vulnerable
name = "Severed Matriarchy"
desc = "Your queen has been killed, you will suffer movement penalties and loss of hivemind. A new queen cannot be made until you recover."
icon_state = "alien_noqueen"
alerttooltipstyle = "alien"
//BLOBS
/obj/screen/alert/nofactory
name = "No Factory"
desc = "You have no factory, and are slowly dying!"
icon_state = "blobbernaut_nofactory"
alerttooltipstyle = "blob"
//SILICONS
/obj/screen/alert/nocell
name = "Missing Power Cell"
desc = "Unit has no power cell. No modules available until a power cell is reinstalled. Robotics may provide assistance."
icon_state = "nocell"
/obj/screen/alert/emptycell
name = "Out of Power"
desc = "Unit's power cell has no charge remaining. No modules available until power cell is recharged. \
Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite."
icon_state = "emptycell"
/obj/screen/alert/lowcell
name = "Low Charge"
desc = "Unit's power cell is running low. Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite."
icon_state = "lowcell"
//Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg
/obj/screen/alert/hacked
name = "Hacked"
desc = "Hazardous non-standard equipment detected. Please ensure any usage of this equipment is in line with unit's laws, if any."
icon_state = "hacked"
no_underlay = TRUE
/obj/screen/alert/locked
name = "Locked Down"
desc = "Unit has been remotely locked down. Usage of a Robotics Control Console like the one in the " + JOB_RESEARCH_DIRECTOR + "'s \
office by your AI master or any qualified human may resolve this matter. Robotics may provide further assistance if necessary."
icon_state = "locked"
no_underlay = TRUE
/obj/screen/alert/newlaw
name = "Law Update"
desc = "Laws have potentially been uploaded to or removed from this unit. Please be aware of any changes \
so as to remain in compliance with the most up-to-date laws."
icon_state = "newlaw"
timeout = 300
no_underlay = TRUE
//MECHS
/obj/screen/alert/low_mech_integrity
name = "Mech Damaged"
desc = "Mech integrity is low."
icon_state = "low_mech_integrity"
//GHOSTS
//TODO: expand this system to replace the pollCandidates/CheckAntagonist/"choose quickly"/etc Yes/No messages
/obj/screen/alert/notify_cloning
name = "Revival"
desc = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!"
icon_state = "template"
timeout = 300
/obj/screen/alert/notify_cloning/Click()
if(!usr || !usr.client) return
var/mob/observer/dead/G = usr
G.reenter_corpse()
// /obj/screen/alert/notify_jump
// name = "Body created"
// desc = "A body was created. You can enter it."
// icon_state = "template"
// timeout = 300
// var/atom/jump_target = null
// var/attack_not_jump = null
// /obj/screen/alert/notify_jump/Click()
// if(!usr || !usr.client) return
// if(!jump_target) return
// var/mob/dead/observer/G = usr
// if(!istype(G)) return
// if(attack_not_jump)
// jump_target.attack_ghost(G)
// else
// var/turf/T = get_turf(jump_target)
// if(T && isturf(T))
// G.loc = T
//OBJECT-BASED
/obj/screen/alert/restrained/buckled
name = "Buckled"
desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed."
/obj/screen/alert/restrained/handcuffed
name = "Handcuffed"
desc = "You're handcuffed and can't act. If anyone drags you, you won't be able to move. Click the alert to free yourself."
/obj/screen/alert/restrained/legcuffed
name = "Legcuffed"
desc = "You're legcuffed, which slows you down considerably. Click the alert to free yourself."
/obj/screen/alert/restrained/Click()
if(isliving(usr))
var/mob/living/L = usr
return L.resist()
// PRIVATE = only edit, use, or override these if you're editing the system as a whole
// Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
/datum/hud/proc/reorganize_alerts()
var/list/alerts = mymob.alerts
if(!hud_shown)
for(var/i = 1, i <= alerts.len, i++)
mymob.client.screen -= alerts[alerts[i]]
return 1
for(var/i = 1, i <= alerts.len, i++)
var/obj/screen/alert/alert = alerts[alerts[i]]
if(alert.icon_state in cached_icon_states(ui_style))
alert.icon = ui_style
else if(!alert.no_underlay)
var/image/I = image(icon = ui_style, icon_state = "template")
I.color = ui_color
I.alpha = ui_alpha
alert.underlays = list(I)
switch(i)
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 = .
mymob?.client?.screen |= alert
return 1
/mob
var/list/alerts = list() // contains /obj/screen/alert only // On /mob so clientless mobs will throw alerts properly
/obj/screen/alert/Click(location, control, params)
if(!usr || !usr.client)
return
var/paramslist = params2list(params)
if(paramslist["shift"]) // screen objects don't do the normal Click() stuff so we'll cheat
to_chat(usr,span_boldnotice(name) + " - " + span_info(desc))
return
if(master)
return usr.client.Click(master, location, control, params)
..() // VOREStation Edit: Pass through to click_vr
/obj/screen/alert/Destroy()
..()
severity = 0
master = null
screen_loc = ""
return QDEL_HINT_QUEUE