diff --git a/aurorastation.dme b/aurorastation.dme
index 1ef9a3bc63a..3250b7fbe0a 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -304,6 +304,7 @@
#include "code\_onclick\hud\ability_screen_objects.dm"
#include "code\_onclick\hud\action.dm"
#include "code\_onclick\hud\ai.dm"
+#include "code\_onclick\hud\alert.dm"
#include "code\_onclick\hud\borer_hud.dm"
#include "code\_onclick\hud\captive_brain_hud.dm"
#include "code\_onclick\hud\fullscreen.dm"
@@ -2715,6 +2716,7 @@
#include "code\modules\mob\living\carbon\carbon_defines.dm"
#include "code\modules\mob\living\carbon\diona_base.dm"
#include "code\modules\mob\living\carbon\give.dm"
+#include "code\modules\mob\living\carbon\inventory.dm"
#include "code\modules\mob\living\carbon\resist.dm"
#include "code\modules\mob\living\carbon\taste.dm"
#include "code\modules\mob\living\carbon\alien\alien.dm"
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 1821baa64fa..8b7c42706b3 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -10,3 +10,11 @@
#define NO_HUD 0
#define SEC_HUD 1
#define MED_HUD 2
+
+// Notification action types
+#define NOTIFY_JUMP "jump"
+#define NOTIFY_ATTACK "attack"
+#define NOTIFY_ORBIT "orbit"
+
+#define ALERT_BUCKLED "buckled"
+#define ALERT_FIRE "fire"
diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm
index d11db3059f1..3ccaa9294d5 100644
--- a/code/__DEFINES/span.dm
+++ b/code/__DEFINES/span.dm
@@ -39,6 +39,9 @@
#define SPAN_LANGCHAT(X) "[X]"
+#define SPAN_BOLDNOTICE(str) ("" + str + "")
+#define SPAN_BOLDWARNING(X) "[X]"
+
/*
#####################
Font sizes
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 300e3a6f551..9ec19e5f057 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -97,6 +97,13 @@
#define ui_health_east_template "EAST-1:" // ditto
#define ui_internal "EAST-1:28,CENTER+1:17"
+//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"
+
//borgs
#define ui_borg_health "EAST-1:28,CENTER-1:13" //borgs have the health display where humans have the pressure damage indicator.
#define ui_alien_health "EAST-1:28,CENTER-1:13" //aliens have the health display where humans have the pressure damage indicator.
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
new file mode 100644
index 00000000000..6546a7dd43d
--- /dev/null
+++ b/code/_onclick/hud/alert.dm
@@ -0,0 +1,265 @@
+//A system to manage and display alerts on screen without needing you to do it yourself
+
+//PUBLIC - call these wherever you want
+
+/**
+ * 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
+ thealert.alert_post_setup(src)
+ 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.remove_from_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/MouseExited(location, control, params)
+ . = ..()
+ closeToolTip(usr)
+
+/// Called by throw_alert(), passes the mob throw_alert() is being called on as an arg. Parent proc, does nothing.
+/atom/movable/screen/alert/proc/alert_post_setup(mob/user)
+ SIGNAL_HANDLER
+ return
+
+/atom/movable/screen/alert/notify_action
+ name = "Notification"
+ desc = "A new notification."
+ icon_state = "template"
+ timeout = 15 SECONDS
+ var/datum/weakref/target_ref
+ var/action = NOTIFY_JUMP
+
+/atom/movable/screen/alert/notify_action/Click()
+ . = ..()
+ if(!usr || !usr.client || usr != owner)
+ return
+ var/atom/target = target_ref?.resolve()
+ if(!target)
+ return
+ var/mob/abstract/ghost/ghost_user = usr
+ if(!istype(ghost_user))
+ return
+ switch(action)
+ if(NOTIFY_ATTACK)
+ target.attack_ghost(ghost_user)
+ if(NOTIFY_JUMP)
+ var/turf/gotten_turf = get_turf(target)
+ if(gotten_turf && isturf(gotten_turf))
+ ghost_user.abstract_move(gotten_turf)
+ //if(NOTIFY_ORBIT)
+ // ghost_user.do_observe(target)
+
+/atom/movable/screen/alert/buckled
+ name = "Buckled"
+ desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed."
+ icon_state = ALERT_BUCKLED
+
+/atom/movable/screen/alert/buckled/Click(location, control, params)
+ . = ..()
+ var/mob/living/living_mob = usr
+ if(!istype(living_mob) || living_mob != owner)
+ return
+ living_mob.execute_resist()
+
+/atom/movable/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."
+
+/atom/movable/screen/alert/restrained/legcuffed
+ name = "Legcuffed"
+ desc = "You're legcuffed, which slows you down considerably. Click the alert to free yourself."
+
+/atom/movable/screen/alert/restrained/Click(location, control, params)
+ . = ..()
+ var/mob/living/carbon/carbon_mob = usr
+ if(!istype(carbon_mob) || carbon_mob != owner)
+ return
+ carbon_mob.execute_resist()
+
+/// Gives the player the option to succumb while in critical condition (without relying on verbs)
+/atom/movable/screen/alert/succumb
+ name = "Succumb"
+ desc = "Shuffle off this mortal coil."
+ icon_state = "succumb"
+
+/atom/movable/screen/alert/succumb/Click()
+ if (isobserver(usr))
+ return
+
+ var/mob/living/living_owner = owner
+ if(!istype(living_owner))
+ return
+
+ living_owner.succumb()
+
+/atom/movable/screen/alert/fire
+ name = "On Fire!"
+ desc = "You are currently on fire! Click to Stop, drop and roll to put the fire out or move to a vacuum area."
+ icon_state = "fire"
+
+/atom/movable/screen/alert/fire/Click()
+ if (isobserver(usr))
+ return
+
+ var/mob/living/living_owner = owner
+ if(!istype(living_owner))
+ return
+
+ living_owner.execute_resist()
+
+// PRIVATE = only edit, use, or override these if you're editing the system as a whole
+
+// Re-render all alerts - also called in /mob/verb/button_pressed_F12() because it's needed there
+/datum/hud/proc/reorganize_alerts()
+ var/mob/screenmob = mymob
+ if(!screenmob.client)
+ return
+ var/list/alerts = mymob.alerts
+ if(!hud_shown)
+ for(var/i = 1, i <= length(alerts), i++)
+ screenmob.client.screen -= alerts[alerts[i]]
+ return TRUE
+ for(var/i = 1, i <= length(alerts), i++)
+ var/atom/movable/screen/alert/alert = alerts[alerts[i]]
+ if(alert.icon_state != "default" && alert.icon_state != "template")
+ var/mutable_appearance/alert_underlay = mutable_appearance(ui_style2icon(mymob.client.prefs.UI_style), "template", FLOAT_LAYER, FLOAT_PLANE, alpha = mymob.client.prefs.UI_style_alpha)
+ alert_underlay.color = mymob.client.prefs.UI_style_color
+ alert.underlays += alert_underlay
+ alert.alpha = mymob.client.prefs.UI_style_alpha
+ else if (alert.icon_state == "default")
+ alert.alpha = mymob.client.prefs.UI_style_alpha
+ else if (alert.icon_state == "template")
+ alert.icon = ui_style2icon(mymob.client.prefs.UI_style)
+ alert.color = mymob.client.prefs.UI_style_color
+ alert.alpha = mymob.client.prefs.UI_style_alpha
+ 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 = .
+ screenmob.client.screen |= alert
+ return TRUE
+
+/atom/movable/screen/alert/Click(location, control, params)
+ if(!usr || !usr.client)
+ return FALSE
+ var/list/modifiers = params2list(params)
+ if(LAZYACCESS(modifiers, SHIFT_CLICK)) // screen objects don't do the normal Click() stuff so we'll cheat
+ to_chat(usr, SPAN_BOLDNOTICE("[name] - [desc]"))
+ return FALSE
+ if(usr != owner)
+ return
+ if(master)
+ return usr.client.Click(master, location, control, params)
+
+ return TRUE
+
+/atom/movable/screen/alert/Destroy()
+ . = ..()
+ severity = 0
+ master = null
+ owner = null
+ screen_loc = ""
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index ee8d4f5ba36..497394a6480 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -426,6 +426,7 @@ GLOBAL_LIST(global_huds)
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
+ hud_used.reorganize_alerts()
update_action_buttons()
//Similar to button_pressed_F12() but keeps zone_sel, gun_setting_icon, and healths.
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 9534e7dbe43..80fead9f6ff 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -251,13 +251,6 @@
mymob.toxin.screen_loc = ui_temp
hud_elements |= mymob.toxin
- mymob.fire = new /atom/movable/screen()
- mymob.fire.icon = ui_style
- mymob.fire.icon_state = "fire0"
- mymob.fire.name = "fire"
- mymob.fire.screen_loc = ui_fire
- hud_elements |= mymob.fire
-
mymob.paralysis_indicator = new /atom/movable/screen/paralysis()
mymob.paralysis_indicator.icon = 'icons/mob/status_indicators.dmi'
mymob.paralysis_indicator.icon_state = "paralysis0"
diff --git a/code/_onclick/hud/nymph_hud.dm b/code/_onclick/hud/nymph_hud.dm
index aafecd0b248..706d0f71511 100644
--- a/code/_onclick/hud/nymph_hud.dm
+++ b/code/_onclick/hud/nymph_hud.dm
@@ -21,12 +21,6 @@
mymob.healths.name = "health"
mymob.healths.screen_loc = ui_alien_health
- mymob.fire = new /atom/movable/screen()
- mymob.fire.icon = 'icons/mob/screen/diona_nymph.dmi'
- mymob.fire.icon_state = "fire0"
- mymob.fire.name = "fire"
- mymob.fire.screen_loc = ui_fire
-
mymob.client.screen = null
- mymob.client.screen += list(mymob.healths, mymob.fire)
+ mymob.client.screen += list(mymob.healths)
mymob.client.screen += src.adding + src.other
diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm
index 44d95903a65..685c3e95195 100644
--- a/code/_onclick/hud/other_mobs.dm
+++ b/code/_onclick/hud/other_mobs.dm
@@ -112,11 +112,6 @@
constructtype = "harvester"
if(constructtype)
- mymob.fire = new /atom/movable/screen()
- mymob.fire.icon = 'icons/mob/screen/construct.dmi'
- mymob.fire.icon_state = "fire0"
- mymob.fire.name = "fire"
- mymob.fire.screen_loc = ui_construct_fire
mymob.healths = new /atom/movable/screen()
mymob.healths.icon = 'icons/mob/screen/construct.dmi'
@@ -144,4 +139,4 @@
mymob.client.screen = null
- mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged)
+ mymob.client.screen += list(mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged)
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index aa5db102b9a..ddf8a812f84 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -50,6 +50,7 @@
buckling_mob.set_dir(buckle_dir ? buckle_dir : dir)
buckling_mob.facing_dir = null
buckling_mob.update_canmove()
+ buckling_mob.throw_alert(ALERT_BUCKLED, /atom/movable/screen/alert/buckled)
else
buckling_atom.anchored = TRUE
@@ -72,6 +73,7 @@
if(istype(MA, /mob/living))
var/mob/living/M = MA
M.update_canmove()
+ M.clear_alert(ALERT_BUCKLED)
post_buckle(.)
/obj/proc/post_buckle(atom/movable/MA)
diff --git a/code/game/objects/items/tools/tools.dm b/code/game/objects/items/tools/tools.dm
index 7f91d033ba8..bda3042b8e3 100644
--- a/code/game/objects/items/tools/tools.dm
+++ b/code/game/objects/items/tools/tools.dm
@@ -195,9 +195,7 @@
SPAN_NOTICE("You cut \the [C]'s restraints with \the [src]!"),\
SPAN_NOTICE("You hear cable being cut."))
C.handcuffed = null
- if(C.buckled_to?.buckle_require_restraints)
- C.buckled_to.unbuckle()
- C.update_inv_handcuffed()
+ C.handcuff_update()
return
else
..()
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index 02dc6f421e0..ac1cbaafa07 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -97,10 +97,6 @@
user.do_attack_animation(H)
user.visible_message(SPAN_DANGER("\The [user] has put [cuff_type] on \the [H]!"))
- if(!legcuff)
- target.drop_r_hand()
- target.drop_l_hand()
-
// Apply cuffs.
var/obj/item/handcuffs/cuffs = src
if(dispenser)
@@ -112,10 +108,10 @@
if(!legcuff)
target.handcuffed = cuffs
- target.update_inv_handcuffed()
+ target.handcuff_update()
else
target.legcuffed = cuffs
- target.update_inv_legcuffed()
+ target.legcuff_update()
return TRUE
/mob/living/carbon/human/RestrainedClickOn(var/atom/A)
diff --git a/code/game/objects/items/weapons/implants/implants/freedom.dm b/code/game/objects/items/weapons/implants/implants/freedom.dm
index b37ad6f2833..3d3749febea 100644
--- a/code/game/objects/items/weapons/implants/implants/freedom.dm
+++ b/code/game/objects/items/weapons/implants/implants/freedom.dm
@@ -29,9 +29,7 @@
if(C_imp_in.handcuffed)
var/obj/item/W = C_imp_in.handcuffed
C_imp_in.handcuffed = null
- if(C_imp_in.buckled_to && C_imp_in.buckled_to.buckle_require_restraints)
- C_imp_in.buckled_to.unbuckle()
- C_imp_in.update_inv_handcuffed()
+ C_imp_in.handcuff_update()
if(C_imp_in.client)
C_imp_in.client.screen -= W
if(W)
@@ -42,7 +40,7 @@
if(C_imp_in.legcuffed)
var/obj/item/W = C_imp_in.legcuffed
C_imp_in.legcuffed = null
- C_imp_in.update_inv_legcuffed()
+ C_imp_in.legcuff_update()
if(C_imp_in.client)
C_imp_in.client.screen -= W
if(W)
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 4f2910c4b85..3a92e77e5d9 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -148,11 +148,8 @@
if(environment.temperature > (T0C+66))
adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing.
- if (fire) fire.icon_state = "fire2"
if(prob(20))
to_chat(src, SPAN_DANGER("You feel a searing heat!"))
- else
- if (fire) fire.icon_state = "fire0"
/mob/living/carbon/alien/handle_fire(var/seconds_per_tick, var/datum/gas_mixture/environment)
if(..())
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 1fc9a1c9628..ad677045d20 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -376,23 +376,6 @@
return 1
return
-/mob/living/carbon/u_equip(obj/item/W as obj)
- if(!W) return 0
-
- else if (W == handcuffed)
- handcuffed = null
- update_inv_handcuffed()
- if(buckled_to && buckled_to.buckle_require_restraints)
- buckled_to.unbuckle()
-
- else if (W == legcuffed)
- legcuffed = null
- update_inv_legcuffed()
- else
- ..()
-
- return
-
// output for machines^ ^^^^^^^output for people^^^^^^^^^
/mob/living/carbon/verb/mob_sleep()
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 8f97826f736..f7f8f743434 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -215,12 +215,10 @@ This saves us from having to call add_fingerprint() any time something is put in
update_inv_back()
else if (W == handcuffed)
handcuffed = null
- if(buckled_to && buckled_to.buckle_require_restraints)
- buckled_to.unbuckle()
- update_inv_handcuffed()
+ handcuff_update()
else if (W == legcuffed)
legcuffed = null
- update_inv_legcuffed()
+ legcuff_update()
else if (W == r_hand)
r_hand = null
update_inv_r_hand()
@@ -265,11 +263,11 @@ This saves us from having to call add_fingerprint() any time something is put in
update_inv_wear_mask(redraw_mob)
if(slot_handcuffed)
src.handcuffed = W
- update_inv_handcuffed(redraw_mob)
+ handcuff_update()
if(slot_legcuffed)
src.legcuffed = W
W.on_equipped(src, slot, assisted_equip)
- update_inv_legcuffed(redraw_mob)
+ legcuff_update()
if(slot_l_hand)
src.l_hand = W
W.on_equipped(src, slot, assisted_equip)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 01db3e1e224..199b6acda06 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1062,12 +1062,6 @@
if (oxygen.icon_state != new_oxy)
oxygen.icon_state = new_oxy
- if(fire)
- //fire_alert is either 0 if no alert, 1 for cold and 2 for heat.
- var/new_fire = fire_alert ? "fire[fire_alert]" : "fire0"
- if (fire.icon_state != new_fire)
- fire.icon_state = new_fire
-
if(bodytemp)
var/new_temp
if (!species)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index ac7726a7101..c4379c2bdd6 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -1476,8 +1476,10 @@ There are several things that need to be remembered:
if(!on_fire)
set_light_on(FALSE)
+ clear_alert(ALERT_FIRE)
else
set_light_on(TRUE)
+ throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
var/image/fire_image_lower = on_fire ? image(species.onfire_overlay, "lower", layer = FIRE_LAYER_LOWER) : null
var/image/fire_image_upper = on_fire ? image(species.onfire_overlay, "upper", layer = FIRE_LAYER_UPPER) : null
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
new file mode 100644
index 00000000000..faf9ee91f53
--- /dev/null
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -0,0 +1,33 @@
+/mob/living/carbon/proc/handcuff_update()
+ if(handcuffed)
+ drop_r_hand()
+ drop_l_hand()
+ stop_pulling()
+ throw_alert("Handcuffed", /atom/movable/screen/alert/restrained/handcuffed, new_master = handcuffed)
+ else
+ clear_alert("Handcuffed")
+ if(buckled_to && buckled_to.buckle_require_restraints)
+ buckled_to.unbuckle()
+ update_inv_handcuffed()
+
+/mob/living/carbon/proc/legcuff_update()
+ if(legcuffed)
+ throw_alert("Legcuffed", /atom/movable/screen/alert/restrained/legcuffed, new_master = legcuffed)
+ else
+ clear_alert("Legcuffed")
+ update_inv_legcuffed()
+
+/mob/living/carbon/u_equip(obj/item/W as obj)
+ if(!W) return 0
+
+ else if (W == handcuffed)
+ handcuffed = null
+ handcuff_update()
+
+ else if (W == legcuffed)
+ legcuffed = null
+ legcuff_update()
+ else
+ ..()
+
+ return
diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm
index 43e0a4b66a5..f058877e973 100644
--- a/code/modules/mob/living/carbon/resist.dm
+++ b/code/modules/mob/living/carbon/resist.dm
@@ -171,7 +171,7 @@
drop_from_inventory(legcuffed)
legcuffed = null
- update_inv_legcuffed()
+ legcuff_update()
/mob/living/carbon/proc/can_break_cuffs()
if((mutations & HULK))
@@ -206,9 +206,7 @@
qdel(handcuffed)
handcuffed = null
- if(buckled_to)
- buckled_to.unbuckle()
- update_inv_handcuffed()
+ handcuff_update()
/mob/living/carbon/proc/break_legcuffs()
to_chat(src, SPAN_WARNING("You attempt to break your legcuffs. (This will take around 5 seconds and you need to stand still)"))
@@ -227,7 +225,7 @@
qdel(legcuffed)
legcuffed = null
- update_inv_legcuffed()
+ legcuff_update()
/mob/living/carbon/human/can_break_cuffs()
if(species.can_shred(src,1))
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 71eb8f9ddad..80484780578 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -332,6 +332,9 @@
if(on_fire)
AddOverlays(image("icon" = 'icons/mob/burning/burning_generic.dmi', "icon_state" = "upper"))
AddOverlays(image("icon" = 'icons/mob/burning/burning_generic.dmi', "icon_state" = "lower"))
+ throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
+ else
+ clear_alert(ALERT_FIRE)
/mob/living/silicon/robot/fire_act(exposed_temperature, exposed_volume)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm b/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm
index 1c81dfe06c3..de3a350c9de 100644
--- a/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm
+++ b/code/modules/mob/living/simple_animal/constructs/constructs/cult_construct.dm
@@ -135,10 +135,6 @@
. = ..()
if(.)
var/newstate
- if(fire)
- newstate = fire_alert ? "fire1" : "fire0"
- if(fire.icon_state != newstate)
- fire.icon_state = newstate
if(pullin)
newstate = pulling ? "pull1" : "pull0"
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 914eda0b8f9..2602433afcb 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -1072,6 +1072,9 @@
AddOverlays(upper_fire_emissive)
AddOverlays(lower_fire_overlay)
AddOverlays(lower_fire_emissive)
+ throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
+ else
+ clear_alert(ALERT_FIRE)
/mob/living/simple_animal/get_resist_power()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c8bb637cc03..762cf5660c4 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -70,7 +70,6 @@
i_select = null
m_select = null
toxin = null
- fire = null
bodytemp = null
healths = null
throw_icon = null
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index d0fba847767..2c8852b6ba3 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -37,7 +37,6 @@
var/atom/movable/screen/i_select = null
var/atom/movable/screen/m_select = null
var/atom/movable/screen/toxin = null
- var/atom/movable/screen/fire = null
var/atom/movable/screen/bodytemp = null
var/atom/movable/screen/healths = null
var/atom/movable/screen/throw_icon = null
@@ -168,6 +167,8 @@
var/obj/item/storage/s_active = null//Carbon
var/obj/item/clothing/mask/wear_mask = null//Carbon
+ /// contains [/atom/movable/screen/alert only] // On /mob so clientless mobs will throw alerts properly
+ var/list/alerts = list()
var/list/screens = list()
var/seer = 0 //for cult//Carbon, probably Human
diff --git a/code/stylesheet.dm b/code/stylesheet.dm
index a684fb1890c..9958c4cfba9 100644
--- a/code/stylesheet.dm
+++ b/code/stylesheet.dm
@@ -92,9 +92,11 @@ h1.alert, h2.alert {color: #000000;}
.danger {color: #ff0000; font-weight: bold;}
.warning {color: #ff0000; font-style: italic;}
+.boldwarning {color: #ff0000; font-weight: bold; font-style: italic;}
.rose {color: #ff5050;}
.info {color: #0000CC;}
.notice {color: #000099;}
+.boldnotice {color: #000099; font-weight: bold;}
.hear {color: #000099; font-style: italic;}
.subtle {color: #000099; font-size: 75%; font-style: italic;}
.alium {color: #00ff00;}
diff --git a/html/changelogs/GeneralCamo - Screen Alerts.yml b/html/changelogs/GeneralCamo - Screen Alerts.yml
new file mode 100644
index 00000000000..97e3c796b15
--- /dev/null
+++ b/html/changelogs/GeneralCamo - Screen Alerts.yml
@@ -0,0 +1,59 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# - (fixes bugs)
+# wip
+# - (work in progress)
+# qol
+# - (quality of life)
+# soundadd
+# - (adds a sound)
+# sounddel
+# - (removes a sound)
+# rscadd
+# - (adds a feature)
+# rscdel
+# - (removes a feature)
+# imageadd
+# - (adds an image or sprite)
+# imagedel
+# - (removes an image or sprite)
+# spellcheck
+# - (fixes spelling or grammar)
+# experiment
+# - (experimental change)
+# balance
+# - (balance changes)
+# code_imp
+# - (misc internal code change)
+# refactor
+# - (refactors code)
+# config
+# - (makes a change to the config files)
+# admin
+# - (makes changes to administrator tools)
+# server
+# - (miscellaneous changes to server)
+#################################
+
+# Your name.
+author: GeneralCamo
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
+# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Ported screen alerts from CM-13."
+ - rscadd: "Added screen alerts for buckling, being cuffed, and being on fire."
diff --git a/icons/mob/screen/orange.dmi b/icons/mob/screen/orange.dmi
index b042bdac458..50abf3d6e37 100644
Binary files a/icons/mob/screen/orange.dmi and b/icons/mob/screen/orange.dmi differ
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
new file mode 100644
index 00000000000..99e79ed4306
Binary files /dev/null and b/icons/mob/screen_alert.dmi differ
diff --git a/maps/away/away_site/quarantined_outpost/quarantined_outpost_objects.dm b/maps/away/away_site/quarantined_outpost/quarantined_outpost_objects.dm
index ba1ad1f60f0..68399b56aa1 100644
--- a/maps/away/away_site/quarantined_outpost/quarantined_outpost_objects.dm
+++ b/maps/away/away_site/quarantined_outpost/quarantined_outpost_objects.dm
@@ -112,6 +112,9 @@ GLOBAL_LIST_EMPTY(trackables_pool)
if(on_fire)
AddOverlays(image("icon" = 'icons/mob/burning/burning_generic.dmi', "icon_state" = "lower"))
+ throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
+ else
+ clear_alert(ALERT_FIRE)
/mob/living/simple_animal/hostile/revivable/AttackTarget()
. = ..()
diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js
index 6061256f2d2..73b680a0985 100644
--- a/tgui/packages/tgui-panel/chat/constants.js
+++ b/tgui/packages/tgui-panel/chat/constants.js
@@ -72,7 +72,7 @@ export const MESSAGE_TYPES = [
name: 'Warnings',
description: 'Urgent messages from the game and items',
selector:
- '.warning:not(.pm), .critical, .userdanger, .italics, .alertsyndie, .warningplain',
+ '.warning:not(.pm), .critical, .userdanger, .italics, .alertsyndie, .warningplain, .boldwarning',
},
{
type: MESSAGE_TYPE_DEADCHAT,
diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
index b964df57275..182d382f9d0 100644
--- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
+++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
@@ -536,6 +536,11 @@ em {
color: #c51e1e;
font-style: italic;
}
+.boldwarning {
+ color: #c51e1e;
+ font-weight: bold;
+ font-style: italic;
+}
.boldannounce {
color: #c51e1e;
font-weight: bold;
@@ -549,6 +554,10 @@ em {
.notice {
color: #6685f5;
}
+.boldnotice {
+ color: #6685f5;
+ font-weight: bold;
+}
.rose {
color: #ff5050;
}
diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
index 3981f89d769..aee92d34d43 100644
--- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
+++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
@@ -554,6 +554,11 @@ h2.alert {
color: #ff0000;
font-style: italic;
}
+.boldwarning {
+ color: #ff0000;
+ font-style: italic;
+ font-weight: bold;
+}
.boldannounce {
color: #ff0000;
font-weight: bold;
@@ -567,6 +572,10 @@ h2.alert {
.notice {
color: #000099;
}
+.boldnotice {
+ color: #000099;
+ font-weight: bold;
+}
.alium {
color: #00ff00;
}