diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm
index cd0c9955c1..401029c962 100644
--- a/code/__defines/gamemode.dm
+++ b/code/__defines/gamemode.dm
@@ -84,6 +84,7 @@ var/list/be_special_flags = list(
#define MODE_MALFUNCTION "malf"
#define MODE_TRAITOR "traitor"
#define MODE_AUTOTRAITOR "autotraitor"
+#define MODE_INFILTRATOR "infiltrator"
#define DEFAULT_TELECRYSTAL_AMOUNT 120
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index fb99da896f..ddcae4980b 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -281,15 +281,15 @@
//A list of every mob with a client
for(var/mob in player_list)
- if(isnull(mob)) //VOREStation Add - Fix for a weird bug with nulls in this list
- player_list -= mob //VOREStation Add
- continue //VOREStation Add
+ if(!istype(mob, /mob))
+ crash_with("There is a null or non-mob reference inside player_list.")
+ continue
if(get_turf(mob) in hearturfs)
mobs |= mob
continue
var/mob/M = mob
- if(M.stat == DEAD && !M.forbid_seeing_deadchat)
+ if(M && M.stat == DEAD && !M.forbid_seeing_deadchat)
switch(type)
if(1) //Audio messages use ghost_ears
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm
index 26cc136ccc..b1029e0391 100644
--- a/code/controllers/Processes/inactivity.dm
+++ b/code/controllers/Processes/inactivity.dm
@@ -6,7 +6,7 @@
if(config.kick_inactive)
for(last_object in clients)
var/client/C = last_object
- if(!C.holder && C.is_afk(config.kick_inactive MINUTES))
+ if(C.is_afk(config.kick_inactive MINUTES))
if(!istype(C.mob, /mob/observer/dead))
log_access("AFK: [key_name(C)]")
C << "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected."
diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm
index b40bf27e47..769aa0b2b6 100644
--- a/code/datums/autolathe/arms.dm
+++ b/code/datums/autolathe/arms.dm
@@ -132,9 +132,9 @@
path =/obj/item/ammo_magazine/m10mm
hidden = 1
-/datum/category_item/autolathe/arms/pistol_50
- name = "pistol magazine (.50AE)"
- path =/obj/item/ammo_magazine/m50
+/datum/category_item/autolathe/arms/pistol_44
+ name = "pistol magazine (.44)"
+ path =/obj/item/ammo_magazine/m44
hidden = 1
/////// 5.56mm
@@ -225,9 +225,9 @@
category = "Arms and Ammunition"
hidden = 1
-/datum/category_item/autolathe/arms/pistol_50
- name = "pistol magazine (.50AE)"
- path =/obj/item/ammo_magazine/m50/empty
+/datum/category_item/autolathe/arms/pistol_44
+ name = "pistol magazine (.44)"
+ path =/obj/item/ammo_magazine/m44/empty
category = "Arms and Ammunition"
hidden = 1
@@ -340,7 +340,7 @@
hidden = 1
/datum/category_item/autolathe/arms/pistol_clip_50
- name = "ammo clip (.50AE)"
+ name = "ammo clip (.44)"
path =/obj/item/ammo_magazine/clip/c50
category = "Arms and Ammunition"
hidden = 1
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 11d622b255..0b524befec 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -490,6 +490,8 @@
world.log << "## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn"
if(!mind.name) mind.name = real_name
mind.current = src
+ if(player_is_antag(mind))
+ src.client.verbs += /client/proc/aooc
//HUMAN
/mob/living/carbon/human/mind_initialize()
diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm
index dc49b380dc..1b7207069e 100644
--- a/code/datums/supplypacks/medical.dm
+++ b/code/datums/supplypacks/medical.dm
@@ -331,7 +331,7 @@
/datum/supply_packs/med/defib
name = "Defibrilator crate"
- contains = list(/obj/item/device/defib_kit = 4)
+ contains = list(/obj/item/device/defib_kit = 2)
cost = 30
containertype = /obj/structure/closet/crate/medical
containername = "Defibrilator crate"
\ No newline at end of file
diff --git a/code/datums/supplypacks/robotics.dm b/code/datums/supplypacks/robotics.dm
index 0f1a0c3b66..8f0ed6d452 100644
--- a/code/datums/supplypacks/robotics.dm
+++ b/code/datums/supplypacks/robotics.dm
@@ -159,7 +159,7 @@
/obj/item/device/kit/paint/gygax/recitence
)
name = "Random Gygax exosuit modkit"
-
+/*
/datum/supply_packs/robotics/jumper_cables
name = "Jumper kit crate"
contains = list(
@@ -168,4 +168,5 @@
cost = 30
containertype = /obj/structure/closet/crate/secure/science
containername = "Jumper kit crate"
- access = access_robotics
\ No newline at end of file
+ access = access_robotics
+*/
\ No newline at end of file
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 44d32bfecb..4b2afa1df3 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -79,6 +79,8 @@
Think through your actions and make the roleplay immersive! Please remember all \
rules aside from those without explicit exceptions apply to antagonists."
+ var/can_use_aooc = TRUE // If true, will be given the AOOC verb, along with the ability to use it.
+
/datum/antagonist/New()
..()
cur_max = hard_cap
diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm
index e42888737f..67eb7e2e72 100644
--- a/code/game/antagonist/antagonist_add.dm
+++ b/code/game/antagonist/antagonist_add.dm
@@ -36,6 +36,9 @@
and it otherwise has no bearing on your round."
player.current.verbs |= /mob/living/proc/write_ambition
+ if(can_use_aooc)
+ player.current.client.verbs += /client/proc/aooc
+
// Handle only adding a mind and not bothering with gear etc.
if(nonstandard_role_type)
faction_members |= player
@@ -58,6 +61,7 @@
BITSET(player.current.hud_updateflag, SPECIALROLE_HUD)
if(!is_special_character(player))
player.current.verbs -= /mob/living/proc/write_ambition
+ player.current.client.verbs -= /client/proc/aooc
player.ambitions = ""
return 1
return 0
\ No newline at end of file
diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm
index b176df2467..c1aec2bcf8 100644
--- a/code/game/antagonist/outsider/ert.dm
+++ b/code/game/antagonist/outsider/ert.dm
@@ -25,6 +25,8 @@ var/datum/antagonist/ert/ert
initial_spawn_req = 5
initial_spawn_target = 7
+ can_use_aooc = FALSE // They're the good guys.
+
/datum/antagonist/ert/create_default(var/mob/source)
var/mob/living/carbon/human/M = ..()
if(istype(M)) M.age = rand(25,45)
diff --git a/code/game/antagonist/outsider/trader.dm b/code/game/antagonist/outsider/trader.dm
index aaf573cd20..9603b49523 100644
--- a/code/game/antagonist/outsider/trader.dm
+++ b/code/game/antagonist/outsider/trader.dm
@@ -24,6 +24,8 @@ var/datum/antagonist/trader/traders
initial_spawn_req = 5
initial_spawn_target = 7
+ can_use_aooc = FALSE // They're not real antags.
+
/datum/antagonist/trader/create_default(var/mob/source)
var/mob/living/carbon/human/M = ..()
if(istype(M)) M.age = rand(25,45)
diff --git a/code/game/antagonist/station/infiltrator.dm b/code/game/antagonist/station/infiltrator.dm
new file mode 100644
index 0000000000..81430c0006
--- /dev/null
+++ b/code/game/antagonist/station/infiltrator.dm
@@ -0,0 +1,78 @@
+// Infiltrator is a varient of Traitor, except that the traitors are in a team and can communicate with a special headset.
+
+var/datum/antagonist/traitor/infiltrator/infiltrators
+
+// Inherits most of its vars from the base datum.
+/datum/antagonist/traitor/infiltrator
+ id = MODE_INFILTRATOR
+ role_type = BE_TRAITOR
+ antag_indicator = "synd"
+ antaghud_indicator = "hudinfiltrator"
+ role_text = "Infiltrator"
+ role_text_plural = "Infiltrators"
+ welcome_text = "To speak on your team's private channel, use :t."
+ protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Colony Director")
+ flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
+
+/datum/antagonist/traitor/infiltrator/New()
+ ..()
+ infiltrators = src
+
+/datum/antagonist/traitor/infiltrator/equip(var/mob/living/carbon/human/traitor_mob)
+ ..() // Give the uplink and other stuff.
+ // Now for the special headset.
+
+ // Humans and the AI.
+ if(istype(traitor_mob) || istype(traitor_mob, /mob/living/silicon/ai))
+ var/obj/item/device/radio/headset/R
+ R = locate(/obj/item/device/radio/headset) in traitor_mob.contents
+ if(!R)
+ to_chat(traitor_mob, "Unfortunately, a headset could not be found. You have been given an encryption key \
+ to put into a new headset. Once that is done, you can talk to your team using :t")
+ var/obj/item/device/encryptionkey/syndicate/encrypt_key = new(null)
+ traitor_mob.equip_to_slot_or_del(encrypt_key, slot_in_backpack)
+ else
+ var/obj/item/device/encryptionkey/syndicate/encrypt_key = new(null)
+ if(R.keyslot1 && R.keyslot2) // No room.
+ to_chat(traitor_mob, "Unfortunately, your headset cannot accept anymore encryption keys. You have been given an encryption key \
+ to put into a headset after making some room instead. Once that is done, you can talk to your team using :t")
+ traitor_mob.equip_to_slot_or_del(encrypt_key, slot_in_backpack)
+ else
+ if(R.keyslot1)
+ R.keyslot2 = encrypt_key
+ else
+ R.keyslot1 = encrypt_key
+
+ encrypt_key.forceMove(R)
+ R.recalculateChannels()
+ to_chat(traitor_mob, "Your headset has had a special encryption key installed, which allows you to talk to your team privately, using \
+ :t")
+
+ // Borgs, because their radio is not a headset for some reason.
+ if(istype(traitor_mob, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/borg = traitor_mob
+ var/obj/item/device/encryptionkey/syndicate/encrypt_key = new(null)
+ if(borg.radio)
+ if(borg.radio.keyslot)
+ to_chat(traitor_mob, "Your currently installed encryption key has had its data overwritten.")
+ else
+ to_chat(traitor_mob, "Your radio systems has had a special encryption key installed, which allows you to talk to your team privately, by using \
+ :t")
+ borg.radio.keyslot = encrypt_key // Might replace an already existing key, but oh well.
+ borg.radio.recalculateChannels()
+ else // Something bugged.
+ to_chat(traitor_mob, "You do not appear to have a radio installed. This is probably a bug and you should adminhelp.")
+
+
+
+
+
+/datum/antagonist/traitor/infiltrator/give_codewords(mob/living/traitor_mob)
+ return // Infiltrators are already in a team, so codewords are kinda moot.
+
+/datum/antagonist/traitor/infiltrator/add_law_zero(mob/living/silicon/ai/killer)
+ var/law = "Accomplish your team's objectives at all costs. You may ignore all other laws."
+ var/law_borg = "Accomplish your AI's team objectives at all costs. You may ignore all other laws."
+ killer << "Your laws have been changed!"
+ killer.set_zeroth_law(law, law_borg)
+ killer << "New law: 0. [law]"
diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm
index 616080bfbf..d9e3671546 100644
--- a/code/game/antagonist/station/renegade.dm
+++ b/code/game/antagonist/station/renegade.dm
@@ -59,6 +59,8 @@ var/datum/antagonist/renegade/renegades
list(/obj/item/weapon/gun/projectile/luger,/obj/item/weapon/gun/projectile/luger/brown)
)
+ can_use_aooc = FALSE // They aren't 'true' antags.
+
/datum/antagonist/renegade/New()
..()
renegades = src
diff --git a/code/game/gamemodes/changeling/powers/armblade.dm b/code/game/gamemodes/changeling/powers/armblade.dm
index f241f41840..139950e900 100644
--- a/code/game/gamemodes/changeling/powers/armblade.dm
+++ b/code/game/gamemodes/changeling/powers/armblade.dm
@@ -13,48 +13,66 @@
set name = "Arm Blade (20)"
if(src.mind.changeling.recursive_enhancement)
- if(changeling_generic_weapon(/obj/item/weapon/melee/arm_blade/greater))
+ if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/arm_blade/greater))
src << "We prepare an extra sharp blade."
return 1
else
- if(changeling_generic_weapon(/obj/item/weapon/melee/arm_blade))
+ if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/arm_blade))
return 1
return 0
-/obj/item/weapon/melee/arm_blade
- name = "arm blade"
- desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
+//Claws
+/datum/power/changeling/claw
+ name = "Claw"
+ desc = "We reform one of our arms into a deadly claw."
+ helptext = "We may retract our claw by dropping it."
+ enhancedtext = "The claw will have armor peneratration."
+ ability_icon_state = "ling_claw"
+ genomecost = 1
+ verbpath = /mob/proc/changeling_claw
+
+//Grows a scary, and powerful arm blade.
+/mob/proc/changeling_claw()
+ set category = "Changeling"
+ set name = "Claw (15)"
+
+ if(src.mind.changeling.recursive_enhancement)
+ if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/claw/greater, 1, 15))
+ src << "We prepare an extra sharp claw."
+ return 1
+
+ else
+ if(changeling_generic_weapon(/obj/item/weapon/melee/changeling/claw, 1, 15))
+ return 1
+ return 0
+
+/obj/item/weapon/melee/changeling
+ name = "arm weapon"
+ desc = "A grotesque weapon made out of bone and flesh that cleaves through people as a hot knife through butter."
icon = 'icons/obj/weapons.dmi'
icon_state = "arm_blade"
w_class = ITEMSIZE_HUGE
- force = 40
- sharp = 1
- edge = 1
- pry = 1
+ force = 5
anchored = 1
throwforce = 0 //Just to be on the safe side
throw_range = 0
throw_speed = 0
- attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
var/mob/living/creator //This is just like ninja swords, needed to make sure dumb shit that removes the sword doesn't make it stay around.
+ var/weapType = "weapon"
+ var/weapLocation = "arm"
-/obj/item/weapon/melee/arm_blade/greater
- name = "arm greatblade"
- desc = "A grotesque blade made out of bone and flesh that cleaves through people and armor as a hot knife through butter."
- armor_penetration = 30
-
-/obj/item/weapon/melee/arm_blade/New(location)
+/obj/item/weapon/melee/changeling/New(location)
..()
processing_objects |= src
if(ismob(loc))
- visible_message("A grotesque blade forms around [loc.name]\'s arm!",
- "Our arm twists and mutates, transforming it into a deadly blade.",
+ visible_message("A grotesque weapon forms around [loc.name]\'s arm!",
+ "Our arm twists and mutates, transforming it into a deadly weapon.",
"You hear organic matter ripping and tearing!")
src.creator = loc
-/obj/item/weapon/melee/arm_blade/dropped(mob/user)
- visible_message("With a sickening crunch, [creator] reforms their arm blade into an arm!",
+/obj/item/weapon/melee/changeling/dropped(mob/user)
+ visible_message("With a sickening crunch, [creator] reforms their arm!",
"We assimilate the weapon back into our body.",
"You hear organic matter ripping and tearing!")
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
@@ -62,16 +80,16 @@
if(src)
qdel(src)
-/obj/item/weapon/melee/arm_blade/Destroy()
+/obj/item/weapon/melee/changeling/Destroy()
processing_objects -= src
creator = null
..()
-/obj/item/weapon/melee/arm_blade/suicide_act(mob/user)
+/obj/item/weapon/melee/changeling/suicide_act(mob/user)
viewers(user) << "[user] is impaling \himself the [src.name]! It looks like \he's trying to commit suicide."
return(BRUTELOSS)
-/obj/item/weapon/melee/arm_blade/process() //Stolen from ninja swords.
+/obj/item/weapon/melee/changeling/process() //Stolen from ninja swords.
if(!creator || loc != creator || !creator.item_is_in_hands(src))
// Tidy up a bit.
if(istype(loc,/mob/living))
@@ -86,4 +104,34 @@
host.drop_from_inventory(src)
spawn(1)
if(src)
- qdel(src)
\ No newline at end of file
+ qdel(src)
+
+/obj/item/weapon/melee/changeling/arm_blade
+ name = "arm blade"
+ desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
+ icon_state = "arm_blade"
+ force = 40
+ armor_penetration = 15
+ sharp = 1
+ edge = 1
+ pry = 1
+ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+
+/obj/item/weapon/melee/changeling/arm_blade/greater
+ name = "arm greatblade"
+ desc = "A grotesque blade made out of bone and flesh that cleaves through people and armor as a hot knife through butter."
+ armor_penetration = 30
+
+/obj/item/weapon/melee/changeling/claw
+ name = "hand claw"
+ desc = "A grotesque claw made out of bone and flesh that cleaves through people as a hot knife through butter."
+ icon_state = "ling_claw"
+ force = 15
+ sharp = 1
+ edge = 1
+ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+
+/obj/item/weapon/melee/changeling/claw/greater
+ name = "hand greatclaw"
+ force = 20
+ armor_penetration = 20
\ No newline at end of file
diff --git a/code/game/gamemodes/infiltrator/infiltrator.dm b/code/game/gamemodes/infiltrator/infiltrator.dm
new file mode 100644
index 0000000000..f736cd9894
--- /dev/null
+++ b/code/game/gamemodes/infiltrator/infiltrator.dm
@@ -0,0 +1,13 @@
+/datum/game_mode/infiltrator
+ name = "Infiltrator"
+ round_description = "There are a group of shadowy infiltrators onboard! Be careful!"
+ extended_round_description = "A team of secretative people have played the long con, and managed to obtain entry to \
+ the facility. What their goals are, who their employers are, and why the individuals would work for them is a mystery, \
+ but perhaps you will outwit them, or perhaps that is all part of their plan?"
+ config_tag = "infiltrator"
+ required_players = 2
+ required_players_secret = 5
+ required_enemies = 2 // Bit pointless if there is only one, since its basically traitor.
+ end_on_antag_death = 0
+ antag_scaling_coeff = 5
+ antag_tags = list(MODE_INFILTRATOR)
\ No newline at end of file
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index 41680d3de7..94d336274e 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -118,25 +118,8 @@
usr << "[src]'s motors resist your effort."
return
- if(istype(C, /obj/item/stack/material) && C.get_material_name() == "plasteel") // Repairing.
- var/amt = Ceiling((maxhealth - health)/150)
- if(!amt)
- usr << "\The [src] is already fully repaired."
- return
- var/obj/item/stack/P = C
- if(P.amount < amt)
- usr << "You don't have enough sheets to repair this! You need at least [amt] sheets."
- return
- usr << "You begin repairing [src]..."
- if(do_after(usr, 30))
- if(P.use(amt))
- usr << "You have repaired \The [src]"
- src.repair()
- else
- usr << "You don't have enough sheets to repair this! You need at least [amt] sheets."
-
- else if(src.density)
+ else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's a weapon, let's hit it.
var/obj/item/weapon/W = C
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(W.damtype == BRUTE || W.damtype == BURN)
@@ -147,8 +130,37 @@
user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!")
playsound(src.loc, hitsound, 100, 1)
take_damage(W.force*0.35) //it's a blast door, it should take a while. -Luke
- return
+ return
+ else if(istype(C, /obj/item/stack/material) && C.get_material_name() == "plasteel") // Repairing.
+ var/amt = Ceiling((maxhealth - health)/150)
+ if(!amt)
+ usr << "\The [src] is already fully repaired."
+ return
+ var/obj/item/stack/P = C
+ if(P.amount < amt)
+ usr << "You don't have enough sheets to repair this! You need at least [amt] sheets."
+ return
+ usr << "You begin repairing [src]..."
+ if(do_after(usr, 30))
+ if(P.use(amt))
+ usr << "You have repaired \The [src]"
+ src.repair()
+ else
+ usr << "You don't have enough sheets to repair this! You need at least [amt] sheets."
+
+ else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's not a weapon.... Eh, let's attack it anyway.
+ var/obj/item/weapon/W = C
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ if(W.damtype == BRUTE || W.damtype == BURN)
+ user.do_attack_animation(src)
+ if(W.force < min_force) //No actual non-weapon item shouls have a force greater than the min_force, but let's include this just in case.
+ user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.")
+ else
+ user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!")
+ playsound(src.loc, hitsound, 100, 1)
+ take_damage(W.force*0.15) //If the item isn't a weapon, let's make this take longer than usual to break it down.
+ return
// Proc: open()
// Parameters: None
@@ -213,4 +225,4 @@ obj/machinery/door/blast/regular/open
icon_state_opening = "shutterc0"
icon_state_closed = "shutter1"
icon_state_closing = "shutterc1"
- icon_state = "shutter1"
\ No newline at end of file
+ icon_state = "shutter1"
diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm
index 9838d80722..27a03eb410 100644
--- a/code/game/machinery/telecomms/broadcaster.dm
+++ b/code/game/machinery/telecomms/broadcaster.dm
@@ -138,6 +138,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
if(original)
original.data["done"] = 1
+ // For some reason level is both used as a list and not a list, and now it needs to be a list.
+ // Because this is a 'all in one' machine, we're gonna just cheat.
+ signal.data["level"] = using_map.contact_levels.Copy()
+
if(signal.data["slow"] > 0)
sleep(signal.data["slow"]) // simulate the network lag if necessary
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 8b048a035e..e7beded00a 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -1,185 +1,631 @@
-//The case the paddles are kept in.
+#define DEFIB_TIME_LIMIT (10 MINUTES) //past this many seconds, defib is useless.
+#define DEFIB_TIME_LOSS (2 MINUTES) //past this many seconds, brain damage occurs.
+
+//backpack item
/obj/item/device/defib_kit
- name = "defibrillator kit"
- desc = "This KHI-branded defib kit is a semi-automated model. Remove pads, slap on chest, wait."
- icon = 'icons/obj/device.dmi'
- icon_state = "defib_kit"
+ name = "defibrillator"
+ desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients."
+ icon = 'icons/obj/defibrillator.dmi'
+ icon_state = "defibunit"
+ item_state = "defibunit"
+ slot_flags = SLOT_BACK
+ force = 5
+ throwforce = 6
+ w_class = ITEMSIZE_LARGE
+ origin_tech = list(TECH_BIO = 4, TECH_POWER = 2)
+ action_button_name = "Remove/Replace Paddles"
+
+ var/obj/item/weapon/shockpaddles/linked/paddles
+ var/obj/item/weapon/cell/bcell = null
+
+/obj/item/device/defib_kit/New() //starts without a cell for rnd
+ ..()
+ if(ispath(paddles))
+ paddles = new paddles(src, src)
+ else
+ paddles = new(src, src)
+
+ if(ispath(bcell))
+ bcell = new bcell(src)
+ update_icon()
+
+/obj/item/device/defib_kit/Destroy()
+ . = ..()
+ qdel_null(paddles)
+ qdel_null(bcell)
+
+/obj/item/device/defib_kit/loaded //starts with highcap cell
+ bcell = /obj/item/weapon/cell/high
+
+
+/obj/item/device/defib_kit/update_icon()
+ var/list/new_overlays = list()
+
+ if(paddles && paddles.loc == src) //in case paddles got destroyed somehow.
+ new_overlays += "[initial(icon_state)]-paddles"
+ if(bcell)
+ if(bcell.check_charge(paddles.chargecost))
+ if(paddles.combat)
+ new_overlays += "[initial(icon_state)]-combat"
+ else if(!paddles.safety)
+ new_overlays += "[initial(icon_state)]-emagged"
+ else
+ new_overlays += "[initial(icon_state)]-powered"
+
+ var/ratio = Ceiling(bcell.percent()/25) * 25
+ new_overlays += "[initial(icon_state)]-charge[ratio]"
+ else
+ new_overlays += "[initial(icon_state)]-nocell"
+
+ overlays = new_overlays
+
+/obj/item/device/defib_kit/ui_action_click()
+ toggle_paddles()
+
+/obj/item/device/defib_kit/attack_hand(mob/user)
+ if(loc == user)
+ toggle_paddles()
+ else
+ ..()
+
+/obj/item/device/defib_kit/MouseDrop()
+ if(ismob(src.loc))
+ if(!CanMouseDrop(src))
+ return
+ var/mob/M = src.loc
+ if(!M.unEquip(src))
+ return
+ src.add_fingerprint(usr)
+ M.put_in_any_hand_if_possible(src)
+
+
+/obj/item/device/defib_kit/attackby(obj/item/weapon/W, mob/user, params)
+ if(W == paddles)
+ reattach_paddles(user)
+ else if(istype(W, /obj/item/weapon/cell))
+ if(bcell)
+ to_chat(user, "\the [src] already has a cell.")
+ else
+ if(!user.unEquip(W))
+ return
+ W.forceMove(src)
+ bcell = W
+ to_chat(user, "You install a cell in \the [src].")
+ update_icon()
+
+ else if(isscrewdriver(W))
+ if(bcell)
+ bcell.update_icon()
+ bcell.forceMove(get_turf(src.loc))
+ bcell = null
+ to_chat(user, "You remove the cell from \the [src].")
+ update_icon()
+ else
+ return ..()
+
+/obj/item/device/defib_kit/emag_act(var/remaining_charges, var/mob/user)
+ if(paddles)
+ . = paddles.emag_act(user)
+ update_icon()
+ return
+
+//Paddle stuff
+
+/obj/item/device/defib_kit/verb/toggle_paddles()
+ set name = "Toggle Paddles"
+ set category = "Object"
+
+ var/mob/living/carbon/human/user = usr
+ if(!paddles)
+ to_chat(user, "The paddles are missing!")
+ return
+
+ if(paddles.loc != src)
+ reattach_paddles(user) //Remove from their hands and back onto the defib unit
+ return
+
+ if(!slot_check())
+ to_chat(user, "You need to equip [src] before taking out [paddles].")
+ else
+ if(!usr.put_in_hands(paddles)) //Detach the paddles into the user's hands
+ to_chat(user, "You need a free hand to hold the paddles!")
+ update_icon() //success
+
+//checks that the base unit is in the correct slot to be used
+/obj/item/device/defib_kit/proc/slot_check()
+ var/mob/M = loc
+ if(!istype(M))
+ return 0 //not equipped
+
+ if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src)
+ return 1
+ if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == src)
+ return 1
+
+ return 0
+
+/obj/item/device/defib_kit/dropped(mob/user)
+ ..()
+ reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit
+
+/obj/item/device/defib_kit/proc/reattach_paddles(mob/user)
+ if(!paddles) return
+
+ if(ismob(paddles.loc))
+ var/mob/M = paddles.loc
+ if(M.drop_from_inventory(paddles, src))
+ to_chat(user, "\The [paddles] snap back into the main unit.")
+ else
+ paddles.forceMove(src)
+
+ update_icon()
+
+/*
+ Base Unit Subtypes
+*/
+
+/obj/item/device/defib_kit/compact
+ name = "compact defibrillator"
+ desc = "A belt-equipped defibrillator that can be rapidly deployed."
+ icon_state = "defibcompact"
+ item_state = "defibcompact"
+ w_class = ITEMSIZE_NORMAL
+ slot_flags = SLOT_BELT
+ origin_tech = list(TECH_BIO = 5, TECH_POWER = 3)
+
+/obj/item/device/defib_kit/compact/loaded
+ bcell = /obj/item/weapon/cell/high
+
+
+/obj/item/device/defib_kit/compact/combat
+ name = "combat defibrillator"
+ desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
+ paddles = /obj/item/weapon/shockpaddles/linked/combat
+
+/obj/item/device/defib_kit/compact/combat/loaded
+ bcell = /obj/item/weapon/cell/high
+
+/obj/item/weapon/shockpaddles/linked/combat
+ combat = 1
+ safety = 0
+ chargetime = (1 SECONDS)
+
+
+//paddles
+
+/obj/item/weapon/shockpaddles
+ name = "defibrillator paddles"
+ desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks."
+ icon = 'icons/obj/defibrillator.dmi'
+ icon_state = "defibpaddles"
+ item_state = "defibpaddles"
+ gender = PLURAL
+ force = 2
+ throwforce = 6
w_class = ITEMSIZE_LARGE
- var/state //0 off, 1 open, 2 working, 3 dead
- var/uses = 2 //Calculates initial uses based on starting cell size
- var/use_on_synthetic = 0 //If 1, this is only useful on FBPs, if 0, this is only useful on fleshies
- var/pad_name = "defib pads" //Just the name given for some cosmetic things
- var/chance = 75 //Percent chance of working
- var/charge_cost //Set in New() based on uses
- var/obj/item/weapon/cell/cell //The size is mostly irrelevant, see 'uses'
- var/mob/living/carbon/human/patient //The person the paddles are on
+ var/safety = 1 //if you can zap people with the paddles on harm mode
+ var/combat = 0 //If it can be used to revive people wearing thick clothing (e.g. spacesuits)
+ var/cooldowntime = (6 SECONDS) // How long in deciseconds until the defib is ready again after use.
+ var/chargetime = (2 SECONDS)
+ var/chargecost = 1000 //units of charge
+ var/burn_damage_amt = 5
-/obj/item/device/defib_kit/New()
+ var/wielded = 0
+ var/cooldown = 0
+ var/busy = 0
+
+/obj/item/weapon/shockpaddles/proc/set_cooldown(var/delay)
+ cooldown = 1
+ update_icon()
+
+ spawn(delay)
+ if(cooldown)
+ cooldown = 0
+ update_icon()
+
+ make_announcement("beeps, \"Unit is re-energized.\"", "notice")
+ playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
+
+/obj/item/weapon/shockpaddles/update_held_icon()
+ var/mob/living/M = loc
+ if(istype(M) && !issmall(M) && M.item_is_in_hands(src) && !M.hands_are_full())
+ wielded = 1
+ name = "[initial(name)] (wielded)"
+ else
+ wielded = 0
+ name = initial(name)
+ update_icon()
..()
- //Create cell and determine uses (futureproofing against cell size changes)
- cell = new(src)
- charge_cost = cell.maxcharge / uses
- statechange(0)
-/obj/item/device/defib_kit/attack_self(mob/user as mob)
- ..()
- if(patient)
- patient = null
- user.visible_message("[user] returns the pads to \the [src] and closes it.",
- "You return the pads to \the [src] and close it.")
- statechange(0)
+/obj/item/weapon/shockpaddles/update_icon()
+ icon_state = "defibpaddles[wielded]"
+ item_state = "defibpaddles[wielded]"
+ if(cooldown)
+ icon_state = "defibpaddles[wielded]_cooldown"
-/obj/item/device/defib_kit/MouseDrop(var/mob/living/carbon/human/onto)
- if(istype(onto) && Adjacent(usr) && !usr.restrained() && !usr.stat)
- var/mob/living/carbon/human/user = usr
- //<--Feel free to code clothing checks right here
- if(can_defib(onto))
- user.visible_message("[user] begins applying [pad_name] to [onto].",
- "You begin applying [pad_name] to [onto].")
- if(do_after(user, 100, onto))
- patient = onto
- statechange(1,patient)
- user.visible_message("[user] applies [pad_name] to [onto].",
- "You finish applying [pad_name] to [onto].")
-
-
-//can_defib() check is where all of the qualifying conditions should go
-//Could probably toss in checks here for damage, organs, etc, but for now I'll leave it as just this
-/obj/item/device/defib_kit/proc/can_defib(var/mob/living/carbon/human/target)
- var/mob/living/carbon/human/user = usr
- if(use_on_synthetic && !target.isSynthetic())
- to_chat(user, "[src] isn't designed for organics!")
+/obj/item/weapon/shockpaddles/proc/can_use(mob/user, mob/M)
+ if(busy)
return 0
- else if(!use_on_synthetic && target.isSynthetic())
- to_chat(user, "[src] isn't designed for synthetics!")
+ if(!check_charge(chargecost))
+ to_chat(user, "\The [src] doesn't have enough charge left to do that.")
return 0
- else if(!target.isSynthetic() && ((world.time - target.timeofdeath) > (10 MINUTES)))//Can only revive organics within a few minutes
- to_chat(user, "There is no spark of life in [target.name], they've been dead too long to revive this way.")
+ if(!wielded && !isrobot(user))
+ to_chat(user, "You need to wield the paddles with both hands before you can use them on someone!")
+ return 0
+ if(cooldown)
+ to_chat(user, "\The [src] are re-energizing!")
return 0
return 1
+//Checks for various conditions to see if the mob is revivable
+/obj/item/weapon/shockpaddles/proc/can_defib(mob/living/carbon/human/H) //This is checked before doing the defib operation
+ if((H.species.flags & NO_SCAN) || H.isSynthetic())
+ return "buzzes, \"Unrecogized physiology. Operation aborted.\""
-/obj/item/device/defib_kit/attackby(var/obj/item/A as obj, mob/living/user as mob)
+ if(H.stat != DEAD)
+ return "buzzes, \"Patient is not in a valid state. Operation aborted.\""
+
+ if(!check_contact(H))
+ return "buzzes, \"Patient's chest is obstructed. Operation aborted.\""
+
+ return null
+
+/obj/item/weapon/shockpaddles/proc/can_revive(mob/living/carbon/human/H) //This is checked right before attempting to revive
+
+ var/deadtime = world.time - H.timeofdeath
+ if (deadtime > DEFIB_TIME_LIMIT)
+ return "buzzes, \"Resuscitation failed - Excessive neural degeneration. Further attempts futile.\""
+
+ H.updatehealth()
+ if(H.health + H.getOxyLoss() <= config.health_threshold_dead || (HUSK in H.mutations))
+ return "buzzes, \"Resuscitation failed - Severe tissue damage makes recovery of patient impossible via defibrillator. Further attempts futile.\""
+
+ var/bad_vital_organ = check_vital_organs(H)
+ if(bad_vital_organ)
+ return bad_vital_organ
+
+ //this needs to be last since if any of the 'other conditions are met their messages take precedence
+ if(!H.client && !H.teleop)
+ return "buzzes, \"Resuscitation failed - Mental interface error. Further attempts may be successful.\""
+
+ return null
+
+/obj/item/weapon/shockpaddles/proc/check_contact(mob/living/carbon/human/H)
+ if(!combat)
+ for(var/obj/item/clothing/cloth in list(H.wear_suit, H.w_uniform))
+ if((cloth.body_parts_covered & UPPER_TORSO) && (cloth.item_flags & THICKMATERIAL))
+ return FALSE
+ return TRUE
+
+/obj/item/weapon/shockpaddles/proc/check_vital_organs(mob/living/carbon/human/H)
+ for(var/organ_tag in H.species.has_organ)
+ var/obj/item/organ/O = H.species.has_organ[organ_tag]
+ var/name = initial(O.name)
+ var/vital = initial(O.vital) //check for vital organs
+ if(vital)
+ O = H.internal_organs_by_name[organ_tag]
+ if(!O)
+ return "buzzes, \"Resuscitation failed - Patient is missing vital organ ([name]). Further attempts futile.\""
+ if(O.damage > O.max_damage)
+ return "buzzes, \"Resuscitation failed - Excessive damage to vital organ ([name]). Further attempts futile.\""
+ return null
+
+/obj/item/weapon/shockpaddles/proc/check_blood_level(mob/living/carbon/human/H)
+ if(!H.should_have_organ(O_HEART))
+ return FALSE
+
+ var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[O_HEART]
+ if(!heart)
+ return TRUE
+
+ var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
+ if(!heart || heart.is_broken())
+ blood_volume *= 0.3
+ else if(heart.is_bruised())
+ blood_volume *= 0.7
+ else if(heart.damage > 1)
+ blood_volume *= 0.8
+ return blood_volume < BLOOD_VOLUME_SURVIVE
+
+/obj/item/weapon/shockpaddles/proc/check_charge(var/charge_amt)
+ return 0
+
+/obj/item/weapon/shockpaddles/proc/checked_use(var/charge_amt)
+ return 0
+
+/obj/item/weapon/shockpaddles/attack(mob/living/M, mob/living/user, var/target_zone)
+ var/mob/living/carbon/human/H = M
+ if(!istype(H) || user.a_intent == I_HURT)
+ return ..() //Do a regular attack. Harm intent shocking happens as a hit effect
+
+ if(can_use(user, H))
+ busy = 1
+ update_icon()
+
+ do_revive(H, user)
+
+ busy = 0
+ update_icon()
+
+ return 1
+
+//Since harm-intent now skips the delay for deliberate placement, you have to be able to hit them in combat in order to shock people.
+/obj/item/weapon/shockpaddles/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
+ if(ishuman(target) && can_use(user, target))
+ busy = 1
+ update_icon()
+
+ do_electrocute(target, user, hit_zone)
+
+ busy = 0
+ update_icon()
+
+ return 1
+
+ return ..()
+
+// This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled
+/obj/item/weapon/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/user)
+ if(!H.client && !H.teleop)
+ to_chat(find_dead_player(H.ckey, 1), "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived!")
+
+ //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
+ user.visible_message("\The [user] begins to place [src] on [H]'s chest.", "You begin to place [src] on [H]'s chest...")
+ if(!do_after(user, 30, H))
+ return
+ user.visible_message("\The [user] places [src] on [H]'s chest.", "You place [src] on [H]'s chest.")
+ playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
+
+ var/error = can_defib(H)
+ if(error)
+ make_announcement(error, "warning")
+ playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
+ return
+
+ if(check_blood_level(H))
+ make_announcement("buzzes, \"Warning - Patient is in hypovolemic shock.\"", "warning") //also includes heart damage
+
+ //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
+ if(!do_after(user, chargetime, H))
+ return
+
+ //deduct charge here, in case the base unit was EMPed or something during the delay time
+ if(!checked_use(chargecost))
+ make_announcement("buzzes, \"Insufficient charge.\"", "warning")
+ playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
+ return
+
+ H.visible_message("\The [H]'s body convulses a bit.")
+ playsound(get_turf(src), "bodyfall", 50, 1)
+ playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
+ set_cooldown(cooldowntime)
+
+ error = can_revive(H)
+ if(error)
+ make_announcement(error, "warning")
+ playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
+ return
+
+ H.apply_damage(burn_damage_amt, BURN, BP_TORSO)
+
+ //set oxyloss so that the patient is just barely in crit, if possible
+ var/barely_in_crit = config.health_threshold_crit - 1
+ var/adjust_health = barely_in_crit - H.health //need to increase health by this much
+ H.adjustOxyLoss(-adjust_health)
+
+ make_announcement("pings, \"Resuscitation successful.\"", "notice")
+ playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0)
+
+ make_alive(H)
+
+ log_and_message_admins("used \a [src] to revive [key_name(H)].")
+
+
+/obj/item/weapon/shockpaddles/proc/do_electrocute(mob/living/carbon/human/H, mob/user, var/target_zone)
+ var/obj/item/organ/external/affecting = H.get_organ(target_zone)
+ if(!affecting)
+ to_chat(user, "They are missing that body part!")
+ return
+
+ //no need to spend time carefully placing the paddles, we're just trying to shock them
+ user.visible_message("\The [user] slaps [src] onto [H]'s [affecting.name].", "You overcharge [src] and slap them onto [H]'s [affecting.name].")
+
+ //Just stop at awkwardly slapping electrodes on people if the safety is enabled
+ if(safety)
+ to_chat(user, "You can't do that while the safety is enabled.")
+ return
+
+ playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
+ audible_message("\The [src] lets out a steadily rising hum...")
+
+ if(!do_after(user, chargetime, H))
+ return
+
+ //deduct charge here, in case the base unit was EMPed or something during the delay time
+ if(!checked_use(chargecost))
+ make_announcement("buzzes, \"Insufficient charge.\"", "warning")
+ playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
+ return
+
+ user.visible_message("\The [user] shocks [H] with \the [src]!", "You shock [H] with \the [src]!")
+ playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1)
+ playsound(loc, 'sound/weapons/Egloves.ogg', 100, 1, -1)
+ set_cooldown(cooldowntime)
+
+ H.stun_effect_act(2, 120, target_zone)
+ var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone)
+ if(burn_damage > 15 && H.can_feel_pain())
+ H.emote("scream")
+
+ admin_attack_log(user, H, "Electrocuted using \a [src]", "Was electrocuted with \a [src]", "used \a [src] to electrocute")
+
+/obj/item/weapon/shockpaddles/proc/make_alive(mob/living/carbon/human/M) //This revives the mob
+ var/deadtime = world.time - M.timeofdeath
+
+ dead_mob_list.Remove(M)
+ if((M in living_mob_list) || (M in dead_mob_list))
+ WARNING("Mob [M] was defibbed but already in the living or dead list still!")
+ living_mob_list += M
+
+ M.timeofdeath = 0
+ M.stat = UNCONSCIOUS //Life() can bring them back to consciousness if it needs to.
+ M.regenerate_icons()
+ M.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
+ M.reload_fullscreen()
+
+ M.emote("gasp")
+ M.Weaken(rand(10,25))
+ M.updatehealth()
+ apply_brain_damage(M, deadtime)
+
+/obj/item/weapon/shockpaddles/proc/apply_brain_damage(mob/living/carbon/human/H, var/deadtime)
+ if(deadtime < DEFIB_TIME_LOSS) return
+
+ if(!H.should_have_organ(O_BRAIN)) return //no brain
+
+ var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[O_BRAIN]
+ if(!brain) return //no brain
+
+ var/brain_damage = Clamp((deadtime - DEFIB_TIME_LOSS)/(DEFIB_TIME_LIMIT - DEFIB_TIME_LOSS)*brain.max_damage, H.getBrainLoss(), brain.max_damage)
+ H.setBrainLoss(brain_damage)
+
+/obj/item/weapon/shockpaddles/proc/make_announcement(var/message, var/msg_class)
+ audible_message("\The [src] [message]", "\The [src] vibrates slightly.")
+
+/obj/item/weapon/shockpaddles/emag_act(mob/user)
+ if(safety)
+ safety = 0
+ to_chat(user, "You silently disable \the [src]'s safety protocols with the cryptographic sequencer.")
+ update_icon()
+ return 1
+ else
+ safety = 1
+ to_chat(user, "You silently enable \the [src]'s safety protocols with the cryptographic sequencer.")
+ update_icon()
+ return 1
+
+/obj/item/weapon/shockpaddles/emp_act(severity)
+ var/new_safety = rand(0, 1)
+ if(safety != new_safety)
+ safety = new_safety
+ if(safety)
+ make_announcement("beeps, \"Safety protocols enabled!\"", "notice")
+ playsound(get_turf(src), 'sound/machines/defib_safetyon.ogg', 50, 0)
+ else
+ make_announcement("beeps, \"Safety protocols disabled!\"", "warning")
+ playsound(get_turf(src), 'sound/machines/defib_safetyoff.ogg', 50, 0)
+ update_icon()
..()
- if(!cell && istype(A,/obj/item/weapon/cell))
- if(!user.unEquip(A)) return
- to_chat(user,"You jack \the [A] into \the [src]'s battery mount.")
- A.forceMove(src)
- src.cell = A
+/obj/item/weapon/shockpaddles/robot
+ name = "defibrillator paddles"
+ desc = "A pair of advanced shockpaddles powered by a robot's internal power cell, able to penetrate thick clothing."
+ chargecost = 50
+ combat = 1
+ icon_state = "defibpaddles0"
+ item_state = "defibpaddles0"
+ cooldowntime = (3 SECONDS)
- else if(istype(A,/obj/item/weapon/screwdriver))
- if(cell)
- to_chat(user,"You remove \the [cell] from \the [src].")
- if(user.r_hand && user.l_hand)
- cell.forceMove(get_turf(user))
- else
- user.put_in_hands(cell)
- cell = null
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- else
- to_chat(user,"The power source has already been removed!")
+/obj/item/weapon/shockpaddles/robot/check_charge(var/charge_amt)
+ if(isrobot(src.loc))
+ var/mob/living/silicon/robot/R = src.loc
+ return (R.cell && R.cell.check_charge(charge_amt))
-/obj/item/device/defib_kit/proc/statechange(var/new_state, var/pat)
- if(state == new_state) return //Let's just save ourselves some time
- state = new_state
- icon_state = "[initial(icon_state)][state]"
- var/turf/T = get_turf(src)
- var/state_words = ""
- switch(state)
- if(0)
- state_words = "It is currently closed."
- processing_objects -= src
+/obj/item/weapon/shockpaddles/robot/checked_use(var/charge_amt)
+ if(isrobot(src.loc))
+ var/mob/living/silicon/robot/R = src.loc
+ return (R.cell && R.cell.checked_use(charge_amt))
+
+/*
+ Shockpaddles that are linked to a base unit
+*/
+/obj/item/weapon/shockpaddles/linked
+ var/obj/item/device/defib_kit/base_unit
+
+/obj/item/weapon/shockpaddles/linked/New(newloc, obj/item/device/defib_kit/defib)
+ base_unit = defib
+ ..(newloc)
+
+/obj/item/weapon/shockpaddles/linked/Destroy()
+ if(base_unit)
+ //ensure the base unit's icon updates
+ if(base_unit.paddles == src)
+ base_unit.paddles = null
+ base_unit.update_icon()
+ base_unit = null
+ return ..()
+
+/obj/item/weapon/shockpaddles/linked/dropped(mob/user)
+ ..() //update twohanding
+ if(base_unit)
+ base_unit.reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit
+
+/obj/item/weapon/shockpaddles/linked/check_charge(var/charge_amt)
+ return (base_unit.bcell && base_unit.bcell.check_charge(charge_amt))
+
+/obj/item/weapon/shockpaddles/linked/checked_use(var/charge_amt)
+ return (base_unit.bcell && base_unit.bcell.checked_use(charge_amt))
+
+/obj/item/weapon/shockpaddles/linked/make_announcement(var/message, var/msg_class)
+ base_unit.audible_message("\The [base_unit] [message]", "\The [base_unit] vibrates slightly.")
+
+/*
+ Standalone Shockpaddles
+*/
+
+/obj/item/weapon/shockpaddles/standalone
+ desc = "A pair of shockpaddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun
+ var/fail_counter = 0
+
+/obj/item/weapon/shockpaddles/standalone/Destroy()
+ . = ..()
+ if(fail_counter)
+ processing_objects.Remove(src)
+
+/obj/item/weapon/shockpaddles/standalone/check_charge(var/charge_amt)
+ return 1
+
+/obj/item/weapon/shockpaddles/standalone/checked_use(var/charge_amt)
+ radiation_repository.radiate(src, charge_amt/12) //just a little bit of radiation. It's the price you pay for being powered by magic I guess
+ return 1
+
+/obj/item/weapon/shockpaddles/standalone/process()
+ if(fail_counter > 0)
+ radiation_repository.radiate(src, fail_counter--)
+ else
+ processing_objects.Remove(src)
+
+/obj/item/weapon/shockpaddles/standalone/emp_act(severity)
+ ..()
+ var/new_fail = 0
+ switch(severity)
if(1)
- state_words = "A green light is lit; it has charge."
- processing_objects |= src
+ new_fail = max(fail_counter, 20)
+ visible_message("\The [src]'s reactor overloads!")
if(2)
- state_words = "A yellow light is flashing: it's in the process of reviving a patient."
- T.visible_message("A yellow light starts flashing on \the [src].")
- playsound(T, 'sound/machines/chime.ogg', 50, 0)
- if(3)
- state_words = "A red light is flashing: the battery needs to be recharged."
- T.visible_message("A red light starts flashing on \the [src].")
- playsound(T, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ new_fail = max(fail_counter, 8)
+ if(ismob(loc))
+ to_chat(loc, "\The [src] feel pleasantly warm.")
- desc = "[initial(desc)] [state_words][pat ? " The pads are attached to [pat]." : ""]"
- update_icon()
+ if(new_fail && !fail_counter)
+ processing_objects.Add(src)
+ fail_counter = new_fail
-/obj/item/device/defib_kit/process()
- if(!state) //0 or null
- statechange(0)
- processing_objects -= src
- return
-
- //Patient moved too far
- if(patient && !(get_dist(src,patient) <= 1)) //You separated the kit and pads too far
- audible_message("There is a clatter as the [pad_name] are yanked off of [patient].")
- statechange(0)
- patient = null
- return
-
- //Battery died
- if(!cell || cell.charge < charge_cost)
- statechange(3,patient)
- return
-
- //A patient isn't being worked on, but we have one, so start
- if(patient && patient.stat == DEAD && state != 2)
- statechange(2)
- if(attempt_shock()) //Try to shock them, has timer and such
- patient.visible_message("[patient] convulses!")
- playsound(src.loc, 'sound/effects/sparks2.ogg', 75, 1)
- //Actual rezzing code
- if(prob(chance))
- if(!patient.client && patient.mind) //Don't force the dead person to come back if they don't want to.
- for(var/mob/observer/dead/ghost in player_list)
- if(ghost.mind == patient.mind)
- to_chat(ghost, "Someone is trying to \
- revive you. Return to your body if you want to be revived! \
- (Verbs -> Ghost -> Re-enter corpse). You have 15 seconds to do this!")
- sleep(15 SECONDS)
- break
-
- if(!(HUSK in patient.mutations)) // Husked people can't come back with a Defib.
- if(patient.client)
- patient.adjustOxyLoss(-20) //Look, blood stays oxygenated for quite some time, but I'm not recoding the entire oxy system
- patient.stat = CONSCIOUS //Note that if whatever killed them in the first place wasn't fixed, they're likely to die again.
- dead_mob_list -= patient
- living_mob_list += patient
- patient.timeofdeath = null
- patient.visible_message("[patient]'s eyes open!")
- log_and_message_admins("[patient] was revived by a defib.")
- cell.charge -= charge_cost //Always charge the cost after any attempt, failed or not
- sleep(20) //Wait 2 seconds before next attempt
- statechange(1,patient) //Back to ready
-
-/obj/item/device/defib_kit/proc/attempt_shock()
- if(!patient || cell.charge < charge_cost)
- return
-
- var/zap_time = world.time + (7 SECONDS)
- var/o_patient_loc = patient.loc
- . = 1
-
- while(world.time < zap_time) //This is basically a custom do_after() call
- sleep(1)
-
- //Failed: We lost something important
- if(!patient || !cell || cell.charge < charge_cost)
- . = 0
- break
-
- //Failed: The locations aren't right
- if((o_patient_loc != patient.loc) || !(get_dist(src,patient) <= 1))
- . = 0
- break
-
- return
+/* From the Bay port, this doesn't seem to have a sprite.
+/obj/item/weapon/shockpaddles/standalone/traitor
+ name = "defibrillator paddles"
+ desc = "A pair of unusual looking paddles powered by an experimental miniaturized reactor. It possesses both the ability to penetrate armor and to deliver powerful shocks."
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "defibpaddles0"
+ item_state = "defibpaddles0"
+ combat = 1
+ safety = 0
+ chargetime = (1 SECONDS)
+*/
+//Stub
/obj/item/device/defib_kit/jumper_kit
- name = "jumper cable kit"
- desc = "This Morpheus-branded FBP defib kit is a semi-automated model. Apply cables, step back, wait."
- icon_state = "jumper_kit"
- use_on_synthetic = 1
- pad_name = "jumper cables"
+
+#undef DEFIB_TIME_LIMIT
+#undef DEFIB_TIME_LOSS
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index a56ea4fa98..6526668b64 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -13,7 +13,7 @@
var/translate_hive = 0
var/obj/item/device/encryptionkey/keyslot1 = null
var/obj/item/device/encryptionkey/keyslot2 = null
- var/ks1type = /obj/item/device/encryptionkey
+ var/ks1type = null
var/ks2type = null
/obj/item/device/radio/headset/New()
diff --git a/code/global.dm b/code/global.dm
index 3b69e9b777..b630b52074 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -167,7 +167,7 @@ var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J
// Used by robots and robot preferences.
var/list/robot_module_types = list(
- "Standard", "Engineering", "Construction", "Surgeon", "Crisis",
+ "Standard", "Engineering", "Surgeon", "Crisis",
"Miner", "Janitor", "Service", "Clerical", "Security",
"Research"
)
diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm
index 8c73591197..f3a6ffc77c 100644
--- a/code/modules/admin/verbs/antag-ooc.dm
+++ b/code/modules/admin/verbs/antag-ooc.dm
@@ -3,17 +3,40 @@
set name = "AOOC"
set desc = "Antagonist OOC"
- if(!check_rights(R_ADMIN|R_MOD)) return
+ var/is_admin = check_rights(R_ADMIN|R_MOD, show_msg = 0)
+ var/is_antag = usr.mind && usr.mind.special_role
+
+ if(!is_antag && !is_admin) // Non-antagonists and non-admins have no business using this.
+ to_chat(usr, "Sorry, but only certain antagonists or administrators can use this verb.")
+ return
+
+ else if(is_antag && !is_admin) // Is an antag, and not an admin, meaning we need to check if their antag type allows AOOC.
+ var/datum/antagonist/A = get_antag_data(usr.mind.special_role)
+ if(!A || !A.can_use_aooc)
+ to_chat(usr, "Sorry, but your antagonist type is not allowed to speak in AOOC.")
+ return
msg = sanitize(msg)
- if(!msg) return
+ if(!msg)
+ return
+ // Name shown to admins.
var/display_name = src.key
- if(holder && holder.fakekey)
- display_name = holder.fakekey
+ if(holder)
+ if(holder.fakekey)
+ display_name = usr.client.holder.fakekey
+
+ // Name shown to other players. Admins whom are not also antags have their rank displayed.
+ var/player_display = (is_admin && !is_antag) ? "[display_name]([usr.client.holder.rank])" : display_name
for(var/mob/M in mob_list)
- if((M.mind && M.mind.special_role && M.client) || check_rights((R_ADMIN|R_MOD), 0, M))
- M << "" + create_text_tag("aooc", "Antag-OOC:", M.client) + " [display_name]: [msg]"
+ if(check_rights(R_ADMIN|R_MOD, 0, M)) // Staff can see AOOC unconditionally, and with more details.
+ to_chat(M, "[create_text_tag("aooc", "Antag-OOC:", M.client)] [get_options_bar(src, 0, 1, 1)]([admin_jump_link(usr, M.client.holder)]): [msg]")
+ else if(M.client) // Players can only see AOOC if observing, or if they are an antag type allowed to use AOOC.
+ var/datum/antagonist/A = null
+ if(M.mind) // Observers don't have minds, but they should still see AOOC.
+ A = get_antag_data(M.mind.special_role)
+ if((M.mind && M.mind.special_role && A && A.can_use_aooc) || isobserver(M)) // Antags must have their type be allowed to AOOC to see AOOC. This prevents, say, ERT from seeing AOOC.
+ to_chat(M, "[create_text_tag("aooc", "Antag-OOC:", M.client)] [player_display]: [msg]")
log_ooc("(ANTAG) [key] : [msg]")
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm
index 871c31ec34..dbacf45e34 100644
--- a/code/modules/client/preference_setup/loadout/loadout_suit.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm
@@ -391,4 +391,38 @@
/datum/gear/suit/miscellaneous/peacoat/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
\ No newline at end of file
+ gear_tweaks = list(gear_tweak_free_color_choice)
+
+/datum/gear/suit/snowsuit
+ display_name = "snowsuit"
+ path = /obj/item/clothing/suit/storage/snowsuit
+
+/datum/gear/suit/snowsuit/command
+ display_name = "snowsuit, command"
+ path = /obj/item/clothing/suit/storage/snowsuit/command
+ allowed_roles = list("Colony Director","Research Director","Head of Personnel","Head of Security","Chief Engineer","Command Secretary")
+
+/datum/gear/suit/snowsuit/security
+ display_name = "snowsuit, security"
+ path = /obj/item/clothing/suit/storage/snowsuit/security
+ allowed_roles = list("Security Officer", "Head of Security", "Warden", "Detective")
+
+/datum/gear/suit/snowsuit/medical
+ display_name = "snowsuit, medical"
+ path = /obj/item/clothing/suit/storage/snowsuit/medical
+ allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist")
+
+/datum/gear/suit/snowsuit/science
+ display_name = "snowsuit, science"
+ path = /obj/item/clothing/suit/storage/snowsuit/science
+ allowed_roles = list("Research Director","Scientist", "Roboticist", "Xenobiologist")
+
+/datum/gear/suit/snowsuit/engineering
+ display_name = "snowsuit, engineering"
+ path = /obj/item/clothing/suit/storage/snowsuit/engineering
+ allowed_roles = list("Chief Engineer","Atmospheric Technician", "Station Engineer")
+
+/datum/gear/suit/snowsuit/cargo
+ display_name = "snowsuit, supply"
+ path = /obj/item/clothing/suit/storage/snowsuit/cargo
+ allowed_roles = list("Quartermaster","shaft Miner","Cargo Technician","Head of Personnel")
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
index 8974cc004d..30b0a74f70 100644
--- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
@@ -375,6 +375,10 @@
/datum/gear/uniform/dresses/janimaid
display_name = "maid uniform"
path = /obj/item/clothing/under/dress/janimaid
+
+/datum/gear/uniform/dresses/sexymaid
+ display_name = "sexy maid uniform"
+ path = /obj/item/clothing/under/dress/sexymaid
/datum/gear/uniform/pt
display_name = "pt uniform"
@@ -458,4 +462,4 @@
/datum/gear/uniform/red_swept_dress
display_name = "red swept dress"
- path = /obj/item/clothing/under/dress/red_swept_dress
\ No newline at end of file
+ path = /obj/item/clothing/under/dress/red_swept_dress
diff --git a/code/modules/clothing/spacesuits/rig/suits/alien.dm b/code/modules/clothing/spacesuits/rig/suits/alien.dm
index fe91639322..bc3113a4cc 100644
--- a/code/modules/clothing/spacesuits/rig/suits/alien.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/alien.dm
@@ -13,7 +13,7 @@
offline_slowdown = 10
vision_restriction = 1
offline_vision_restriction = 2
-
+ siemens_coefficient = 0.75
chest_type = /obj/item/clothing/suit/space/rig/breacher
helm_type = /obj/item/clothing/head/helmet/space/rig/breacher
boot_type = /obj/item/clothing/shoes/magboots/rig/breacher
@@ -25,6 +25,7 @@
icon_state = "breacher_rig"
armor = list(melee = 90, bullet = 90, laser = 90, energy = 90, bomb = 90, bio = 100, rad = 80) //Takes TEN TIMES as much damage to stop someone in a breacher. In exchange, it's slow.
vision_restriction = 0
+ siemens_coefficient = 0.2
/obj/item/clothing/head/helmet/space/rig/breacher
species_restricted = list("Unathi")
diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm
index 5d0dd4cb8f..915c2bc698 100644
--- a/code/modules/clothing/spacesuits/rig/suits/ert.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm
@@ -11,6 +11,7 @@
helm_type = /obj/item/clothing/head/helmet/space/rig/ert
req_access = list(access_cent_specops)
+ siemens_coefficient= 0.5
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 100)
allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank, /obj/item/device/t_scanner, /obj/item/weapon/rcd, /obj/item/weapon/crowbar, \
@@ -30,7 +31,7 @@
suit_type = "ERT engineer"
icon_state = "ert_engineer_rig"
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 100)
- siemens_coefficient = 0
+ glove_type = /obj/item/clothing/gloves/gauntlets/rig/eva
initial_modules = list(
/obj/item/rig_module/ai_container,
@@ -71,6 +72,8 @@
suit_type = "heavy asset protection"
icon_state = "asset_protection_rig"
armor = list(melee = 60, bullet = 50, laser = 50,energy = 40, bomb = 40, bio = 100, rad = 100)
+ siemens_coefficient= 0.3
+ glove_type = /obj/item/clothing/gloves/gauntlets/rig/eva
initial_modules = list(
/obj/item/rig_module/ai_container,
diff --git a/code/modules/clothing/spacesuits/rig/suits/merc.dm b/code/modules/clothing/spacesuits/rig/suits/merc.dm
index 1c69920300..4724e2c733 100644
--- a/code/modules/clothing/spacesuits/rig/suits/merc.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/merc.dm
@@ -11,7 +11,8 @@
slowdown = 1
offline_slowdown = 3
offline_vision_restriction = 1
-
+ siemens_coefficient = 0.3
+ glove_type = /obj/item/clothing/gloves/gauntlets/rig/eva
helm_type = /obj/item/clothing/head/helmet/space/rig/merc
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs)
diff --git a/code/modules/clothing/spacesuits/rig/suits/station.dm b/code/modules/clothing/spacesuits/rig/suits/station.dm
index f25da53b4a..56dd1b107e 100644
--- a/code/modules/clothing/spacesuits/rig/suits/station.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/station.dm
@@ -65,6 +65,7 @@
offline_slowdown = 10
offline_vision_restriction = 2
emp_protection = -20
+ siemens_coefficient= 0.75
helm_type = /obj/item/clothing/head/helmet/space/rig/industrial
@@ -92,6 +93,7 @@
slowdown = 0
offline_slowdown = 1
offline_vision_restriction = 1
+ siemens_coefficient= 0.75
helm_type = /obj/item/clothing/head/helmet/space/rig/eva
glove_type = /obj/item/clothing/gloves/gauntlets/rig/eva
@@ -100,6 +102,7 @@
req_access = list()
req_one_access = list()
+ max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/gauntlets/rig/eva
name = "insulated gauntlets"
@@ -127,6 +130,7 @@
slowdown = 0
offline_slowdown = 0
offline_vision_restriction = 0
+ siemens_coefficient= 0.75
helm_type = /obj/item/clothing/head/helmet/space/rig/ce
glove_type = /obj/item/clothing/gloves/gauntlets/rig/ce
@@ -135,6 +139,7 @@
req_access = list()
req_one_access = list()
+ max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/gauntlets/rig/ce
name = "insulated gauntlets"
@@ -161,6 +166,7 @@
armor = list(melee = 45, bullet = 5, laser = 45, energy = 80, bomb = 60, bio = 100, rad = 100)
slowdown = 1
offline_vision_restriction = 1
+ siemens_coefficient= 0.75
helm_type = /obj/item/clothing/head/helmet/space/rig/hazmat
@@ -188,6 +194,7 @@
armor = list(melee = 30, bullet = 15, laser = 20, energy = 60, bomb = 30, bio = 100, rad = 100)
slowdown = 1
offline_vision_restriction = 1
+ siemens_coefficient= 0.75
helm_type = /obj/item/clothing/head/helmet/space/rig/medical
@@ -217,6 +224,7 @@
slowdown = 1
offline_slowdown = 3
offline_vision_restriction = 1
+ siemens_coefficient= 0.7
helm_type = /obj/item/clothing/head/helmet/space/rig/hazard
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 7ce74c610e..27fe815ceb 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -951,3 +951,38 @@ obj/item/clothing/suit/storage/toggle/peacoat
body_parts_covered = UPPER_TORSO|ARMS
flags_inv = HIDEHOLSTER
+/obj/item/clothing/suit/storage/snowsuit
+ name = "snowsuit"
+ desc = "A suit made to keep you nice and toasty on cold winter days. Or at least alive."
+ icon_state = "snowsuit"
+ item_state_slots = list(slot_r_hand_str = "labcoat", slot_l_hand_str = "labcoat")
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS
+ flags_inv = HIDEHOLSTER
+ cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS
+ min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0)
+ allowed = list (/obj/item/weapon/pen, /obj/item/weapon/paper, /obj/item/device/flashlight,/obj/item/weapon/tank/emergency/oxygen, /obj/item/weapon/storage/fancy/cigarettes, /obj/item/weapon/storage/box/matches, /obj/item/weapon/reagent_containers/food/drinks/flask)
+
+/obj/item/clothing/suit/storage/snowsuit/command
+ name = "command snowsuit"
+ icon_state = "snowsuit_command"
+
+/obj/item/clothing/suit/storage/snowsuit/security
+ name = "security snowsuit"
+ icon_state = "snowsuit_security"
+
+/obj/item/clothing/suit/storage/snowsuit/medical
+ name = "medical snowsuit"
+ icon_state = "snowsuit_medical"
+
+/obj/item/clothing/suit/storage/snowsuit/engineering
+ name = "engineering snowsuit"
+ icon_state = "snowsuit_engineering"
+
+/obj/item/clothing/suit/storage/snowsuit/cargo
+ name = "cargo snowsuit"
+ icon_state = "snowsuit_cargo"
+
+/obj/item/clothing/suit/storage/snowsuit/science
+ name = "science snowsuit"
+ icon_state = "snowsuit_science"
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index d3d336e075..6a50570a2f 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -324,6 +324,11 @@
name = "maid uniform"
desc = "A simple maid uniform for housekeeping."
icon_state = "janimaid"
+
+/obj/item/clothing/under/dress/sexymaid
+ name = "sexy maid uniform"
+ desc = "You must be a bit risque teasing all of them in a maid uniform!"
+ icon_state = "sexymaid"
/obj/item/clothing/under/dress/dress_fire
name = "flame dress"
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index 6e5616e7b4..56081c274a 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -313,4 +313,104 @@
name = "mobility module"
desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds."
icon = 'icons/obj/decals.dmi'
- icon_state = "shock"
\ No newline at end of file
+ icon_state = "shock"
+
+/obj/item/weapon/inflatable_dispenser
+ name = "inflatables dispenser"
+ desc = "Hand-held device which allows rapid deployment and removal of inflatables."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "inf_deployer"
+ w_class = ITEMSIZE_LARGE
+
+ var/stored_walls = 5
+ var/stored_doors = 2
+ var/max_walls = 5
+ var/max_doors = 2
+ var/mode = 0 // 0 - Walls 1 - Doors
+
+/obj/item/weapon/inflatable_dispenser/robot
+ w_class = ITEMSIZE_HUGE
+ stored_walls = 10
+ stored_doors = 5
+ max_walls = 10
+ max_doors = 5
+
+/obj/item/weapon/inflatable_dispenser/examine(var/mob/user)
+ if(!..(user))
+ return
+ to_chat(user, "It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored.")
+ to_chat(user, "It is set to deploy [mode ? "doors" : "walls"]")
+
+/obj/item/weapon/inflatable_dispenser/attack_self()
+ mode = !mode
+ to_chat(usr, "You set \the [src] to deploy [mode ? "doors" : "walls"].")
+
+/obj/item/weapon/inflatable_dispenser/afterattack(var/atom/A, var/mob/user)
+ ..(A, user)
+ if(!user)
+ return
+ if(!user.Adjacent(A))
+ to_chat(user, "You can't reach!")
+ return
+ if(istype(A, /turf))
+ try_deploy_inflatable(A, user)
+ if(istype(A, /obj/item/inflatable) || istype(A, /obj/structure/inflatable))
+ pick_up(A, user)
+
+/obj/item/weapon/inflatable_dispenser/proc/try_deploy_inflatable(var/turf/T, var/mob/living/user)
+ if(mode) // Door deployment
+ if(!stored_doors)
+ to_chat(user, "\The [src] is out of doors!")
+ return
+
+ if(T && istype(T))
+ new /obj/structure/inflatable/door(T)
+ stored_doors--
+
+ else // Wall deployment
+ if(!stored_walls)
+ to_chat(user, "\The [src] is out of walls!")
+ return
+
+ if(T && istype(T))
+ new /obj/structure/inflatable(T)
+ stored_walls--
+
+ playsound(T, 'sound/items/zip.ogg', 75, 1)
+ to_chat(user, "You deploy the inflatable [mode ? "door" : "wall"]!")
+
+/obj/item/weapon/inflatable_dispenser/proc/pick_up(var/obj/A, var/mob/living/user)
+ if(istype(A, /obj/structure/inflatable))
+ if(!istype(A, /obj/structure/inflatable/door))
+ if(stored_walls >= max_walls)
+ to_chat(user, "\The [src] is full.")
+ return
+ stored_walls++
+ qdel(A)
+ else
+ if(stored_doors >= max_doors)
+ to_chat(user, "\The [src] is full.")
+ return
+ stored_doors++
+ qdel(A)
+ playsound(loc, 'sound/machines/hiss.ogg', 75, 1)
+ visible_message("\The [user] deflates \the [A] with \the [src]!")
+ return
+ if(istype(A, /obj/item/inflatable))
+ if(!istype(A, /obj/item/inflatable/door))
+ if(stored_walls >= max_walls)
+ to_chat(user, "\The [src] is full.")
+ return
+ stored_walls++
+ qdel(A)
+ else
+ if(stored_doors >= max_doors)
+ to_chat(usr, "\The [src] is full!")
+ return
+ stored_doors++
+ qdel(A)
+ visible_message("\The [user] picks up \the [A] with \the [src]!")
+ return
+
+ to_chat(user, "You fail to pick up \the [A] with \the [src]")
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 50b20dc890..897f6d1d17 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -9,7 +9,7 @@ var/global/list/robot_modules = list(
"Security" = /obj/item/weapon/robot_module/robot/security/general,
"Combat" = /obj/item/weapon/robot_module/robot/security/combat,
"Engineering" = /obj/item/weapon/robot_module/robot/engineering/general,
- "Construction" = /obj/item/weapon/robot_module/robot/engineering/construction,
+// "Construction" = /obj/item/weapon/robot_module/robot/engineering/construction,
"Janitor" = /obj/item/weapon/robot_module/robot/janitor
)
@@ -342,6 +342,8 @@ var/global/list/robot_modules = list(
name = "construction robot module"
no_slip = 1
+/* Merged back into engineering (Hell, it's about time.)
+
/obj/item/weapon/robot_module/robot/engineering/construction/New()
..()
src.modules += new /obj/item/borg/sight/meson(src)
@@ -381,6 +383,7 @@ var/global/list/robot_modules = list(
var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src)
RG.synths = list(metal, glass)
src.modules += RG
+*/
/obj/item/weapon/robot_module/robot/engineering/general/New()
..()
@@ -397,14 +400,21 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/lightreplacer(src)
src.modules += new /obj/item/device/pipe_painter(src)
src.modules += new /obj/item/device/floor_painter(src)
+ src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src)
src.emag = new /obj/item/weapon/melee/baton/robot/arm(src)
src.modules += new /obj/item/device/geiger(src)
+ src.modules += new /obj/item/weapon/rcd/borg(src)
+ src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
+ src.modules += new /obj/item/weapon/gripper/no_use/loader(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000)
var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000)
+ var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel(20000)
+
var/datum/matter_synth/wire = new /datum/matter_synth/wire()
synths += metal
synths += glass
+ synths += plasteel
synths += wire
var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src)
@@ -428,6 +438,10 @@ var/global/list/robot_modules = list(
C.synths = list(wire)
src.modules += C
+ var/obj/item/stack/material/cyborg/plasteel/P = new (src)
+ P.synths = list(plasteel)
+ src.modules += P
+
var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src)
S.synths = list(metal)
src.modules += S
@@ -692,6 +706,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/surgical/circular_saw(src)
src.modules += new /obj/item/weapon/reagent_containers/syringe(src)
src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
+ src.modules += new /obj/item/weapon/storage/part_replacer(src)
src.emag = new /obj/item/weapon/hand_tele(src)
var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000)
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index e142f31ca0..dc54c76102 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -65,7 +65,7 @@
/obj/item/ammo_magazine
name = "magazine"
desc = "A magazine for some kind of gun."
- icon_state = "357"
+ icon_state = ".357"
icon = 'icons/obj/ammo.dmi'
flags = CONDUCT
slot_flags = SLOT_BELT
@@ -78,7 +78,7 @@
var/list/stored_ammo = list()
var/mag_type = SPEEDLOADER //ammo_magazines can only be used with compatible guns. This is not a bitflag, the load_method var on guns is.
- var/caliber = "357"
+ var/caliber = ".357"
var/max_ammo = 7
var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 6202e03cde..ca671caba0 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -30,7 +30,7 @@
name = "speedloader (.357)"
desc = "A speedloader for .357 revolvers."
icon_state = "38"
- caliber = "357"
+ caliber = ".357"
ammo_type = /obj/item/ammo_casing/a357
matter = list(DEFAULT_WALL_MATERIAL = 1260)
max_ammo = 6
@@ -381,28 +381,28 @@
/obj/item/ammo_magazine/m556saw/empty
initial_ammo = 0
-///////// .50 AE /////////
+///////// .44 Magnum /////////
-/obj/item/ammo_magazine/m50
- name = "magazine (.50 AE)"
- icon_state = "50ae"
+/obj/item/ammo_magazine/m44
+ name = "magazine (.44)"
+ icon_state = ".44"
origin_tech = list(TECH_COMBAT = 2)
mag_type = MAGAZINE
- caliber = ".50AE"
+ caliber = ".44"
matter = list(DEFAULT_WALL_MATERIAL = 1260)
- ammo_type = /obj/item/ammo_casing/a50ae
+ ammo_type = /obj/item/ammo_casing/a44
max_ammo = 7
multiple_sprites = 1
-/obj/item/ammo_magazine/m50/empty
+/obj/item/ammo_magazine/m44/empty
initial_ammo = 0
-/obj/item/ammo_magazine/clip/c50
- name = "ammo clip (.50 AE)"
+/obj/item/ammo_magazine/clip/c44
+ name = "ammo clip (.44)"
icon_state = "clip_pistol"
- desc = "A stripper clip for reloading .50 Action Express rounds into magazines."
- caliber = ".50AE"
- ammo_type = /obj/item/ammo_casing/a50ae
+ desc = "A stripper clip for reloading .44 rounds into magazines."
+ caliber = ".44"
+ ammo_type = /obj/item/ammo_casing/a44
matter = list(DEFAULT_WALL_MATERIAL = 1620) // metal costs are very roughly based around one .50 casing = 180 metal
max_ammo = 9
multiple_sprites = 1
diff --git a/code/modules/projectiles/ammunition/rounds.dm b/code/modules/projectiles/ammunition/rounds.dm
index 3230e6ed62..eb36cae3b1 100644
--- a/code/modules/projectiles/ammunition/rounds.dm
+++ b/code/modules/projectiles/ammunition/rounds.dm
@@ -25,7 +25,7 @@
/obj/item/ammo_casing/a357
desc = "A .357 bullet casing."
- caliber = "357"
+ caliber = ".357"
projectile_type = /obj/item/projectile/bullet/pistol/strong
/*
@@ -54,9 +54,9 @@
* .50 Action Express
*/
-/obj/item/ammo_casing/a50ae
- desc = "A .50AE bullet casing."
- caliber = ".50AE"
+/obj/item/ammo_casing/a44
+ desc = "A .44 bullet casing."
+ caliber = ".44"
projectile_type = /obj/item/projectile/bullet/pistol/strong
/*
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 2d3d034bf9..b9c7b3f2db 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -11,7 +11,7 @@
matter = list(DEFAULT_WALL_MATERIAL = 1000)
recoil = 1
- var/caliber = "357" //determines which casings will fit
+ var/caliber = ".357" //determines which casings will fit
var/handle_casings = EJECT_CASINGS //determines how spent casings should be handled
var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine
var/obj/item/ammo_casing/chambered = null
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index ba5f4f147d..bab8f8c811 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -116,15 +116,15 @@
/obj/item/weapon/gun/projectile/deagle
name = "desert eagle"
- desc = "A robust handgun that uses .50 AE rounds."
+ desc = "The perfect handgun for shooters with a need to hit targets through a wall and behind a fridge in your neighbor's house. Uses .44 rounds."
icon_state = "deagle"
item_state = "deagle"
force = 14.0
- caliber = ".50AE"
+ caliber = ".44"
load_method = MAGAZINE
fire_sound = 'sound/weapons/deagle.ogg'
- magazine_type = /obj/item/ammo_magazine/m50
- allowed_magazines = list(/obj/item/ammo_magazine/m50)
+ magazine_type = /obj/item/ammo_magazine/m44
+ allowed_magazines = list(/obj/item/ammo_magazine/m44)
/obj/item/weapon/gun/projectile/deagle/update_icon()
..()
@@ -134,12 +134,12 @@
icon_state = "[initial(icon_state)]-e"
/obj/item/weapon/gun/projectile/deagle/gold
- desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .50 AE rounds."
+ desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .44 rounds."
icon_state = "deagleg"
item_state = "deagleg"
/obj/item/weapon/gun/projectile/deagle/camo
- desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE rounds."
+ desc = "A Deagle brand Deagle for operators operating operationally. Uses .44 rounds."
icon_state = "deaglecamo"
item_state = "deagleg"
@@ -259,14 +259,14 @@
/obj/item/ammo_casing/a9mmf = "9mm",
/obj/item/ammo_casing/a45f = ".45",
/obj/item/ammo_casing/a10mm = "10mm",
- /obj/item/ammo_casing/a12g = "12 gauge",
- /obj/item/ammo_casing/a12g = "12 gauge",
- /obj/item/ammo_casing/a12g/pellet = "12 gauge",
- /obj/item/ammo_casing/a12g/pellet = "12 gauge",
- /obj/item/ammo_casing/a12g/pellet = "12 gauge",
- /obj/item/ammo_casing/a12g/beanbag = "12 gauge",
- /obj/item/ammo_casing/a12g/stunshell = "12 gauge",
- /obj/item/ammo_casing/a12g/flash = "12 gauge",
+ /obj/item/ammo_casing/a12g = "12g",
+ /obj/item/ammo_casing/a12g = "12g",
+ /obj/item/ammo_casing/a12g/pellet = "12g",
+ /obj/item/ammo_casing/a12g/pellet = "12g",
+ /obj/item/ammo_casing/a12g/pellet = "12g",
+ /obj/item/ammo_casing/a12g/beanbag = "12g",
+ /obj/item/ammo_casing/a12g/stunshell = "12g",
+ /obj/item/ammo_casing/a12g/flash = "12g",
/obj/item/ammo_casing/a762 = "7.62mm",
/obj/item/ammo_casing/a556 = "5.56mm"
)
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 3886450fcf..7d7a01464f 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -3,7 +3,7 @@
desc = "The Lumoco Arms HE Colt is a choice revolver for when you absolutely, positively need to put a hole in the other guy. Uses .357 rounds."
icon_state = "revolver"
item_state = "revolver"
- caliber = "357"
+ caliber = ".357"
origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2)
handle_casings = CYCLE_CASINGS
max_shells = 6
diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm
index 1c82f6cded..9d97f528e3 100644
--- a/code/modules/reagents/reagent_containers/food/lunch.dm
+++ b/code/modules/reagents/reagent_containers/food/lunch.dm
@@ -58,7 +58,7 @@ var/list/lunchables_drink_reagents_ = list(/datum/reagent/drink/nothing,
/datum/reagent/drink/dry_ramen,
/datum/reagent/drink/hell_ramen,
/datum/reagent/drink/hot_ramen,
- /datum/reagent/drink/nuka_cola,)
+ /datum/reagent/drink/nuka_cola)
// This default list is a bit different, it contains items we don't want
var/list/lunchables_ethanol_reagents_ = list(/datum/reagent/ethanol/acid_spit,
diff --git a/code/modules/tables/interactions.dm b/code/modules/tables/interactions.dm
index 35dfdc33b6..1b287294b1 100644
--- a/code/modules/tables/interactions.dm
+++ b/code/modules/tables/interactions.dm
@@ -130,7 +130,7 @@
break_to_parts()
return
- if(istype(W, /obj/item/weapon/melee/arm_blade))
+ if(istype(W, /obj/item/weapon/melee/changeling/arm_blade))
user.visible_message("\The [src] was sliced apart by [user]!")
break_to_parts()
return
diff --git a/code/modules/xenoarcheaology/tools/artifact_harvester.dm b/code/modules/xenoarcheaology/tools/artifact_harvester.dm
index 23ff59799e..ca7b43b1d3 100644
--- a/code/modules/xenoarcheaology/tools/artifact_harvester.dm
+++ b/code/modules/xenoarcheaology/tools/artifact_harvester.dm
@@ -15,10 +15,10 @@
/obj/machinery/artifact_harvester/New()
..()
- //connect to a nearby scanner pad
- owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir)
- if(!owned_scanner)
- owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src)
+ spawn(50) //Delay so the scan pad has time to actually spawn in
+ owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir) //connect to a nearby scanner pad
+ if(!owned_scanner)
+ owned_scanner = locate(/obj/machinery/artifact_scanpad) in orange(1, src)
/obj/machinery/artifact_harvester/attackby(var/obj/I as obj, var/mob/user as mob)
if(istype(I,/obj/item/weapon/anobattery))
diff --git a/code/stylesheet.dm b/code/stylesheet.dm
index 0e9f5f87b7..663ddae5f6 100644
--- a/code/stylesheet.dm
+++ b/code/stylesheet.dm
@@ -24,6 +24,7 @@ em {font-style: normal;font-weight: bold;}
.ooc .moderator {color: #184880;}
.ooc .developer {color: #1b521f;}
.ooc .admin {color: #b82e00;}
+.ooc .aooc {color: #960018;}
/* Admin: Private Messages */
.pm .howto {color: #ff0000; font-weight: bold; font-size: 200%;}
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index c13a604dba..f601d18e3c 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi
index b26eabc764..3a70243e7b 100644
Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index 5442b3b4a8..7580e0ea65 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi
index 5e2e4a2c69..28158e4838 100644
Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ
diff --git a/icons/mob/items/lefthand_melee.dmi b/icons/mob/items/lefthand_melee.dmi
index 93ac77c655..41f7617c3f 100644
Binary files a/icons/mob/items/lefthand_melee.dmi and b/icons/mob/items/lefthand_melee.dmi differ
diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi
index 3b1a1dea8f..55de85a668 100644
Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ
diff --git a/icons/mob/items/righthand_melee.dmi b/icons/mob/items/righthand_melee.dmi
index ce37a0997e..fb7baddc29 100644
Binary files a/icons/mob/items/righthand_melee.dmi and b/icons/mob/items/righthand_melee.dmi differ
diff --git a/icons/mob/screen_spells.dmi b/icons/mob/screen_spells.dmi
index 908331c31d..c65d50880f 100644
Binary files a/icons/mob/screen_spells.dmi and b/icons/mob/screen_spells.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index c5464b5336..7249f9b218 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index 37c85a0837..3aef9384f4 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index dcdb20e070..b105cb9e12 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 549f90747a..2925d066c2 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index a7fed692ad..7c33803ebc 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/defibrillator.dmi b/icons/obj/defibrillator.dmi
new file mode 100644
index 0000000000..7be0d18d00
Binary files /dev/null and b/icons/obj/defibrillator.dmi differ
diff --git a/icons/obj/food.dmi b/icons/obj/food.dmi
index 8df487ad3c..373fdcb25b 100644
Binary files a/icons/obj/food.dmi and b/icons/obj/food.dmi differ
diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi
index f870bd9672..f90a841fde 100644
Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 39ed73fc3d..a933bc6a2f 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index 22f52ad154..c7fd776592 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/sound/machines/defib_SafetyOn.ogg b/sound/machines/defib_SafetyOn.ogg
new file mode 100644
index 0000000000..cf26153646
Binary files /dev/null and b/sound/machines/defib_SafetyOn.ogg differ
diff --git a/sound/machines/defib_charge.ogg b/sound/machines/defib_charge.ogg
new file mode 100644
index 0000000000..3e2be160fd
Binary files /dev/null and b/sound/machines/defib_charge.ogg differ
diff --git a/sound/machines/defib_failed.ogg b/sound/machines/defib_failed.ogg
new file mode 100644
index 0000000000..341f70ce84
Binary files /dev/null and b/sound/machines/defib_failed.ogg differ
diff --git a/sound/machines/defib_ready.ogg b/sound/machines/defib_ready.ogg
new file mode 100644
index 0000000000..718128602e
Binary files /dev/null and b/sound/machines/defib_ready.ogg differ
diff --git a/sound/machines/defib_safetyOff.ogg b/sound/machines/defib_safetyOff.ogg
new file mode 100644
index 0000000000..6ab57097de
Binary files /dev/null and b/sound/machines/defib_safetyOff.ogg differ
diff --git a/sound/machines/defib_success.ogg b/sound/machines/defib_success.ogg
new file mode 100644
index 0000000000..3f71438c16
Binary files /dev/null and b/sound/machines/defib_success.ogg differ
diff --git a/sound/machines/defib_zap.ogg b/sound/machines/defib_zap.ogg
new file mode 100644
index 0000000000..5612db39a4
Binary files /dev/null and b/sound/machines/defib_zap.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index abd0b5fe55..7a59331e5f 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -186,8 +186,8 @@
#include "code\controllers\ProcessScheduler\core\process.dm"
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
#include "code\controllers\subsystems\garbage.dm"
-#include "code\controllers\subsystems\mobs.dm"
#include "code\controllers\subsystems\lighting.dm"
+#include "code\controllers\subsystems\mobs.dm"
#include "code\controllers\subsystems\transcore_vr.dm"
#include "code\datums\ai_law_sets.dm"
#include "code\datums\ai_laws.dm"
@@ -354,6 +354,7 @@
#include "code\game\antagonist\station\changeling.dm"
#include "code\game\antagonist\station\cultist.dm"
#include "code\game\antagonist\station\highlander.dm"
+#include "code\game\antagonist\station\infiltrator.dm"
#include "code\game\antagonist\station\loyalist.dm"
#include "code\game\antagonist\station\renegade.dm"
#include "code\game\antagonist\station\revolutionary.dm"
@@ -440,6 +441,7 @@
#include "code\game\gamemodes\events\holidays\Other.dm"
#include "code\game\gamemodes\extended\extended.dm"
#include "code\game\gamemodes\heist\heist.dm"
+#include "code\game\gamemodes\infiltrator\infiltrator.dm"
#include "code\game\gamemodes\malfunction\malf_hardware.dm"
#include "code\game\gamemodes\malfunction\malf_research.dm"
#include "code\game\gamemodes\malfunction\malf_research_ability.dm"