diff --git a/.github/boring-cyborg.yml b/.github/boring-cyborg.yml
index 4b8d729834..d6047f49af 100644
--- a/.github/boring-cyborg.yml
+++ b/.github/boring-cyborg.yml
@@ -6,24 +6,24 @@
labelPRBasedOnFilePath:
# Add 'Type: Map' to any changes to .dmm files
"Type: Map":
- - '**.dmm'
+ - '**/*.dmm'
# Add 'Type: Map' to any changes to image files
"Type: Icon":
- - '**.dmi'
- - '**.png'
- - '**.jpg'
+ - '**/*.dmi'
+ - '**/*.png'
+ - '**/*.jpg'
# Add 'Type: Sound' to any change to sound files
"Type: Sound":
- - '**.ogg'
- - '**.mp3'
- - '**.wav'
+ - '**/*.ogg'
+ - '**/*.mp3'
+ - '**/*.wav'
# Add 'Type: Fluff' to any change to *custom_items*
"Type: Fluff":
- - '**custom_items**'
- - '**loadout_fluff**'
+ - '**/*custom_items*'
+ - '**/*loadout_fluff*'
# Contains changes to system folders
"Type: .git or .github":
diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm
index d7bab37345..f97f206634 100644
--- a/code/__defines/is_helpers.dm
+++ b/code/__defines/is_helpers.dm
@@ -54,4 +54,4 @@
//---------------
//#define isturf(D) istype(D, /turf) //Built in
#define isopenspace(A) istype(A, /turf/simulated/open)
-#define isspace(A) istype(A, /turf/space)
+#define isspace(A) istype(A, /turf/space)
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 518cc78b91..978f2d782d 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -159,3 +159,23 @@
#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
#define ui_ghost_pai "SOUTH: 6,CENTER+2:24"
#define ui_ghost_updown "SOUTH: 6,CENTER+3:24"
+
+// Rig panel
+#define ui_rig_deco1 "WEST:-7, SOUTH+5"
+#define ui_rig_deco2 "WEST:-7, SOUTH+6"
+#define ui_rig_pwr "WEST+1:-7, SOUTH+6"
+#define ui_rig_health "WEST+1:-7, SOUTH+6"
+#define ui_rig_air "WEST+1:-7, SOUTH+5"
+#define ui_rig_airtoggle "WEST+1:-7, SOUTH+5"
+#define ui_rig_deco1_f "WEST+2:-7, SOUTH+5"
+#define ui_rig_deco2_f "WEST+2:-7, SOUTH+6"
+
+// Mech panel
+#define ui_mech_deco1 "WEST:-7, SOUTH+8"
+#define ui_mech_deco2 "WEST:-7, SOUTH+9"
+#define ui_mech_pwr "WEST+1:-7, SOUTH+9"
+#define ui_mech_health "WEST+1:-7, SOUTH+9"
+#define ui_mech_air "WEST+1:-7, SOUTH+8"
+#define ui_mech_airtoggle "WEST+1:-7, SOUTH+8"
+#define ui_mech_deco1_f "WEST+2:-7, SOUTH+8"
+#define ui_mech_deco2_f "WEST+2:-7, SOUTH+9"
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 2b18b5a90d..7e23e31692 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -36,8 +36,9 @@
alert = new type
if(new_master)
- alert.icon_state = "template" // blank, so our icon is presented
+ 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
alert.add_overlay(I)
alert.master = new_master
else
@@ -220,6 +221,11 @@ The box in your backpack has an oxygen tank and gas mask in it."
or something covering your eyes."
icon_state = "blind"
+/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 man, you're tripping balls! Careful you don't get addicted... if you aren't already."
@@ -312,12 +318,14 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
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 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"
@@ -325,6 +333,7 @@ office by your AI master or any qualified human may resolve this matter. Robotic
so as to remain in compliance with the most up-to-date laws."
icon_state = "newlaw"
timeout = 300
+ no_underlay = TRUE
//MECHS
@@ -397,12 +406,13 @@ so as to remain in compliance with the most up-to-date laws."
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)) // prevents "" state from attempting matches
+ 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)
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index 048b0e716d..7af541e9d3 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -1,30 +1,43 @@
/obj/screen/ghost
icon = 'icons/mob/screen_ghost.dmi'
-/obj/screen/ghost/MouseEntered()
+/obj/screen/ghost/MouseEntered(location,control,params)
flick(icon_state + "_anim", src)
+ openToolTip(usr, src, params, title = name, content = desc)
+
+/obj/screen/ghost/MouseExited()
+ closeToolTip(usr)
+
+/obj/screen/ghost/Click()
+ closeToolTip(usr)
/obj/screen/ghost/jumptomob
name = "Jump to mob"
+ desc = "Pick a mob from a list to jump to."
icon_state = "jumptomob"
/obj/screen/ghost/jumptomob/Click()
+ ..()
var/mob/observer/dead/G = usr
G.jumptomob()
/obj/screen/ghost/orbit
name = "Orbit"
+ desc = "Pick a mob to follow and orbit."
icon_state = "orbit"
/obj/screen/ghost/orbit/Click()
+ ..()
var/mob/observer/dead/G = usr
G.follow()
/obj/screen/ghost/reenter_corpse
name = "Reenter corpse"
+ desc = "Only applicable if you HAVE a corpse..."
icon_state = "reenter_corpse"
/obj/screen/ghost/reenter_corpse/Click()
+ ..()
var/mob/observer/dead/G = usr
G.reenter_corpse()
@@ -33,30 +46,37 @@
icon_state = "teleport"
/obj/screen/ghost/teleport/Click()
+ ..()
var/mob/observer/dead/G = usr
G.dead_tele()
/obj/screen/ghost/pai
- name = "pAI Candidate"
+ name = "pAI Alert"
+ desc = "Ping all the unoccupied pAI devices in the world."
icon_state = "pai"
/obj/screen/ghost/pai/Click()
+ ..()
var/mob/observer/dead/G = usr
G.paialert()
/obj/screen/ghost/up
name = "Move Upwards"
+ desc = "Move up a z-level."
icon_state = "up"
/obj/screen/ghost/up/Click()
+ ..()
var/mob/observer/dead/G = usr
G.zMove(UP)
/obj/screen/ghost/down
name = "Move Downwards"
+ desc = "Move down a z-level."
icon_state = "down"
/obj/screen/ghost/down/Click()
+ ..()
var/mob/observer/dead/G = usr
G.zMove(DOWN)
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index c4dabaf3ca..5fbe760240 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -184,6 +184,7 @@ var/list/global_huds = list(
var/list/adding
var/list/other
+ var/list/miniobjs
var/list/obj/screen/hotkeybuttons
var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
@@ -193,6 +194,8 @@ var/list/global_huds = list(
var/icon/ui_style
var/ui_color
var/ui_alpha
+
+ var/list/minihuds = list()
datum/hud/New(mob/owner)
mymob = owner
@@ -219,6 +222,7 @@ datum/hud/New(mob/owner)
hotkeybuttons = null
// item_action_list = null // ?
mymob = null
+ qdel_null(minihuds)
/datum/hud/proc/hidden_inventory_update()
if(!mymob) return
@@ -325,6 +329,26 @@ datum/hud/New(mob/owner)
HUD.ui_color = client?.prefs?.UI_style_color
HUD.ui_alpha = client?.prefs?.UI_style_alpha
+/datum/hud/proc/apply_minihud(var/datum/mini_hud/MH)
+ if(MH in minihuds)
+ return
+ minihuds += MH
+ if(mymob.client)
+ mymob.client.screen -= miniobjs
+ miniobjs += MH.get_screen_objs()
+ if(mymob.client)
+ mymob.client.screen += miniobjs
+
+/datum/hud/proc/remove_minihud(var/datum/mini_hud/MH)
+ if(!(MH in minihuds))
+ return
+ minihuds -= MH
+ if(mymob.client)
+ mymob.client.screen -= miniobjs
+ miniobjs -= MH.get_screen_objs()
+ if(mymob.client)
+ mymob.client.screen += miniobjs
+
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
/mob/verb/button_pressed_F12(var/full = 0 as null)
set name = "F12"
@@ -332,61 +356,66 @@ datum/hud/New(mob/owner)
if(!hud_used)
to_chat(usr, "This mob type does not use a HUD.")
- return
-
- if(!ishuman(src))
- to_chat(usr, "Inventory hiding is currently only supported for human mobs, sorry.")
- return
-
- if(!client) return
+ return FALSE
+ if(!client)
+ return FALSE
if(client.view != world.view)
- return
+ return FALSE
+
+ toggle_hud_vis(full)
+
+/mob/proc/toggle_hud_vis(full)
if(hud_used.hud_shown)
hud_used.hud_shown = 0
- if(src.hud_used.adding)
- src.client.screen -= src.hud_used.adding
- if(src.hud_used.other)
- src.client.screen -= src.hud_used.other
- if(src.hud_used.hotkeybuttons)
- src.client.screen -= src.hud_used.hotkeybuttons
-
- //Due to some poor coding some things need special treatment:
- //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
- if(!full)
- src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
- src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
- src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
- src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
- else
- src.client.screen -= src.healths
- src.client.screen -= src.internals
- src.client.screen -= src.gun_setting_icon
-
- //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
- src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason.
-
+ if(hud_used.adding)
+ client.screen -= hud_used.adding
+ if(hud_used.other)
+ client.screen -= hud_used.other
+ if(hud_used.hotkeybuttons)
+ client.screen -= hud_used.hotkeybuttons
else
hud_used.hud_shown = 1
- if(src.hud_used.adding)
- src.client.screen += src.hud_used.adding
- if(src.hud_used.other && src.hud_used.inventory_shown)
- src.client.screen += src.hud_used.other
- if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
- src.client.screen += src.hud_used.hotkeybuttons
- if(src.healths)
- src.client.screen |= src.healths
- if(src.internals)
- src.client.screen |= src.internals
- if(src.gun_setting_icon)
- src.client.screen |= src.gun_setting_icon
+ if(hud_used.adding)
+ client.screen += hud_used.adding
+ if(hud_used.other && hud_used.inventory_shown)
+ client.screen += hud_used.other
+ if(hud_used.hotkeybuttons && !hud_used.hotkey_ui_hidden)
+ client.screen += hud_used.hotkeybuttons
+ if(healths)
+ client.screen |= healths
+ if(internals)
+ client.screen |= internals
+ if(gun_setting_icon)
+ client.screen |= gun_setting_icon
- src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
- src.client.screen += src.zone_sel //This one is a special snowflake
+ hud_used?.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
+ client.screen += zone_sel //This one is a special snowflake
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
update_action_buttons()
hud_used.reorganize_alerts()
+ return TRUE
+
+/mob/living/carbon/human/toggle_hud_vis(full)
+ ..()
+
+ // Prevents humans from hiding a few hud elements
+ if(!hud_used.hud_shown) // transitioning to hidden
+ //Due to some poor coding some things need special treatment:
+ //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
+ if(!full)
+ client.screen += hud_used.l_hand_hud_object //we want the hands to be visible
+ client.screen += hud_used.r_hand_hud_object //we want the hands to be visible
+ client.screen += hud_used.action_intent //we want the intent swticher visible
+ hud_used?.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
+ else
+ client.screen -= healths
+ client.screen -= internals
+ client.screen -= gun_setting_icon
+
+ //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
+ client.screen -= zone_sel //zone_sel is a mob variable for some reason.
//Similar to button_pressed_F12() but keeps zone_sel, gun_setting_icon, and healths.
/mob/proc/toggle_zoom_hud()
diff --git a/code/_onclick/hud/rigmech.dm b/code/_onclick/hud/rigmech.dm
new file mode 100644
index 0000000000..91632e1604
--- /dev/null
+++ b/code/_onclick/hud/rigmech.dm
@@ -0,0 +1,267 @@
+/datum/mini_hud
+ var/datum/hud/main_hud
+ var/list/screenobjs = list()
+ var/list/types_to_instantiate
+ var/needs_processing = FALSE
+
+/datum/mini_hud/New(var/datum/hud/other)
+ apply_to_hud(other)
+ if(needs_processing)
+ START_PROCESSING(SSprocessing, src)
+
+/datum/mini_hud/Destroy()
+ main_hud?.remove_minihud(src)
+ main_hud = null
+ if(needs_processing)
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
+
+// Apply to a real /datum/hud
+/datum/mini_hud/proc/apply_to_hud(var/datum/hud/other)
+ if(main_hud)
+ unapply_to_hud(main_hud)
+ main_hud = other
+ main_hud.apply_minihud(src)
+
+// Remove from a real /datum/hud
+/datum/mini_hud/proc/unapply_to_hud(var/datum/hud/other)
+ main_hud.remove_minihud(src)
+
+// Update the hud
+/datum/mini_hud/process()
+ return PROCESS_KILL // You shouldn't be here!
+
+// Return a list of screen objects we use
+/datum/mini_hud/proc/get_screen_objs(var/mob/M)
+ return screenobjs
+
+// Specific types
+/datum/mini_hud/rig
+ var/obj/item/weapon/rig/owner_rig
+ var/obj/screen/rig/power/power
+ var/obj/screen/rig/health/health
+ var/obj/screen/rig/air/air
+ var/obj/screen/rig/airtoggle/airtoggle
+
+ needs_processing = TRUE
+
+/datum/mini_hud/rig/New(var/datum/hud/other, var/obj/item/weapon/rig/owner)
+ owner_rig = owner
+ power = new ()
+ health = new ()
+ air = new ()
+ airtoggle = new ()
+
+ screenobjs = list(power, health, air, airtoggle)
+ screenobjs += new /obj/screen/rig/deco1
+ screenobjs += new /obj/screen/rig/deco2
+ screenobjs += new /obj/screen/rig/deco1_f
+ screenobjs += new /obj/screen/rig/deco2_f
+
+ for(var/scr in screenobjs)
+ var/obj/screen/S = scr
+ S.master = owner_rig
+ ..()
+
+/datum/mini_hud/rig/Destroy()
+ if(owner_rig)
+ //owner_rig.minihud = null
+ owner_rig = null
+ return ..()
+
+/datum/mini_hud/rig/process()
+ if(!owner_rig)
+ qdel(src)
+ return
+
+ var/obj/item/weapon/cell/rigcell = owner_rig.cell
+ var/obj/item/weapon/tank/rigtank = owner_rig.air_supply
+
+ var/charge_percentage = rigcell ? rigcell.charge / rigcell.maxcharge : 0
+ var/air_percentage = rigtank ? CLAMP(rigtank.air_contents.total_moles / 17.4693, 0, 1) : 0
+ var/air_on = owner_rig.wearer?.internal ? 1 : 0
+
+ power.icon_state = "pwr[round(charge_percentage / 0.2, 1)]"
+ air.icon_state = "air[round(air_percentage / 0.2, 1)]"
+ health.icon_state = owner_rig.malfunctioning ? "health1" : "health5"
+ airtoggle.icon_state = "airon[air_on]"
+
+/datum/mini_hud/mech
+ var/obj/mecha/owner_mech
+ var/obj/screen/mech/power/power
+ var/obj/screen/mech/health/health
+ var/obj/screen/mech/air/air
+ var/obj/screen/mech/airtoggle/airtoggle
+
+ needs_processing = TRUE
+
+/datum/mini_hud/mech/New(var/datum/hud/other, var/obj/mecha/owner)
+ owner_mech = owner
+ power = new ()
+ health = new ()
+ air = new ()
+ airtoggle = new ()
+
+ screenobjs = list(power, health, air, airtoggle)
+ screenobjs += new /obj/screen/mech/deco1
+ screenobjs += new /obj/screen/mech/deco2
+ screenobjs += new /obj/screen/mech/deco1_f
+ screenobjs += new /obj/screen/mech/deco2_f
+
+ for(var/scr in screenobjs)
+ var/obj/screen/S = scr
+ S.master = owner_mech
+ ..()
+
+/datum/mini_hud/mech/Destroy()
+ if(owner_mech)
+ owner_mech.minihud = null
+ owner_mech = null
+ return ..()
+
+/datum/mini_hud/mech/process()
+ if(!owner_mech)
+ qdel(src)
+ return
+
+ var/obj/item/weapon/cell/mechcell = owner_mech.cell
+ var/obj/machinery/portable_atmospherics/canister/mechtank = owner_mech.internal_tank
+
+ var/charge_percentage = mechcell ? mechcell.charge / mechcell.maxcharge : 0
+ var/air_percentage = mechtank ? CLAMP(mechtank.air_contents.total_moles / 1863.47, 0, 1) : 0
+ var/health_percentage = owner_mech.health / owner_mech.maxhealth
+ var/air_on = owner_mech.use_internal_tank
+
+ power.icon_state = "pwr[round(charge_percentage / 0.2, 1)]"
+ air.icon_state = "air[round(air_percentage / 0.2, 1)]"
+ health.icon_state = "health[round(health_percentage / 0.2, 1)]"
+ airtoggle.icon_state = "airon[air_on]"
+
+// Screen objects
+/obj/screen/rig
+ icon = 'icons/mob/screen_rigmech.dmi'
+
+/obj/screen/rig/deco1
+ name = "RIG Status"
+ icon_state = "frame1_1"
+ screen_loc = ui_rig_deco1
+
+/obj/screen/rig/deco2
+ name = "RIG Status"
+ icon_state = "frame1_2"
+ screen_loc = ui_rig_deco2
+
+/obj/screen/rig/deco1_f
+ name = "RIG Status"
+ icon_state = "frame1_1_far"
+ screen_loc = ui_rig_deco1_f
+
+/obj/screen/rig/deco2_f
+ name = "RIG Status"
+ icon_state = "frame1_2_far"
+ screen_loc = ui_rig_deco2_f
+
+/obj/screen/rig/power
+ name = "Charge Level"
+ icon_state = "pwr5"
+ screen_loc = ui_rig_pwr
+
+/obj/screen/rig/health
+ name = "Integrity Level"
+ icon_state = "health5"
+ screen_loc = ui_rig_health
+
+/obj/screen/rig/air
+ name = "Air Storage"
+ icon_state = "air5"
+ screen_loc = ui_rig_air
+
+/obj/screen/rig/airtoggle
+ name = "Toggle Air"
+ icon_state = "airoff"
+ screen_loc = ui_rig_airtoggle
+
+/obj/screen/rig/airtoggle/Click()
+ var/mob/living/carbon/human/user = usr
+ if(!istype(user) || user.stat || user.incapacitated())
+ return
+ var/obj/item/weapon/rig/owner_rig = master
+ if(user != owner_rig.wearer)
+ return
+ user.toggle_internals()
+
+/obj/screen/mech
+ icon = 'icons/mob/screen_rigmech.dmi'
+
+/obj/screen/mech/deco1
+ name = "Mech Status"
+ icon_state = "frame1_1"
+ screen_loc = ui_mech_deco1
+
+/obj/screen/mech/deco2
+ name = "Mech Status"
+ icon_state = "frame1_2"
+ screen_loc = ui_mech_deco2
+
+/obj/screen/mech/deco1_f
+ name = "Mech Status"
+ icon_state = "frame1_1_far"
+ screen_loc = ui_mech_deco1_f
+
+/obj/screen/mech/deco2_f
+ name = "Mech Status"
+ icon_state = "frame1_2_far"
+ screen_loc = ui_mech_deco2_f
+
+/obj/screen/mech/power
+ name = "Charge Level"
+ icon_state = "pwr5"
+ screen_loc = ui_mech_pwr
+
+/obj/screen/mech/health
+ name = "Integrity Level"
+ icon_state = "health5"
+ screen_loc = ui_mech_health
+
+/obj/screen/mech/air
+ name = "Air Storage"
+ icon_state = "air5"
+ screen_loc = ui_mech_air
+
+/obj/screen/mech/airtoggle
+ name = "Toggle Air"
+ icon_state = "airoff"
+ screen_loc = ui_mech_airtoggle
+
+/obj/screen/mech/airtoggle/Click()
+ var/mob/living/carbon/human/user = usr
+ if(!istype(user) || user.stat || user.incapacitated())
+ return
+ var/obj/mecha/owner_mech = master
+ if(user != owner_mech.occupant)
+ return
+ owner_mech.toggle_internal_tank()
+
+/*
+/mob/observer/dead/create_mob_hud(datum/hud/HUD, apply_to_client = TRUE)
+ ..()
+
+ var/list/adding = list()
+ HUD.adding = adding
+
+ var/obj/screen/using
+ using = new /obj/screen/ghost/jumptomob()
+ using.screen_loc = ui_ghost_jumptomob
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/ghost/orbit()
+ using.screen_loc = ui_ghost_orbit
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/ghost/reenter_corpse()
+ using.screen_loc = ui_ghost_reenter_corpse
+ using.hud = src
+ adding += using
+*/
\ No newline at end of file
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 8b194a139c..7c214e3a29 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -5,40 +5,75 @@ var/global/datum/getrev/revdata = new()
var/revision
var/date
var/showinfo
+ var/list/testmerge = list()
/datum/getrev/New()
- var/list/head_branch = file2list(".git/HEAD", "\n")
- if(head_branch.len)
- branch = copytext(head_branch[1], 17)
+ if(world.TgsAvailable()) // Try TGS maybe
+ testmerge = world.TgsTestMerges()
+ var/datum/tgs_revision_information/REV = world.TgsRevision()
+ if(REV)
+ revision = REV.origin_commit || REV.commit
+ branch = "-Using TGS-" // TGS doesn't provide branch info yet
+ date = "-Using TGS-" // Or date
+
+ if(!revision) // File parse method
+ var/list/head_branch = file2list(".git/HEAD", "\n")
+ if(head_branch.len)
+ branch = copytext(head_branch[1], 17)
- var/list/head_log = file2list(".git/logs/HEAD", "\n")
- for(var/line=head_log.len, line>=1, line--)
- if(head_log[line])
- var/list/last_entry = splittext(head_log[line], " ")
- if(last_entry.len < 2) continue
- revision = last_entry[2]
- // Get date/time
- if(last_entry.len >= 5)
- var/unix_time = text2num(last_entry[5])
- if(unix_time)
- date = unix2date(unix_time)
- break
+ var/list/head_log = file2list(".git/logs/HEAD", "\n")
+ for(var/line=head_log.len, line>=1, line--)
+ if(head_log[line])
+ var/list/last_entry = splittext(head_log[line], " ")
+ if(last_entry.len < 2) continue
+ revision = last_entry[2]
+ // Get date/time
+ if(last_entry.len >= 5)
+ var/unix_time = text2num(last_entry[5])
+ if(unix_time)
+ date = unix2date(unix_time)
+ break
- to_world_log("Running revision:")
- to_world_log(branch)
- to_world_log(date)
- to_world_log(revision)
+ to_world_log("-Revision Info-")
+ to_world_log("Branch: [branch]")
+ to_world_log("Date: [date]")
+ to_world_log("Revision: [revision]")
+
+/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
+ if(!testmerge.len)
+ return ""
+ . = header ? "The following pull requests are currently test merged:
" : ""
+ for(var/line in testmerge)
+ var/datum/tgs_revision_information/test_merge/tm = line
+ var/cm = tm.pull_request_commit
+ var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
+ if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
+ continue
+ . += "#[tm.number][details]
"
client/verb/showrevinfo()
set category = "OOC"
set name = "Show Server Revision"
set desc = "Check the current server code revision"
+ var/list/msg = list()
+
if(revdata.revision)
- to_chat(src, "Server revision: [revdata.branch] - [revdata.date]")
+ msg += "Server revision: [revdata.branch] - [revdata.date]"
if(config.githuburl)
- to_chat(src, "[revdata.revision]")
+ msg += "[revdata.revision]"
else
to_chat(src,revdata.revision)
else
- to_chat(src, "Revision unknown")
+ msg += "Server revision: Unknown"
+
+ if(world.TgsAvailable())
+ var/datum/tgs_version/version = world.TgsVersion()
+ msg += "TGS version: [version.raw_parameter]"
+ var/datum/tgs_version/api_version = world.TgsApiVersion()
+ msg += "DMAPI version: [api_version.raw_parameter]"
+
+ if(revdata.testmerge.len)
+ msg += revdata.GetTestMergeInfo()
+
+ to_chat(src, msg.Join("
"))
diff --git a/code/datums/outfits/jobs/security.dm b/code/datums/outfits/jobs/security.dm
index 814cda5054..a5e058ca9c 100644
--- a/code/datums/outfits/jobs/security.dm
+++ b/code/datums/outfits/jobs/security.dm
@@ -41,8 +41,8 @@
/decl/hierarchy/outfit/job/security/detective/forensic
name = OUTFIT_JOB_NAME("Forensic technician")
head = /obj/item/clothing/head/helmet/detective_alt
- suit = null
- uniform = /obj/item/clothing/under/detective_alt
+ suit = /datum/gear/uniform/detective_alt2
+ uniform = /obj/item/clothing/under/det
//VOREStation Edit End
/decl/hierarchy/outfit/job/security/officer
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 87a09d538a..01f5e687d8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -21,7 +21,7 @@
var/icon_rotation = 0 // Used to rotate icons in update_transform()
var/old_x = 0
var/old_y = 0
- var/datum/riding/riding_datum //VOREStation Add - Moved from /obj/vehicle
+ var/datum/riding/riding_datum = null
var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P)
var/movement_type = NONE
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index a410ad79b3..2200ef94c6 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -53,15 +53,6 @@
return TRUE
return FALSE
-/obj/machinery/optable/MouseDrop_T(obj/O as obj, mob/user as mob)
-
- if((!(istype(O, /obj/item/weapon)) || user.get_active_hand() != O))
- return
- user.drop_item()
- if(O.loc != src.loc)
- step(O, get_dir(O, src))
- return
-
/obj/machinery/optable/proc/check_victim()
if(locate(/mob/living/carbon/human, src.loc))
var/mob/living/carbon/human/M = locate(/mob/living/carbon/human, src.loc)
@@ -102,40 +93,43 @@
else
icon_state = "table2-idle"
-/obj/machinery/optable/MouseDrop_T(mob/target, mob/user)
-
- var/mob/living/M = user
- if(user.stat || user.restrained() || !check_table(user) || !iscarbon(target))
- return
- if(istype(M))
- take_victim(target,user)
- else
+/obj/machinery/optable/MouseDrop_T(mob/living/carbon/target, mob/living/user)
+ if(!istype(target) || !istype(user))
return ..()
+ if(!Adjacent(target) || !Adjacent(user))
+ return ..()
+
+ if(user.incapacitated() || !check_table(target, user))
+ return ..()
+
+ take_victim(target, user)
+
/obj/machinery/optable/verb/climb_on()
set name = "Climb On Table"
set category = "Object"
set src in oview(1)
- if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table(usr))
+ var/mob/living/user = usr
+ if(!istype(user) || user.incapacitated() || !check_table(user, user))
return
- take_victim(usr,usr)
+ take_victim(user, user)
-/obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob)
+/obj/machinery/optable/attackby(obj/item/weapon/W, mob/living/carbon/user)
if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
- if(iscarbon(G.affecting) && check_table(G.affecting))
- take_victim(G.affecting,usr)
+ if(iscarbon(G.affecting) && check_table(G.affecting, user))
+ take_victim(G.affecting, user)
qdel(W)
return
-/obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob)
+/obj/machinery/optable/proc/check_table(mob/living/carbon/patient, mob/living/user)
check_victim()
if(victim && get_turf(victim) == get_turf(src) && victim.lying)
- to_chat(usr, "\The [src] is already occupied!")
+ to_chat(user, "\The [src] is already occupied!")
return 0
if(patient.buckled)
- to_chat(usr, "Unbuckle \the [patient] first!")
+ to_chat(user, "Unbuckle \the [patient] first!")
return 0
return 1
\ No newline at end of file
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index f7fd84eca7..60541e0fe3 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -152,11 +152,11 @@
cameraFollow = null
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target as mob)
- if(!istype(target)) return
+ if(!istype(target)) return FALSE
var/mob/living/silicon/ai/U = usr
if(target == U.cameraFollow)
- return
+ return TRUE
if(U.cameraFollow)
U.ai_cancel_tracking()
@@ -185,6 +185,8 @@
return
sleep(10)
+ return TRUE
+
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
if (!istype(user))
return
diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm
index b40314d2c2..37c75957be 100644
--- a/code/game/machinery/oxygen_pump.dm
+++ b/code/game/machinery/oxygen_pump.dm
@@ -41,8 +41,11 @@
return ..()
/obj/machinery/oxygen_pump/MouseDrop(var/mob/living/carbon/human/target, src_location, over_location)
- ..()
- if(istype(target) && CanMouseDrop(target))
+ var/mob/living/user = usr
+ if(!istype(user) || !istype(target))
+ return ..()
+
+ if(CanMouseDrop(target, user))
if(!can_apply_to_target(target, usr)) // There is no point in attempting to apply a mask if it's impossible.
return
usr.visible_message("\The [usr] begins placing \the [contained] onto [target].")
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 990a99bc05..594c89a4ee 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -100,6 +100,8 @@
var/static/image/radial_image_lighttoggle = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_light")
var/static/image/radial_image_statpanel = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine2")
+ var/datum/mini_hud/mech/minihud
+
/obj/mecha/drain_power(var/drain_check)
@@ -195,6 +197,7 @@
QDEL_NULL(pr_give_air)
QDEL_NULL(pr_internal_damage)
QDEL_NULL(spark_system)
+ QDEL_NULL(minihud)
mechas_list -= src //global mech list
. = ..()
@@ -1321,6 +1324,8 @@
src.verbs += /obj/mecha/verb/eject
src.log_append_to_last("[H] moved in as pilot.")
src.icon_state = src.reset_icon()
+ if(occupant.hud_used)
+ minihud = new (occupant.hud_used, src)
update_cell_alerts()
update_damage_alerts()
set_dir(dir_in)
@@ -1386,6 +1391,7 @@
/obj/mecha/proc/go_out()
if(!src.occupant) return
var/atom/movable/mob_container
+ QDEL_NULL(minihud)
if(ishuman(occupant))
mob_container = src.occupant
else if(istype(occupant, /mob/living/carbon/brain))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index c295a1a08c..4835268bfa 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -341,7 +341,7 @@ var/list/global/slot_flags_enumeration = list(
//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
//Set disable_warning to 1 if you wish it to not give you outputs.
//Should probably move the bulk of this into mob code some time, as most of it is related to the definition of slots and not item-specific
-/obj/item/proc/mob_can_equip(M as mob, slot, disable_warning = 0)
+/obj/item/proc/mob_can_equip(M as mob, slot, disable_warning = FALSE)
if(!slot) return 0
if(!M) return 0
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index 562ed56990..08d4440d66 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -183,6 +183,13 @@ var/list/GPS_list = list()
/obj/item/device/gps/security/on
tracking = TRUE
+/obj/item/device/gps/security/hos
+ icon_state = "gps-sec-hos"
+ gps_tag = "HOS0"
+
+/obj/item/device/gps/security/hos/on
+ tracking = TRUE
+
/obj/item/device/gps/medical
icon_state = "gps-med"
gps_tag = "MED0"
@@ -190,6 +197,13 @@ var/list/GPS_list = list()
/obj/item/device/gps/medical/on
tracking = TRUE
+/obj/item/device/gps/medical/cmo
+ icon_state = "gps-med-cmo"
+ gps_tag = "CMO0"
+
+/obj/item/device/gps/medical/cmo/on
+ tracking = TRUE
+
/obj/item/device/gps/science
icon_state = "gps-sci"
gps_tag = "SCI0"
@@ -197,6 +211,13 @@ var/list/GPS_list = list()
/obj/item/device/gps/science/on
tracking = TRUE
+/obj/item/device/gps/science/rd
+ icon_state = "gps-sci-rd"
+ gps_tag = "RD0"
+
+/obj/item/device/gps/science/rd/on
+ tracking = TRUE
+
/obj/item/device/gps/engineering
icon_state = "gps-eng"
gps_tag = "ENG0"
@@ -204,6 +225,20 @@ var/list/GPS_list = list()
/obj/item/device/gps/engineering/on
tracking = TRUE
+/obj/item/device/gps/engineering/atmos
+ icon_state = "gps-eng-atm"
+ gps_tag = "ATM0"
+
+/obj/item/device/gps/engineering/atmos/on
+ tracking = TRUE
+
+/obj/item/device/gps/engineering/ce
+ icon_state = "gps-eng-ce"
+ gps_tag = "CE0"
+
+/obj/item/device/gps/engineering/ce/on
+ tracking = TRUE
+
/obj/item/device/gps/mining
icon_state = "gps-mine"
gps_tag = "MINE0"
diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm
index ddb7e873e6..63afc51b4e 100644
--- a/code/game/objects/items/weapons/storage/internal.dm
+++ b/code/game/objects/items/weapons/storage/internal.dm
@@ -18,7 +18,7 @@
/obj/item/weapon/storage/internal/attack_hand()
return //make sure this is never picked up
-/obj/item/weapon/storage/internal/mob_can_equip(M as mob, slot, disable_warning = 0)
+/obj/item/weapon/storage/internal/mob_can_equip(M as mob, slot, disable_warning = FALSE)
return 0 //make sure this is never picked up
//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items.
diff --git a/code/game/objects/random/_random.dm b/code/game/objects/random/_random.dm
index b559495eb5..8b616c83f5 100644
--- a/code/game/objects/random/_random.dm
+++ b/code/game/objects/random/_random.dm
@@ -11,15 +11,7 @@
. = ..()
if (!prob(spawn_nothing_percentage))
spawn_item()
- Random_SafeDestroy(0)
-
-// This function should, theoretically, guarantee the deletion of the random object. Not all of them destroy themselves for some reason, especially if created through non-standard means.
-/obj/random/proc/Random_SafeDestroy(var/recursion_level)
- set waitfor = FALSE
- sleep(30)
- qdel(src)
- if(src && recursion_level < 5)
- Random_SafeDestroy(recursion_level + 1)
+ return INITIALIZE_HINT_QDEL
// this function should return a specific item to spawn
/obj/random/proc/item_to_spawn()
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index e0a94e285b..40c47c9bb9 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -14,8 +14,8 @@
var/glass = 0 // 0 = glass can be installed. -1 = glass can't be installed. 1 = glass is already installed. Text = mineral plating is installed instead.
var/created_name = null
- New()
- update_state()
+/obj/structure/door_assembly/New()
+ update_state()
/obj/structure/door_assembly/door_assembly_com
base_icon_state = "com"
@@ -136,23 +136,23 @@
airlock_type = "/multi_tile/glass"
glass = -1 //To prevent bugs in deconstruction process.
- New()
- if(dir in list(EAST, WEST))
- bound_width = width * world.icon_size
- bound_height = world.icon_size
- else
- bound_width = world.icon_size
- bound_height = width * world.icon_size
- update_state()
+/obj/structure/door_assembly/multi_tile/New()
+ if(dir in list(EAST, WEST))
+ bound_width = width * world.icon_size
+ bound_height = world.icon_size
+ else
+ bound_width = world.icon_size
+ bound_height = width * world.icon_size
+ update_state()
- Moved(atom/old_loc, direction, forced = FALSE)
- . = ..()
- if(dir in list(EAST, WEST))
- bound_width = width * world.icon_size
- bound_height = world.icon_size
- else
- bound_width = world.icon_size
- bound_height = width * world.icon_size
+/obj/structure/door_assembly/multi_tile/Moved(atom/old_loc, direction, forced = FALSE)
+ . = ..()
+ if(dir in list(EAST, WEST))
+ bound_width = width * world.icon_size
+ bound_height = world.icon_size
+ else
+ bound_width = world.icon_size
+ bound_height = width * world.icon_size
/obj/structure/door_assembly/proc/rename_door(mob/living/user)
var/t = sanitizeSafe(input(user, "Enter the name for the windoor.", src.name, src.created_name), MAX_NAME_LEN)
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index 1e9c091ccb..7802e258ea 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -8,45 +8,45 @@
w_class = ITEMSIZE_HUGE
var/obj/item/target/pinned_target // the current pinned target
- Moved(atom/old_loc, direction, forced = FALSE)
- . = ..()
- // Move the pinned target along with the stake
- if(pinned_target in view(3, src))
- pinned_target.forceMove(loc)
+/obj/structure/target_stake/Moved(atom/old_loc, direction, forced = FALSE)
+ . = ..()
+ // Move the pinned target along with the stake
+ if(pinned_target in view(3, src))
+ pinned_target.forceMove(loc)
- else // Sanity check: if the pinned target can't be found in immediate view
- pinned_target = null
- density = 1
+ else // Sanity check: if the pinned target can't be found in immediate view
+ pinned_target = null
+ density = 1
- attackby(obj/item/W as obj, mob/user as mob)
- // Putting objects on the stake. Most importantly, targets
- if(pinned_target)
- return // get rid of that pinned target first!
+/obj/structure/target_stake/attackby(obj/item/W as obj, mob/user as mob)
+ // Putting objects on the stake. Most importantly, targets
+ if(pinned_target)
+ return // get rid of that pinned target first!
- if(istype(W, /obj/item/target))
- density = 0
- W.density = 1
- user.remove_from_mob(W)
- W.loc = loc
- W.layer = ABOVE_JUNK_LAYER
- pinned_target = W
- to_chat(user, "You slide the target into the stake.")
- return
+ if(istype(W, /obj/item/target))
+ density = 0
+ W.density = 1
+ user.remove_from_mob(W)
+ W.loc = loc
+ W.layer = ABOVE_JUNK_LAYER
+ pinned_target = W
+ to_chat(user, "You slide the target into the stake.")
+ return
- attack_hand(mob/user as mob)
- // taking pinned targets off!
- if(pinned_target)
- density = 1
- pinned_target.density = 0
- pinned_target.layer = OBJ_LAYER
+/obj/structure/target_stake/attack_hand(mob/user as mob)
+ // taking pinned targets off!
+ if(pinned_target)
+ density = 1
+ pinned_target.density = 0
+ pinned_target.layer = OBJ_LAYER
- pinned_target.loc = user.loc
- if(ishuman(user))
- if(!user.get_active_hand())
- user.put_in_hands(pinned_target)
- to_chat(user, "You take the target out of the stake.")
- else
- pinned_target.loc = get_turf(user)
+ pinned_target.loc = user.loc
+ if(ishuman(user))
+ if(!user.get_active_hand())
+ user.put_in_hands(pinned_target)
to_chat(user, "You take the target out of the stake.")
+ else
+ pinned_target.loc = get_turf(user)
+ to_chat(user, "You take the target out of the stake.")
- pinned_target = null
+ pinned_target = null
diff --git a/code/game/verbs/advanced_who.dm b/code/game/verbs/advanced_who.dm
index 9f067054f2..4498136b2b 100644
--- a/code/game/verbs/advanced_who.dm
+++ b/code/game/verbs/advanced_who.dm
@@ -7,24 +7,36 @@
var/list/Lines = list()
- if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights))
+ if(holder)
for(var/client/C in GLOB.clients)
- var/entry = "\t[C.key]"
+ var/entry = "
| [C.key]"
if(C.holder && C.holder.fakekey)
entry += " (as [C.holder.fakekey])"
- entry += " - Playing as [C.mob.real_name]"
- switch(C.mob.stat)
- if(UNCONSCIOUS)
- entry += " - Unconscious"
- if(DEAD)
- if(isobserver(C.mob))
- var/mob/observer/dead/O = C.mob
- if(O.started_as_observer)
- entry += " - Observing"
- else
- entry += " - DEAD"
+
+ entry += " | "
+
+ if(C.mob.real_name)
+ switch(C.mob.stat)
+ if(UNCONSCIOUS)
+ entry += "Unconscious" // these are literally all spans so I can apply .inverted to them because black on dark grey isn't legible
+
+ if(DEAD)
+ if(isobserver(C.mob))
+ var/mob/observer/dead/O = C.mob
+ if(O.started_as_observer)
+ entry += "Observing"
+ else
+ entry += "Died"
+
else
- entry += " - DEAD"
+ entry += "Playing"
+
+ entry += " as [C.mob.real_name]"
+
+ else if(isnewplayer(C.mob))
+ entry += "In lobby"
+
+ entry += " | "
var/age
if(isnum(C.player_age))
@@ -33,14 +45,20 @@
age = 0
if(age <= 1)
- age = "[age]"
+ age = "[age]"
else if(age < 10)
- age = "[age]"
+ age = "[age]"
- entry += " - [age]"
+ entry += "Age: [age]"
+ entry += " | "
if(is_special_character(C.mob))
- entry += " - Antagonist"
+ if(C.mob?.mind?.special_role)
+ entry += "[C.mob.mind.special_role]"
+ else
+ entry += "Antagonist"
+
+ entry += " | "
if(C.is_afk())
var/seconds = C.last_activity_seconds()
@@ -48,7 +66,9 @@
entry += "[round(seconds / 60)] minutes, "
entry += "[seconds % 60] seconds)"
+ entry += " | "
entry += " (?)"
+ entry += " |
"
Lines += entry
else
@@ -60,16 +80,17 @@
entry += "[C.key]"
var/mob/observer/dead/O = C.mob
if(isobserver(O))
- entry += " - Observing"
+ entry += " - Observing
"
else if(istype(O,/mob/new_player))
- entry += " - In Lobby"
+ entry += " - In Lobby
"
else
- entry += " - Playing"
+ entry += " - Playing
"
Lines += entry
+ msg += ""
for(var/line in sortList(Lines))
- msg += "[line]\n"
-
+ msg += "[line]"
+ msg += "
"
msg += "Total Players: [length(Lines)]"
- msg = "" + msg + ""
+ msg = "" + msg + ""
to_chat(src, msg)
\ No newline at end of file
diff --git a/code/modules/admin/admin_tools.dm b/code/modules/admin/admin_tools.dm
index 376aa2da44..8b4e1ae44c 100644
--- a/code/modules/admin/admin_tools.dm
+++ b/code/modules/admin/admin_tools.dm
@@ -9,18 +9,18 @@
if(M.mind)
dat += "Current Antag?: [(M.mind.special_role)?"Yes":"No"]
"
dat += "
Note: This is arranged from earliest to latest.
"
-
+
if(!isemptylist(M.attack_log))
- dat += "