diff --git a/code/__DEFINES/ARES.dm b/code/__DEFINES/ARES.dm
index 7eee073aca51..55aa68f97309 100644
--- a/code/__DEFINES/ARES.dm
+++ b/code/__DEFINES/ARES.dm
@@ -15,7 +15,7 @@
/// High Command, can read the deletion log.
#define ARES_ACCESS_HIGH 9
#define ARES_ACCESS_WY_COMMAND 10
-/// Debugging. Allows me to view everything without using a high command rank. Unlikely to stay in a full merge.
+/// Debugging. Allows me to view everything without using a high command rank.
#define ARES_ACCESS_DEBUG 11
#define ARES_RECORD_ANNOUNCE "Announcement Record"
@@ -78,6 +78,7 @@
/// Cooldowns
#define COOLDOWN_ARES_SENSOR 60 SECONDS
#define COOLDOWN_ARES_ACCESS_CONTROL 20 SECONDS
+#define COOLDOWN_ARES_VENT 60 SECONDS
/// Time until someone can respawn as Working Joe
#define JOE_JOIN_DEAD_TIME (15 MINUTES)
diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm
index b607215e215d..943e70c8814f 100644
--- a/code/__DEFINES/__game.dm
+++ b/code/__DEFINES/__game.dm
@@ -79,6 +79,8 @@
#define SEE_INVISIBLE_LEVEL_TWO 45 //Used by some other stuff in code. It's really poorly organized.
#define INVISIBILITY_LEVEL_TWO 45 //Used by some other stuff in code. It's really poorly organized.
+#define HIDE_INVISIBLE_OBSERVER 59 // define for when we want to hide all observer mobs.
+
#define INVISIBILITY_OBSERVER 60
#define SEE_INVISIBLE_OBSERVER 60
diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm
index 59e4c7710992..1e72f51a8d60 100644
--- a/code/__HELPERS/logging.dm
+++ b/code/__HELPERS/logging.dm
@@ -125,11 +125,11 @@ GLOBAL_VAR_INIT(log_end, world.system_type == UNIX ? ascii2text(13) : "")
GLOB.STUI.admin.Add("\[[time]]OVERWATCH: [text]")
GLOB.STUI.processing |= STUI_LOG_ADMIN
-/proc/log_idmod(obj/item/card/id/target_id, msg)
+/proc/log_idmod(obj/item/card/id/target_id, msg, changer)
var/time = time_stamp()
if (CONFIG_GET(flag/log_idmod))
- WRITE_LOG(GLOB.world_game_log, "ID MOD: [msg]")
- LOG_REDIS("idmod", "\[[time]\] [msg]")
+ WRITE_LOG(GLOB.world_game_log, "ID MOD: ([changer]) [msg]")
+ LOG_REDIS("idmod", "\[[time]\] ([changer]) [msg]")
target_id.modification_log += "\[[time]]: [msg]"
/proc/log_vote(text)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index e2572e5e2d61..1cf93e998a4e 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -640,3 +640,27 @@ This maintains a list of ip addresses that are able to bypass topic filtering.
splitter = "|"
key_mode = KEY_MODE_TEXT_UNALTERED
value_mode = VALUE_MODE_TEXT
+
+/datum/config_entry/number/client_warn_version
+ default = null
+ min_val = 500
+
+/datum/config_entry/number/client_warn_build
+ default = null
+ min_val = 0
+
+/datum/config_entry/string/client_warn_message
+ default = "Your version of BYOND may have issues or be blocked from accessing this server in the future."
+
+/datum/config_entry/flag/client_warn_popup
+
+/datum/config_entry/number/client_error_version
+ default = null
+ min_val = 500
+
+/datum/config_entry/number/client_error_build
+ default = null
+ min_val = 0
+
+/datum/config_entry/string/client_error_message
+ default = "Your version of BYOND is too old, may have issues, and is blocked from accessing this server."
diff --git a/code/datums/ammo/bullet/revolver.dm b/code/datums/ammo/bullet/revolver.dm
index 0688e615378e..def0a8e31952 100644
--- a/code/datums/ammo/bullet/revolver.dm
+++ b/code/datums/ammo/bullet/revolver.dm
@@ -7,14 +7,13 @@
/datum/ammo/bullet/revolver
name = "revolver bullet"
headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- damage = 55
+ damage = 72
penetration = ARMOR_PENETRATION_TIER_1
accuracy = HIT_ACCURACY_TIER_1
/datum/ammo/bullet/revolver/marksman
name = "marksman revolver bullet"
-
+ damage = 55
shrapnel_chance = 0
damage_falloff = 0
accurate_range = 12
diff --git a/code/datums/skills/uscm.dm b/code/datums/skills/uscm.dm
index 8a6d2fd2c8c2..1e0dedf5dd05 100644
--- a/code/datums/skills/uscm.dm
+++ b/code/datums/skills/uscm.dm
@@ -292,6 +292,7 @@ COMMAND STAFF
SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
SKILL_POLICE = SKILL_POLICE_FLASH,
SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm
index d6f58f371715..6cc7c220fd04 100644
--- a/code/game/machinery/ARES/ARES_interface.dm
+++ b/code/game/machinery/ARES/ARES_interface.dm
@@ -214,6 +214,8 @@
data["active_ref"] = active_ref
data["conversations"] = logged_convos
+ data["security_vents"] = link.get_ares_vents()
+
return data
/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state)
@@ -227,19 +229,19 @@
. = ..()
if(.)
return
-
- playsound(src, "keyboard_alt", 15, 1)
- var/mob/living/carbon/human/operator = ui.user
+ var/mob/user = ui.user
+ var/playsound = TRUE
switch (action)
if("go_back")
if(!last_menu)
- return to_chat(operator, SPAN_WARNING("Error, no previous page detected."))
+ return to_chat(user, SPAN_WARNING("Error, no previous page detected."))
var/temp_holder = current_menu
current_menu = last_menu
last_menu = temp_holder
if("login")
+ var/mob/living/carbon/human/operator = user
var/obj/item/card/id/idcard = operator.get_active_hand()
if(istype(idcard))
authentication = get_ares_access(idcard)
@@ -250,7 +252,7 @@
authentication = get_ares_access(idcard)
last_login = idcard.registered_name
else
- to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!"))
+ to_chat(user, SPAN_WARNING("You require an ID card to access this terminal!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(authentication)
@@ -258,14 +260,14 @@
current_menu = "main"
if("sudo")
- var/new_user = tgui_input_text(operator, "Enter Sudo Username", "Sudo User", encode = FALSE)
+ var/new_user = tgui_input_text(user, "Enter Sudo Username", "Sudo User", encode = FALSE)
if(new_user)
if(new_user == sudo_holder)
last_login = sudo_holder
sudo_holder = null
return FALSE
if(new_user == last_login)
- to_chat(operator, SPAN_WARNING("Already remote logged in as this user."))
+ to_chat(user, SPAN_WARNING("Already remote logged in as this user."))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
sudo_holder = last_login
@@ -331,6 +333,9 @@
if("page_tech")
last_menu = current_menu
current_menu = "tech_log"
+ if("page_core_sec")
+ last_menu = current_menu
+ current_menu = "core_security"
// -- Delete Button -- //
if("delete_record")
@@ -388,9 +393,9 @@
datacore.records_talking -= conversation
if("message_ares")
- var/message = tgui_input_text(operator, "What do you wish to say to ARES?", "ARES Message", encode = FALSE)
+ var/message = tgui_input_text(user, "What do you wish to say to ARES?", "ARES Message", encode = FALSE)
if(message)
- message_ares(message, operator, params["active_convo"])
+ message_ares(message, user, params["active_convo"])
if("read_record")
var/datum/ares_record/deleted_talk/conversation = locate(params["record"])
@@ -403,36 +408,36 @@
// -- Emergency Buttons -- //
if("general_quarters")
if(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown))
- to_chat(operator, SPAN_WARNING("It has not been long enough since the last General Quarters call!"))
+ to_chat(user, SPAN_WARNING("It has not been long enough since the last General Quarters call!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(GLOB.security_level < SEC_LEVEL_RED)
set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE)
shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg')
- log_game("[key_name(operator)] has called for general quarters via ARES.")
- message_admins("[key_name_admin(operator)] has called for general quarters via ARES.")
+ log_game("[key_name(user)] has called for general quarters via ARES.")
+ message_admins("[key_name_admin(user)] has called for general quarters via ARES.")
log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.")
COOLDOWN_START(datacore, ares_quarters_cooldown, 10 MINUTES)
. = TRUE
if("evacuation_start")
if(GLOB.security_level < SEC_LEVEL_RED)
- to_chat(operator, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
+ to_chat(user, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(SShijack.evac_admin_denied)
- to_chat(operator, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
+ to_chat(user, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(!SShijack.initiate_evacuation())
- to_chat(operator, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
+ to_chat(user, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
- log_game("[key_name(operator)] has called for an emergency evacuation via ARES.")
- message_admins("[key_name_admin(operator)] has called for an emergency evacuation via ARES.")
+ log_game("[key_name(user)] has called for an emergency evacuation via ARES.")
+ message_admins("[key_name_admin(user)] has called for an emergency evacuation via ARES.")
log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.")
. = TRUE
@@ -440,27 +445,27 @@
if(!SSticker.mode)
return FALSE //Not a game mode?
if(world.time < DISTRESS_TIME_LOCK)
- to_chat(operator, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!"))
+ to_chat(user, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(!COOLDOWN_FINISHED(datacore, ares_distress_cooldown))
- to_chat(operator, SPAN_WARNING("The distress launcher is cooling down!"))
+ to_chat(user, SPAN_WARNING("The distress launcher is cooling down!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(GLOB.security_level == SEC_LEVEL_DELTA)
- to_chat(operator, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
+ to_chat(user, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(GLOB.security_level < SEC_LEVEL_RED)
- to_chat(operator, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!"))
+ to_chat(user, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
for(var/client/admin in GLOB.admins)
if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
- SSticker.mode.request_ert(operator, TRUE)
- to_chat(operator, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command."))
+ SSticker.mode.request_ert(user, TRUE)
+ to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command."))
COOLDOWN_START(datacore, ares_distress_cooldown, COOLDOWN_COMM_REQUEST)
return TRUE
@@ -468,28 +473,50 @@
if(!SSticker.mode)
return FALSE //Not a game mode?
if(world.time < NUCLEAR_TIME_LOCK)
- to_chat(operator, SPAN_WARNING("It is too soon to request Nuclear Ordnance!"))
+ to_chat(user, SPAN_WARNING("It is too soon to request Nuclear Ordnance!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(!COOLDOWN_FINISHED(datacore, ares_nuclear_cooldown))
- to_chat(operator, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!"))
+ to_chat(user, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
if(GLOB.security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame)
- to_chat(operator, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!"))
+ to_chat(user, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!"))
playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
return FALSE
- var/reason = tgui_input_text(operator, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance")
+ var/reason = tgui_input_text(user, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance")
if(!reason)
return FALSE
for(var/client/admin in GLOB.admins)
if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
- message_admins("[key_name(operator)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(operator)] (APPROVE) (DENY) [ADMIN_JMP_USER(operator)] [CC_REPLY(operator)]")
- to_chat(operator, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]"))
+ message_admins("[key_name(user)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(user)] (APPROVE) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]")
+ to_chat(user, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]"))
log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]")
if(ares_can_interface())
ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V")
ai_silent_announcement("Reason given: [reason].", ".V")
COOLDOWN_START(datacore, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT)
return TRUE
+
+ if("trigger_vent")
+ playsound = FALSE
+ var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
+ if(!istype(sec_vent) || sec_vent.welded)
+ to_chat(user, SPAN_WARNING("ERROR: Gas release failure."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown))
+ to_chat(user, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ to_chat(user, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag]."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT)
+ ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].")
+ log_ares_security("Nerve Gas Release", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.")
+ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
+ log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
+
+ if(playsound)
+ playsound(src, "keyboard_alt", 15, 1)
diff --git a/code/game/machinery/ARES/ARES_interface_admin.dm b/code/game/machinery/ARES/ARES_interface_admin.dm
index 5ca7a9ba171d..586b01a51af9 100644
--- a/code/game/machinery/ARES/ARES_interface_admin.dm
+++ b/code/game/machinery/ARES/ARES_interface_admin.dm
@@ -231,6 +231,8 @@
logged_access += list(current_ticket)
data["access_tickets"] = logged_access
+ data["security_vents"] = get_ares_vents()
+
return data
@@ -321,6 +323,9 @@
if("page_tech")
admin_interface.last_menu = admin_interface.current_menu
admin_interface.current_menu = "tech_log"
+ if("page_core_sec")
+ admin_interface.last_menu = admin_interface.current_menu
+ admin_interface.current_menu = "core_security"
if("page_access_management")
admin_interface.last_menu = admin_interface.current_menu
admin_interface.current_menu = "access_management"
@@ -491,3 +496,21 @@
ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [MAIN_AI_SYSTEM].")
to_chat(user, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice]."))
return TRUE
+
+ if("trigger_vent")
+ var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
+ if(!istype(sec_vent) || sec_vent.welded)
+ to_chat(user, SPAN_WARNING("ERROR: Gas release failure."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown))
+ to_chat(user, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ to_chat(user, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag]."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT)
+ ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].")
+ log_ares_security("Nerve Gas Release", "[MAIN_AI_SYSTEM] released Nerve Gas from Vent '[sec_vent.vent_tag]'.")
+ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
+ log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm
index c1c936676dc5..48fcad588574 100644
--- a/code/game/machinery/ARES/ARES_interface_apollo.dm
+++ b/code/game/machinery/ARES/ARES_interface_apollo.dm
@@ -141,6 +141,8 @@
requesting_access += access_ticket.ticket_name
data["access_tickets"] = logged_access
+ data["security_vents"] = link.get_ares_vents()
+
return data
/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state)
@@ -211,6 +213,9 @@
if("page_maintenance")
last_menu = current_menu
current_menu = "maint_claim"
+ if("page_core_gas")
+ last_menu = current_menu
+ current_menu = "core_security_gas"
if("toggle_sound")
notify_sounds = !notify_sounds
@@ -413,6 +418,25 @@
playsound_client(id_owner?.client, 'sound/machines/pda_ping.ogg', src, 25, 0)
return TRUE
+ if("trigger_vent")
+ playsound = FALSE
+ var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
+ if(!istype(sec_vent) || sec_vent.welded)
+ to_chat(operator, SPAN_WARNING("ERROR: Gas release failure."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown))
+ to_chat(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ to_chat(operator, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag]."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT)
+ ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].")
+ log_ares_security("Nerve Gas Release", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.")
+ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
+ log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
+
if(playsound)
playsound(src, "keyboard_alt", 15, 1)
diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm
index 1212d1509a01..05f110ec1a0c 100644
--- a/code/game/machinery/ARES/ARES_procs.dm
+++ b/code/game/machinery/ARES/ARES_procs.dm
@@ -29,6 +29,10 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
var/datum/ares_datacore/datacore
var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list()
+ /// Linked security gas vents.
+ var/list/linked_vents = list()
+ /// The tag number for generated vent labels, if none is manually set.
+ var/tag_num = 1
/// Working Joe stuff
var/list/tickets_maintenance = list()
@@ -50,6 +54,23 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
alert.delink()
..()
+/datum/ares_link/proc/get_ares_vents()
+ var/list/security_vents = list()
+ var/datum/ares_link/link = GLOB.ares_link
+ for(var/obj/structure/pipes/vents/pump/no_boom/gas/vent in link.linked_vents)
+ if(!vent.vent_tag)
+ vent.vent_tag = "Security Vent #[link.tag_num]"
+ link.tag_num++
+
+ var/list/current_vent = list()
+ var/is_available = COOLDOWN_FINISHED(vent, vent_trigger_cooldown)
+ current_vent["vent_tag"] = vent.vent_tag
+ current_vent["ref"] = "\ref[vent]"
+ current_vent["available"] = is_available
+ security_vents += list(current_vent)
+ return security_vents
+
+
/* BELOW ARE IN AdminAres.dm
/datum/ares_link/tgui_interact(mob/user, datum/tgui/ui)
/datum/ares_link/ui_data(mob/user)
@@ -144,11 +165,11 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
var/datum/ares_datacore/datacore = GLOB.ares_datacore
datacore.records_bioscan.Add(new /datum/ares_record/bioscan(title, input))
-/proc/log_ares_bombardment(user_name, ob_name, coordinates)
+/proc/log_ares_bombardment(user_name, ob_name, message)
if(!ares_can_log())
return FALSE
var/datum/ares_datacore/datacore = GLOB.ares_datacore
- datacore.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user_name))
+ datacore.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, message, user_name))
/proc/log_ares_announcement(title, message)
if(!ares_can_log())
diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm
index 69e774cf0da3..e447bb6f7ee7 100644
--- a/code/game/machinery/ARES/apollo_pda.dm
+++ b/code/game/machinery/ARES/apollo_pda.dm
@@ -166,6 +166,8 @@
requesting_access += access_ticket.ticket_name
data["access_tickets"] = logged_access
+ data["security_vents"] = link.get_ares_vents()
+
return data
/obj/item/device/working_joe_pda/ui_status(mob/user, datum/ui_state/state)
@@ -237,6 +239,9 @@
if("page_maintenance")
last_menu = current_menu
current_menu = "maint_claim"
+ if("page_core_gas")
+ last_menu = current_menu
+ current_menu = "core_security_gas"
if("toggle_sound")
notify_sounds = !notify_sounds
@@ -439,6 +444,25 @@
playsound_client(id_owner?.client, 'sound/machines/pda_ping.ogg', src, 25, 0)
return TRUE
+ if("trigger_vent")
+ playsound = FALSE
+ var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"])
+ if(!istype(sec_vent) || sec_vent.welded)
+ to_chat(operator, SPAN_WARNING("ERROR: Gas release failure."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown))
+ to_chat(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ to_chat(operator, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag]."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT)
+ ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].")
+ log_ares_security("Nerve Gas Release", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.")
+ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS)
+ log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.")
+
if(playsound)
var/sound = pick('sound/machines/pda_button1.ogg', 'sound/machines/pda_button2.ogg')
playsound(src, sound, 15, TRUE)
diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm
index 3fa96ca0bc3a..4b68b397116e 100644
--- a/code/game/machinery/kitchen/gibber.dm
+++ b/code/game/machinery/kitchen/gibber.dm
@@ -105,15 +105,28 @@
to_chat(user, SPAN_WARNING("You need a better grip to do that!"))
return
- if(victim.abiotic(1))
+ if(victim.abiotic(TRUE))
to_chat(user, SPAN_WARNING("Subject may not have abiotic items on."))
return
user.visible_message(SPAN_DANGER("[user] starts to put [victim] into the gibber!"))
add_fingerprint(user)
+ ///If synth is getting gibbed, we will 'soft gib' them, but this is still pretty LRP so let admin know.
+ if(issynth(victim) && ishuman_strict(user) && !occupant)
+ var/turf/turf_ref = get_turf(user)
+ var/area/area = get_area(user)
+ message_admins("ALERT: [user] ([user.key]) is trying to shove [victim] in a gibber! (They are a synth, so this will delimb them) ([victim.key]) in [area.name] [ADMIN_JMP(turf_ref)]")
+ log_attack("[key_name(user)] tried to delimb [victim] using a gibber ([victim.key]) in [area.name]")
+ to_chat(user, SPAN_DANGER("What are you doing..."))
+ if(do_after(user, 30 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE && grabbed && grabbed.grabbed_thing && !occupant))
+ user.visible_message(SPAN_DANGER("[user] stuffs [victim] into the gibber!"))
+ victim.forceMove(src)
+ occupant = victim
+ update_icon()
+
///If someone's being LRP and doing funny chef shit, this lets admins know. This *shouldn't* flag preds, though.
- if(ishuman(victim) && ishuman_strict(user) && !occupant)
+ else if(ishuman(victim) && ishuman_strict(user) && !occupant)
var/turf/turf_ref = get_turf(user)
var/area/area = get_area(user)
message_admins("ALERT: [user] ([user.key]) is trying to gib [victim] ([victim.key]) in [area.name] [ADMIN_JMP(turf_ref)]")
@@ -142,18 +155,23 @@
add_fingerprint(usr)
return
-/obj/structure/machinery/gibber/proc/go_out()
+/obj/structure/machinery/gibber/proc/go_out(launch = FALSE)
if (!occupant)
- return
+ return FALSE
for(var/obj/O in src)
O.forceMove(loc)
if (occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.forceMove(loc)
+ if(launch)
+ // yeet them out of the gibber
+ visible_message(SPAN_DANGER("[occupant] suddenly is launched out of the [src]!"))
+ var/turf/Tx = locate(x - 3, y, z)
+ occupant.throw_atom(Tx, 3, SPEED_FAST, src, TRUE)
occupant = null
update_icon()
- return
+ return TRUE
/obj/structure/machinery/gibber/proc/startgibbing(mob/user as mob)
@@ -162,13 +180,18 @@
if(!occupant)
visible_message(SPAN_DANGER("You hear a loud metallic grinding sound."))
return
+ var/synthetic = issynth(occupant)
use_power(1000)
- visible_message(SPAN_DANGER("You hear a loud squelchy grinding sound."))
- operating = 1
+ if(synthetic)
+ visible_message(SPAN_BOLDWARNING("[src] begins to emitt sparks out the top as a banging noise can be heard!"), SPAN_BOLDWARNING("You hear a myriad of loud bangs!"))
+ else
+ visible_message(SPAN_DANGER("You hear a loud squelchy grinding sound."))
+ operating = TRUE
update_icon()
var/totalslabs = 2
+
var/obj/item/reagent_container/food/snacks/meat/meat_template = /obj/item/reagent_container/food/snacks/meat/monkey
if(istype(occupant, /mob/living/carbon/xenomorph))
var/mob/living/carbon/xenomorph/X = occupant
@@ -186,6 +209,35 @@
meat_template = /obj/item/reagent_container/food/snacks/meat/human
totalslabs = 3
+ // Synths only get delimbed from this. 1 meat per limb
+ if(synthetic)
+ meat_template = /obj/item/reagent_container/food/snacks/meat/synthmeat/synthflesh
+ totalslabs = 0
+ var/mob/living/carbon/human/victim = occupant
+
+ // Remove all limbs to allow synth to park closer at the supermarket
+ var/obj/limb/limb
+
+ if(victim.has_limb("l_leg"))
+ limb = victim.get_limb("r_leg")
+ totalslabs += 1
+ limb.droplimb(FALSE, TRUE, "gibber")
+
+ if(victim.has_limb("l_leg"))
+ limb = victim.get_limb("l_leg")
+ totalslabs += 1
+ limb.droplimb(FALSE, TRUE, "gibber")
+
+ if(victim.has_limb("r_arm"))
+ limb = victim.get_limb("r_arm")
+ totalslabs += 1
+ limb.droplimb(FALSE, TRUE, "gibber")
+
+ if(victim.has_limb("l_arm"))
+ limb = victim.get_limb("l_arm")
+ totalslabs += 1
+ limb.droplimb(FALSE, TRUE, "gibber")
+
var/obj/item/reagent_container/food/snacks/meat/allmeat[totalslabs]
for(var/i in 1 to totalslabs)
var/obj/item/reagent_container/food/snacks/meat/newmeat
@@ -194,26 +246,38 @@
newmeat.name = newmeat.made_from_player + newmeat.name
allmeat[i] = newmeat
- if(src.occupant.client) // Gibbed a cow with a client in it? log that shit
- src.occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [key_name(user)]"
+ // Synths wont die to this (on it's own at least), dont log as a gib
+ if(synthetic)
+ if(occupant.client) // Log still
+ occupant.attack_log += "\[[time_stamp()]\] Was delimbed by [key_name(user)]"
+ user.attack_log += "\[[time_stamp()]\] delimbed [key_name(occupant)]"
+ msg_admin_attack("[key_name(user)] delimbed [key_name(occupant)] with a gibber in [user.loc.name]([user.x], [user.y], [user.z]).", user.x, user.y, user.z)
+ continue
+
+ if(occupant.client) // Gibbed a cow with a client in it? log that shit
+ occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [key_name(user)]"
user.attack_log += "\[[time_stamp()]\] Gibbed [key_name(occupant)]"
msg_admin_attack("[key_name(user)] gibbed [key_name(occupant)] in [user.loc.name] ([user.x], [user.y], [user.z]).", user.x, user.y, user.z)
- src.occupant.death(create_cause_data("gibber", user), TRUE)
- src.occupant.ghostize()
+ occupant.death(create_cause_data("gibber", user), TRUE)
+ occupant.ghostize()
- QDEL_NULL(occupant)
+ if(synthetic)
+ to_chat(occupant, SPAN_HIGHDANGER("You can detect your limbs being ripped off your body, but it begins to malfunction as it reaches your torso!"))
+ addtimer(CALLBACK(src, PROC_REF(create_gibs), totalslabs, allmeat), gibtime)
+ addtimer(CALLBACK(src, PROC_REF(go_out), TRUE), gibtime)
+ return
- addtimer(CALLBACK(src, PROC_REF(create_gibs), totalslabs, allmeat), gibtime)
+ QDEL_NULL(occupant)
/obj/structure/machinery/gibber/proc/create_gibs(totalslabs, list/obj/item/reagent_container/food/snacks/allmeat)
playsound(loc, 'sound/effects/splat.ogg', 25, 1)
operating = FALSE
+ var/turf/Tx = locate(x - 1, y, z)
for (var/i in 1 to totalslabs)
var/obj/item/meatslab = allmeat[i]
- var/turf/Tx = locate(x - i, y, z)
meatslab.forceMove(loc)
- meatslab.throw_atom(Tx, i, SPEED_FAST, src)
+ meatslab.throw_atom(Tx, 1, SPEED_FAST, src)
if (!Tx.density)
if(istype(meatslab, /obj/item/reagent_container/food/snacks/meat/xenomeat))
new /obj/effect/decal/cleanable/blood/gibs/xeno(Tx)
diff --git a/code/game/objects/effects/effect_system/foam.dm b/code/game/objects/effects/effect_system/foam.dm
index 525cb8c731a9..7a06fa50619c 100644
--- a/code/game/objects/effects/effect_system/foam.dm
+++ b/code/game/objects/effects/effect_system/foam.dm
@@ -20,6 +20,7 @@
var/expand = 1
animate_movement = 0
var/metal = FOAM_NOT_METAL
+ var/time_to_solidify = 4 SECONDS
/obj/effect/particle_effect/foam/Initialize(mapload, ismetal=0)
@@ -28,7 +29,7 @@
metal = ismetal
playsound(src, 'sound/effects/bubbles2.ogg', 25, 1, 5)
addtimer(CALLBACK(src, PROC_REF(foam_react)), 3 + metal*3)
- addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), 40)
+ addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), time_to_solidify)
/obj/effect/particle_effect/foam/proc/foam_react()
process()
diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm
index c9e404ae5b60..6e3869f563a4 100644
--- a/code/game/objects/effects/effect_system/smoke.dm
+++ b/code/game/objects/effects/effect_system/smoke.dm
@@ -240,9 +240,9 @@
if(isyautja(M) || isxeno(M))
burn_damage *= xeno_yautja_reduction
+ var/reagent = new /datum/reagent/napalm/ut()
M.burn_skin(burn_damage)
- M.adjust_fire_stacks(applied_fire_stacks)
- M.fire_reagent = new /datum/reagent/napalm/ut()
+ M.adjust_fire_stacks(applied_fire_stacks, reagent)
M.IgniteMob()
M.updatehealth()
@@ -316,7 +316,7 @@
if(xeno_affecting)
stun_chance = 35
if(prob(stun_chance))
- creature.apply_effect(1, WEAKEN)
+ creature.apply_effect(2, WEAKEN)
//Topical damage (neurotoxin on exposed skin)
if(xeno_creature)
diff --git a/code/game/objects/effects/landmarks/survivor_spawner.dm b/code/game/objects/effects/landmarks/survivor_spawner.dm
index 803d73151aeb..4a6e5272ed05 100644
--- a/code/game/objects/effects/landmarks/survivor_spawner.dm
+++ b/code/game/objects/effects/landmarks/survivor_spawner.dm
@@ -201,8 +201,8 @@
//CMB Survivors//
/obj/effect/landmark/survivor_spawner/fiorina_armory_cmb
- equipment = /datum/equipment_preset/survivor/colonial_marshal
- synth_equipment = /datum/equipment_preset/synth/survivor/cmb_synth
+ equipment = /datum/equipment_preset/survivor/cmb/standard
+ synth_equipment = /datum/equipment_preset/synth/survivor/cmb/synth
intro_text = list("
You are a CMB Deputy!
",\
"You are aware of the 'alien' threat.",\
"Your primary objective is to survive the infestation.")
@@ -211,8 +211,8 @@
spawn_priority = SPAWN_PRIORITY_VERY_HIGH
/obj/effect/landmark/survivor_spawner/fiorina_armory_riot_control
- equipment = /datum/equipment_preset/survivor/colonial_marshal/fiorina
- synth_equipment = /datum/equipment_preset/synth/survivor/cmb_synth
+ equipment = /datum/equipment_preset/survivor/cmb/ua
+ synth_equipment = /datum/equipment_preset/synth/survivor/cmb/ua_synth
intro_text = list("
You are a United Americas Riot Control Officer!
",\
"You are aware of the 'alien' threat.",\
"Your primary objective is to survive the infestation.")
diff --git a/code/game/objects/items/reagent_containers/food/snacks/meat.dm b/code/game/objects/items/reagent_containers/food/snacks/meat.dm
index f68f488f268d..f541986112e5 100644
--- a/code/game/objects/items/reagent_containers/food/snacks/meat.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks/meat.dm
@@ -28,7 +28,8 @@
name = "synthetic meat"
desc = "A synthetic slab of flesh."
-/obj/item/reagent_container/food/snacks/meat/synthmeat/synthflesh //meat made from synthetics. Slightly toxic
+/// Meat made from synthetics. Slightly toxic
+/obj/item/reagent_container/food/snacks/meat/synthmeat/synthflesh
name = "synthetic flesh"
desc = "A slab of artificial, inorganic 'flesh' that resembles human meat. Probably came from a synth."
icon_state = "synthmeat"
diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm
index fc8d03f5d24d..e0f432bd5b09 100644
--- a/code/game/objects/items/reagent_containers/glass.dm
+++ b/code/game/objects/items/reagent_containers/glass.dm
@@ -365,6 +365,14 @@
ground_offset_x = 9
ground_offset_y = 8
+/obj/item/reagent_container/glass/beaker/vial/epinephrine
+ name = "epinephrine vial"
+
+/obj/item/reagent_container/glass/beaker/vial/epinephrine/Initialize()
+ . = ..()
+ reagents.add_reagent("adrenaline", 30)
+ update_icon()
+
/obj/item/reagent_container/glass/beaker/vial/tricordrazine
name = "tricordrazine vial"
diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm
index 9e0215b535b6..61cdee01c8f8 100644
--- a/code/game/objects/items/reagent_containers/glass/bottle.dm
+++ b/code/game/objects/items/reagent_containers/glass/bottle.dm
@@ -396,3 +396,13 @@
. = ..()
reagents.add_reagent("tricordrazine", 60)
update_icon()
+
+/obj/item/reagent_container/glass/bottle/epinephrine
+ name = "\improper Epinephrine bottle"
+ desc = "A small bottle. Contains epinephrine - Used to increase a patients arterial blood pressure, amongst other actions, to assist in cardiopulmonary resuscitation." //"I can't lie to you about your odds of a successful resuscitation, but you have my sympathies"
+ volume = 60
+
+/obj/item/reagent_container/glass/bottle/epinephrine/Initialize()
+ . = ..()
+ reagents.add_reagent("adrenaline", 60)
+ update_icon()
diff --git a/code/game/objects/items/reagent_containers/hypospray.dm b/code/game/objects/items/reagent_containers/hypospray.dm
index 5e268d35a33d..05b76568d702 100644
--- a/code/game/objects/items/reagent_containers/hypospray.dm
+++ b/code/game/objects/items/reagent_containers/hypospray.dm
@@ -237,6 +237,9 @@
/obj/item/reagent_container/hypospray/tricordrazine
starting_vial = /obj/item/reagent_container/glass/beaker/vial/tricordrazine
+/obj/item/reagent_container/hypospray/epinephrine
+ starting_vial = /obj/item/reagent_container/glass/beaker/vial/epinephrine
+
/obj/item/reagent_container/hypospray/sedative
name = "Sedative Hypospray"
starting_vial = /obj/item/reagent_container/glass/beaker/vial/sedative
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index a977eb880ff5..1daffa2908f0 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -319,6 +319,29 @@
new /obj/item/storage/pill_bottle/inaprovaline(src)
new /obj/item/storage/pill_bottle/tramadol(src)
+/obj/item/storage/belt/medical/lifesaver/upp/synth/fill_preset_inventory()
+ new /obj/item/storage/pill_bottle/bicaridine(src)
+ new /obj/item/storage/pill_bottle/bicaridine(src)
+ new /obj/item/storage/pill_bottle/kelotane(src)
+ new /obj/item/storage/pill_bottle/kelotane(src)
+ new /obj/item/storage/pill_bottle/tramadol(src)
+ new /obj/item/storage/pill_bottle/tramadol(src)
+ new /obj/item/storage/pill_bottle/antitox(src)
+ new /obj/item/storage/pill_bottle/alkysine(src)
+ new /obj/item/storage/pill_bottle/imidazoline(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/dexalinp(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/oxycodone(src)
+ new /obj/item/device/healthanalyzer(src)
+
/obj/item/storage/belt/security
name = "\improper M276 pattern security rig"
desc = "The M276 is the standard load-bearing equipment of the USCM. It consists of a modular belt with various clips. This configuration is commonly seen among USCM Military Police and peacekeepers, though it can hold some light munitions."
@@ -383,6 +406,13 @@
new /obj/item/reagent_container/spray/pepper(src)
new /obj/item/device/clue_scanner(src)
+/obj/item/storage/belt/security/MP/full/synth/fill_preset_inventory()
+ new /obj/item/explosive/grenade/flashbang(src)
+ new /obj/item/device/flash(src)
+ new /obj/item/weapon/baton(src)
+ new /obj/item/reagent_container/spray/pepper(src)
+ new /obj/item/device/clue_scanner(src)
+ new /obj/item/handcuffs(src)
/obj/item/storage/belt/security/MP/UPP
name = "\improper Type 43 military police rig"
diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm
index c3df7547776d..1b75a1a7d89d 100644
--- a/code/game/objects/items/storage/pouch.dm
+++ b/code/game/objects/items/storage/pouch.dm
@@ -1272,6 +1272,21 @@
new /obj/item/explosive/plastic(src)
new /obj/item/explosive/plastic(src)
+/obj/item/storage/pouch/tools/tactical/upp
+ name = "synthetic tools pouch"
+ desc = "Special issue tools pouch for UPP synthetics. Due to the enhanced strength of the synthetic and its inability to feel discomfort, this pouch is designed to maximize internal space with no concern for its wearer's comfort."
+ icon_state = "tools"
+ storage_slots = 7
+
+/obj/item/storage/pouch/tools/tactical/upp/fill_preset_inventory()
+ new /obj/item/tool/wrench(src)
+ new /obj/item/tool/crowbar(src)
+ new /obj/item/tool/wirecutters(src)
+ new /obj/item/device/multitool(src)
+ new /obj/item/tool/weldingtool(src)
+ new /obj/item/stack/cable_coil(src)
+ new /obj/item/stack/cable_coil(src)
+
/obj/item/storage/pouch/tools/uppsynth/fill_preset_inventory()
new /obj/item/tool/crowbar(src)
new /obj/item/tool/wirecutters(src)
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 0497a410a373..92400e2d3184 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -89,7 +89,7 @@
/obj/item/weapon/shield/riot/attackby(obj/item/W as obj, mob/user as mob)
if(cooldown < world.time - 25)
- if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/sword) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand))
+ if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/sword) || istype(W, /obj/item/weapon/telebaton) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/classic_baton) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand))
user.visible_message(SPAN_WARNING("[user] bashes [src] with [W]!"))
playsound(user.loc, 'sound/effects/shieldbash.ogg', 25, 1)
cooldown = world.time
diff --git a/code/game/objects/structures/pipes/vents/pump_scrubber.dm b/code/game/objects/structures/pipes/vents/pump_scrubber.dm
index a4565c610ad5..acc8b4784af9 100644
--- a/code/game/objects/structures/pipes/vents/pump_scrubber.dm
+++ b/code/game/objects/structures/pipes/vents/pump_scrubber.dm
@@ -21,6 +21,35 @@
name = "Reinforced Air Vent"
explodey = FALSE
+/// Vents that are linked to ARES Security Protocols, allowing the ARES Interface to trigger security measures.
+/obj/structure/pipes/vents/pump/no_boom/gas
+ name = "Security Air Vent"
+ var/datum/ares_link/link
+ var/vent_tag
+ COOLDOWN_DECLARE(vent_trigger_cooldown)
+
+/obj/structure/pipes/vents/pump/no_boom/gas/Initialize()
+ link_systems(override = FALSE)
+ . = ..()
+
+/obj/structure/pipes/vents/pump/no_boom/gas/Destroy()
+ delink()
+ return ..()
+
+/obj/structure/pipes/vents/pump/no_boom/gas/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ if(link && !override)
+ return FALSE
+ delink()
+ if(new_link)
+ link = new_link
+ new_link.linked_vents += src
+ return TRUE
+
+/obj/structure/pipes/vents/pump/no_boom/gas/proc/delink()
+ if(link)
+ link.linked_vents -= src
+ link = null
+
/obj/structure/pipes/vents/pump/on
icon_state = "on"
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index ce02cdb59e20..84298faaa3a1 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -543,27 +543,28 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
log_ahelp(id, "Defer", "Deferred to mentors by [usr.key]", null, usr.ckey)
Close(silent = TRUE)
-/datum/admin_help/proc/mark_ticket()
+/datum/admin_help/proc/mark_ticket(mob/marking_admin)
+ var/mob/user = marking_admin || usr
if(marked_admin)
- if(marked_admin == usr.ckey)
+ if(marked_admin == user.ckey)
unmark_ticket()
return
- to_chat(usr, SPAN_WARNING("This ticket has already been marked by [marked_admin]."))
- var/unmark_option = tgui_alert(usr, "This message has been marked by [marked_admin]. Do you want to override?", "Marked Ticket", list("Overwrite Mark", "Unmark", "Cancel"))
+ to_chat(user, SPAN_WARNING("This ticket has already been marked by [marked_admin]."))
+ var/unmark_option = tgui_alert(user, "This message has been marked by [marked_admin]. Do you want to override?", "Marked Ticket", list("Overwrite Mark", "Unmark", "Cancel"))
if(unmark_option == "Unmark")
unmark_ticket()
return
if(unmark_option != "Overwrite Mark")
return
- var/key_name = key_name_admin(usr)
+ var/key_name = key_name_admin(user)
AddInteraction("Marked by [key_name].", player_message = "Ticket marked!")
to_chat(initiator, SPAN_ADMINHELP("An admin is preparing to respond to your ticket."))
var/msg = "Ticket [TicketHref("#[id]")] marked by [key_name]."
message_admins(msg)
log_admin_private(msg)
- log_ahelp(id, "Marked", "Marked by [usr.key]", sender = usr.ckey)
- marked_admin = usr.ckey
+ log_ahelp(id, "Marked", "Marked by [user.key]", sender = user.ckey)
+ marked_admin = user.ckey
/datum/admin_help/proc/unmark_ticket()
var/key_name = key_name_admin(usr)
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index 76525b2cae96..a6cf0f02a3de 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -60,6 +60,9 @@
var/message_prompt = "Message:"
+ if(AH && !AH.marked_admin)
+ AH.mark_ticket()
+
if((AH?.opening_responders && length(AH.ticket_interactions) == 1 ) || ((AH?.marked_admin && AH?.marked_admin != usr.ckey) && length(AH.ticket_interactions) == 2))
SEND_SOUND(src, sound('sound/machines/buzz-sigh.ogg', volume=30))
message_prompt += "\n\n**This ticket is already being responded to by: [length(AH.opening_responders) ? english_list(AH.opening_responders) : AH.marked_admin]**"
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 63cdcfd8716c..213c54f0e201 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -5,8 +5,6 @@
#define UPLOAD_LIMIT 10485760 //Restricts client uploads to the server to 10MB //Boosted this thing. What's the worst that can happen?
#define MIN_CLIENT_VERSION 0 //Just an ambiguously low version for now, I don't want to suddenly stop people playing.
//I would just like the code ready should it ever need to be used.
-#define GOOD_BYOND_MAJOR 513
-#define GOOD_BYOND_MINOR 1500
GLOBAL_LIST_INIT(blacklisted_builds, list(
"1407" = "bug preventing client display overrides from working leads to clients being able to see things/mobs they shouldn't be able to see",
@@ -364,14 +362,34 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list(
INVOKE_ASYNC(src, /client/proc/set_macros)
// Version check below if we ever need to start checking against BYOND versions again.
-
- /*if((byond_version < world.byond_version) || ((byond_version == world.byond_version) && (byond_build < world.byond_build)))
- src << "Your version of Byond (v[byond_version].[byond_build]) differs from the server (v[world.byond_version].[world.byond_build]). You may experience graphical glitches, crashes, or other errors. You will be disconnected until your version matches or exceeds the server version. \
- Direct Download (Windows Installer): http://www.byond.com/download/build/[world.byond_version]/[world.byond_version].[world.byond_build]_byond.exe \
- Other versions (search for [world.byond_build] or higher): http://www.byond.com/download/build/[world.byond_version]"
+ var/breaking_version = CONFIG_GET(number/client_error_version)
+ var/breaking_build = CONFIG_GET(number/client_error_build)
+ var/warn_version = CONFIG_GET(number/client_warn_version)
+ var/warn_build = CONFIG_GET(number/client_warn_build)
+
+ if (byond_version < breaking_version || (byond_version == breaking_version && byond_build < breaking_build)) //Out of date client.
+ to_chat_immediate(src, SPAN_DANGER("Your version of BYOND is too old:"))
+ to_chat_immediate(src, CONFIG_GET(string/client_error_message))
+ to_chat_immediate(src, "Your version: [byond_version].[byond_build]")
+ to_chat_immediate(src, "Required version: [breaking_version].[breaking_build] or later")
+ to_chat_immediate(src, "Visit BYOND's website to get the latest version of BYOND.")
qdel(src)
- return*/
- //hardcode for now
+ return
+
+ if (byond_version < warn_version || (byond_version == warn_version && byond_build < warn_build)) //We have words for this client.
+ if(CONFIG_GET(flag/client_warn_popup))
+ var/msg = "Your version of BYOND may be getting out of date: "
+ msg += CONFIG_GET(string/client_warn_message) + "
"
+ msg += "Your version: [byond_version].[byond_build] "
+ msg += "Required version to remove this message: [warn_version].[warn_build] or later "
+ msg += "Visit BYOND's website to get the latest version of BYOND. "
+ src << browse(msg, "window=warning_popup")
+ else
+ to_chat(src, SPAN_DANGER("Your version of BYOND may be getting out of date:"))
+ to_chat(src, CONFIG_GET(string/client_warn_message))
+ to_chat(src, "Your version: [byond_version].[byond_build]")
+ to_chat(src, "Required version to remove this message: [warn_version].[warn_build] or later")
+ to_chat(src, "Visit BYOND's website to get the latest version of BYOND.")
if (num2text(byond_build) in GLOB.blacklisted_builds)
log_access("Failed login: [key] - blacklisted byond build ([byond_version].[byond_build])")
@@ -382,10 +400,6 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list(
qdel(src)
return
- //do this check after the blacklist check to avoid confusion
- if((byond_version < GOOD_BYOND_MAJOR) || ((byond_version == GOOD_BYOND_MAJOR) && (byond_build < GOOD_BYOND_MINOR)))
- to_chat(src, FONT_SIZE_HUGE(SPAN_BOLDNOTICE("YOUR BYOND VERSION IS NOT WELL SUITED FOR THIS SERVER. Download latest BETA build or you may suffer random crashes or disconnects.")))
-
// Initialize tgui panel
stat_panel.initialize(
inline_html = file("html/statbrowser.html"),
diff --git a/code/modules/clothing/suits/marine_armor/ert.dm b/code/modules/clothing/suits/marine_armor/ert.dm
index 6d2ad9934a40..106b09961103 100644
--- a/code/modules/clothing/suits/marine_armor/ert.dm
+++ b/code/modules/clothing/suits/marine_armor/ert.dm
@@ -287,6 +287,22 @@
armor_rad = CLOTHING_ARMOR_MEDIUMLOW
armor_internaldamage = CLOTHING_ARMOR_HIGH
+/obj/item/clothing/suit/storage/marine/faction/UPP/support/synth
+ name = "\improper UL6 Synthetic personal armor"
+ desc = "Modified variant of the UL6 personel armor system intended to be useable by Synthetic units. Offers no protection but very little movement impairment."
+ flags_marine_armor = ARMOR_LAMP_OVERLAY|SYNTH_ALLOWED
+ armor_melee = CLOTHING_ARMOR_NONE
+ armor_bullet = CLOTHING_ARMOR_NONE
+ armor_laser = CLOTHING_ARMOR_NONE
+ armor_energy = CLOTHING_ARMOR_NONE
+ armor_bomb = CLOTHING_ARMOR_NONE
+ armor_bio = CLOTHING_ARMOR_NONE
+ armor_rad = CLOTHING_ARMOR_NONE
+ armor_internaldamage = CLOTHING_ARMOR_NONE
+ slowdown = SLOWDOWN_ARMOR_VERY_LIGHT
+ time_to_unequip = 0.5 SECONDS
+ time_to_equip = 1 SECONDS
+
/obj/item/clothing/suit/storage/marine/faction/UPP/commando
name = "\improper UM5CU personal armor"
desc = "A modification of the UM5, designed for stealth operations."
@@ -731,6 +747,22 @@
uniform_restricted = list(/obj/item/clothing/under/marine/ua_riot)
flags_atom = NO_SNOW_TYPE
+/obj/item/clothing/suit/storage/marine/veteran/ua_riot/synth
+ name = "\improper UA-M1S Synthetic body armor"
+ desc = "Based on the M-3 pattern employed by the USCM, the UA-M1 body armor is employed by UA security, riot control and union-busting teams. The UA-1MS modification is Synthetic programming compliant, sacrificing protection for speed and carrying capacity."
+ armor_melee = CLOTHING_ARMOR_NONE
+ armor_bullet = CLOTHING_ARMOR_NONE
+ armor_laser = CLOTHING_ARMOR_NONE
+ armor_energy = CLOTHING_ARMOR_NONE
+ armor_bomb = CLOTHING_ARMOR_NONE
+ armor_bio = CLOTHING_ARMOR_NONE
+ armor_rad = CLOTHING_ARMOR_NONE
+ armor_internaldamage = CLOTHING_ARMOR_NONE
+ slowdown = SLOWDOWN_ARMOR_SUPER_LIGHT
+ storage_slots = 3
+ flags_atom = NO_SNOW_TYPE|NO_NAME_OVERRIDE
+ flags_marine_armor = ARMOR_SQUAD_OVERLAY|ARMOR_LAMP_OVERLAY|SYNTH_ALLOWED
+
//================//=ROYAL MARINES=\\====================================\\
//=======================================================================\\
diff --git a/code/modules/clothing/under/ties.dm b/code/modules/clothing/under/ties.dm
index 413c2edda0c7..d95c0a593d34 100644
--- a/code/modules/clothing/under/ties.dm
+++ b/code/modules/clothing/under/ties.dm
@@ -676,6 +676,25 @@
/obj/item/clothing/accessory/storage/surg_vest/drop_green/equipped
hold = /obj/item/storage/internal/accessory/surg_vest/equipped
+/obj/item/clothing/accessory/storage/surg_vest/drop_green/upp
+ hold = /obj/item/storage/internal/accessory/surg_vest/drop_green/upp
+
+/obj/item/storage/internal/accessory/surg_vest/drop_green/upp/fill_preset_inventory()
+ new /obj/item/tool/surgery/scalpel(src)
+ new /obj/item/tool/surgery/hemostat(src)
+ new /obj/item/tool/surgery/retractor(src)
+ new /obj/item/tool/surgery/cautery(src)
+ new /obj/item/tool/surgery/circular_saw(src)
+ new /obj/item/tool/surgery/surgicaldrill(src)
+ new /obj/item/tool/surgery/scalpel/pict_system(src)
+ new /obj/item/tool/surgery/bonesetter(src)
+ new /obj/item/tool/surgery/FixOVein(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/nanopaste(src)
+ new /obj/item/tool/surgery/bonegel(src)
+ new /obj/item/tool/surgery/bonegel(src)
+ new /obj/item/reagent_container/blood/OMinus(src)
+
/obj/item/clothing/accessory/storage/surg_vest/drop_black
name = "black surgical drop pouch"
desc = "A tactical black synthcotton drop pouch purpose-made for holding surgical tools."
diff --git a/code/modules/cm_marines/marines_consoles.dm b/code/modules/cm_marines/marines_consoles.dm
index 7e57430f081a..e02bb930d416 100644
--- a/code/modules/cm_marines/marines_consoles.dm
+++ b/code/modules/cm_marines/marines_consoles.dm
@@ -43,12 +43,12 @@
ui = new(user, src, "CardMod", name)
ui.open()
-/obj/structure/machinery/computer/card/ui_act(action, params)
+/obj/structure/machinery/computer/card/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- var/mob/user = usr
+ var/mob/user = ui.user
playsound(src, pick('sound/machines/computer_typing4.ogg', 'sound/machines/computer_typing5.ogg', 'sound/machines/computer_typing6.ogg'), 5, 1)
switch(action)
@@ -91,18 +91,11 @@
printing = TRUE
playsound(src.loc, 'sound/machines/fax.ogg', 15, 1)
sleep(40)
- var/faction = "N/A"
- if(target_id_card.faction_group && islist(target_id_card.faction_group))
- faction = jointext(target_id_card.faction_group, ", ")
- if(isnull(target_id_card.faction_group))
- target_id_card.faction_group = list()
- else
- faction = target_id_card.faction_group
var/contents = {"