diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 012677200c3..c73ebf4d41e 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -177,6 +177,9 @@
#define O_LIVER "liver"
#define O_KIDNEYS "kidneys"
#define O_APPENDIX "appendix"
+#define O_VOICE "voicebox"
+
+// Non-Standard organs
#define O_PLASMA "plasma vessel"
#define O_HIVE "hive node"
#define O_NUTRIENT "nutrient vessel"
diff --git a/code/controllers/subsystems/transcore_vr.dm b/code/controllers/subsystems/transcore_vr.dm
index feae05ae917..ddac25ee834 100644
--- a/code/controllers/subsystems/transcore_vr.dm
+++ b/code/controllers/subsystems/transcore_vr.dm
@@ -45,12 +45,18 @@ SUBSYSTEM_DEF(transcore)
current_run.len--
//Remove if not in a human anymore.
- if(!imp || !ishuman(imp.loc))
+ if(!imp || !isorgan(imp.loc))
implants -= imp
continue
- //We're in a human, at least.
- var/mob/living/carbon/human/H = imp.loc
+ //We're in an organ, at least.
+ var/obj/item/organ/external/EO = imp.loc
+ var/mob/living/carbon/human/H = EO.owner
+ if(!H)
+ implants -= imp
+ continue
+
+ //In a human
BITSET(H.hud_updateflag, BACKUP_HUD)
if(H == imp.imp_in && H.mind && H.stat < DEAD)
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index b6654650847..765e1ee9e93 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -84,10 +84,8 @@
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones.
- if(robot.module && robot.module.hide_on_manifest)
- continue
-
- bot[robot.name] = "[robot.modtype] [robot.braintype]"
+ if(!robot.scrambledcodes && !(robot.module && robot.module.hide_on_manifest))
+ bot[robot.name] = "[robot.modtype] [robot.braintype]"
if(heads.len > 0)
diff --git a/code/defines/obj.dm b/code/defines/obj.dm
index f300496aa2a..272309f7802 100644
--- a/code/defines/obj.dm
+++ b/code/defines/obj.dm
@@ -144,7 +144,7 @@ var/global/list/PDA_Manifest = list()
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones.
- if(robot.module && robot.module.hide_on_manifest)
+ if(!robot.scrambledcodes && !(robot.module && robot.module.hide_on_manifest))
continue
bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active")
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 484ff8ea33e..7496551c25f 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -79,7 +79,9 @@
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.
+// var/can_use_aooc = TRUE // If true, will be given the AOOC verb, along with the ability to use it.
+ var/can_hear_aooc = TRUE // If FALSE, the antag can neither speak nor hear AOOC. If TRUE, they can at least hear it.
+ var/can_speak_aooc = TRUE // If TRUE, the antag can freely spean in AOOC.
/datum/antagonist/New()
..()
diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm
index 67eb7e2e726..d5fa2c1fe6f 100644
--- a/code/game/antagonist/antagonist_add.dm
+++ b/code/game/antagonist/antagonist_add.dm
@@ -36,7 +36,7 @@
and it otherwise has no bearing on your round."
player.current.verbs |= /mob/living/proc/write_ambition
- if(can_use_aooc)
+ if(can_speak_aooc)
player.current.client.verbs += /client/proc/aooc
// Handle only adding a mind and not bothering with gear etc.
diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm
index c1aec2bcf82..245296084c6 100644
--- a/code/game/antagonist/outsider/ert.dm
+++ b/code/game/antagonist/outsider/ert.dm
@@ -25,7 +25,8 @@ var/datum/antagonist/ert/ert
initial_spawn_req = 5
initial_spawn_target = 7
- can_use_aooc = FALSE // They're the good guys.
+ can_hear_aooc = FALSE // They're the good guys.
+ can_speak_aooc = FALSE // Just in case the above var bugs, or gets touched.
/datum/antagonist/ert/create_default(var/mob/source)
var/mob/living/carbon/human/M = ..()
diff --git a/code/game/antagonist/outsider/trader.dm b/code/game/antagonist/outsider/trader.dm
index 9603b495238..69af3883b97 100644
--- a/code/game/antagonist/outsider/trader.dm
+++ b/code/game/antagonist/outsider/trader.dm
@@ -24,7 +24,7 @@ var/datum/antagonist/trader/traders
initial_spawn_req = 5
initial_spawn_target = 7
- can_use_aooc = FALSE // They're not real antags.
+ can_speak_aooc = FALSE // They're not real antags.
/datum/antagonist/trader/create_default(var/mob/source)
var/mob/living/carbon/human/M = ..()
diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm
index 6f7ec893229..3e8afae32df 100644
--- a/code/game/antagonist/station/renegade.dm
+++ b/code/game/antagonist/station/renegade.dm
@@ -17,7 +17,7 @@ var/datum/antagonist/renegade/renegades
Think through your actions and make the roleplay immersive! Please remember all \
rules aside from those without explicit exceptions apply to antagonists."
flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- can_use_aooc = FALSE
+ can_speak_aooc = FALSE // They aren't 'true' antags, but they still need to hear blanket antag instructions
hard_cap = 8
hard_cap_round = 12
@@ -61,8 +61,6 @@ 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/antagonist/station/thug.dm b/code/game/antagonist/station/thug.dm
index 8810fca7d04..61d92e1646f 100644
--- a/code/game/antagonist/station/thug.dm
+++ b/code/game/antagonist/station/thug.dm
@@ -15,4 +15,4 @@ var/datum/antagonist/thug/thugs
Think through your actions and make the roleplay immersive! Please remember all \
rules aside from those with explicit exceptions apply to antagonists."
flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- can_use_aooc = FALSE
+ can_speak_aooc = FALSE
diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm
index d0a1f54ed21..3681cf236d7 100644
--- a/code/game/antagonist/station/traitor.dm
+++ b/code/game/antagonist/station/traitor.dm
@@ -5,7 +5,7 @@ var/datum/antagonist/traitor/traitors
id = MODE_TRAITOR
protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Colony Director")
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- can_use_aooc = FALSE
+ can_speak_aooc = FALSE // If they want to plot and plan as this sort of traitor, they'll need to do it ICly.
/datum/antagonist/traitor/auto
id = MODE_AUTOTRAITOR
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 5396c9bb294..278e516aae6 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -391,7 +391,8 @@ var/global/datum/controller/occupations/job_master
H.amend_exploitable(G.path)
if(G.slot == "implant")
- H.implant_loadout(G)
+ var/obj/item/weapon/implant/I = G.spawn_item(H)
+ I.implant_loadout(H)
continue
if(G.slot && !(G.slot in custom_equip_slots))
diff --git a/code/game/objects/items/poi_items.dm b/code/game/objects/items/poi_items.dm
index 85a8b27854e..394212e4c48 100644
--- a/code/game/objects/items/poi_items.dm
+++ b/code/game/objects/items/poi_items.dm
@@ -52,8 +52,9 @@
/obj/structure/largecrate/animal/crashedshuttle
name = "SCP"
+
/obj/structure/largecrate/animal/crashedshuttle/initialize()
- starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble)
+ starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer)
name = pick("Spicy Crust Pizzeria", "Soap and Care Products", "Sally's Computer Parts", "Steve's Chocolate Pastries", "Smith & Christian's Plastics","Standard Containers & Packaging Co.", "Sanitary Chemical Purgation (LTD)")
name += " delivery crate"
return ..()
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index bc93d20bb53..17f4121a76a 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -198,3 +198,9 @@
throw_range = 20
flags = 0
no_variants = FALSE
+
+/obj/item/stack/tile/roofing
+ name = "roofing"
+ singular_name = "roofing"
+ desc = "A section of roofing material. You can use it to repair the ceiling, or expand it."
+ icon_state = "techtile_grid"
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm
index d9606d28d24..7cddfd1efc6 100644
--- a/code/game/objects/items/weapons/autopsy.dm
+++ b/code/game/objects/items/weapons/autopsy.dm
@@ -167,21 +167,24 @@
if(!istype(M))
return 0
+ if (user.a_intent == I_HELP)
+ return ..()
+
if(target_name != M.name)
target_name = M.name
src.wdata = list()
src.chemtraces = list()
src.timeofdeath = null
- user << "A new patient has been registered. Purging data for previous patient."
+ to_chat(user, "A new patient has been registered. Purging data for previous patient.")
src.timeofdeath = M.timeofdeath
var/obj/item/organ/external/S = M.get_organ(user.zone_sel.selecting)
if(!S)
- usr << "You can't scan this body part."
+ to_chat(user, "You can't scan this body part.")
return
if(!S.open)
- usr << "You have to cut [S] open first!"
+ to_chat(user, "You have to cut [S] open first!")
return
M.visible_message("\The [user] scans the wounds on [M]'s [S.name] with [src]")
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 02e4cd48c44..f5bd38dcc17 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -21,12 +21,26 @@
/obj/item/weapon/implant/proc/activate()
return
- // What does the implant do upon injection?
- // return 0 if the implant fails (ex. Revhead and loyalty implant.)
- // return 1 if the implant succeeds (ex. Nonrevhead and loyalty implant.)
-/obj/item/weapon/implant/proc/implanted(var/mob/source)
+// Moves the implant where it needs to go, and tells it if there's more to be done in post_implant
+/obj/item/weapon/implant/proc/handle_implant(var/mob/source, var/target_zone = BP_TORSO)
+ . = TRUE
+ imp_in = source
+ implanted = TRUE
+ if(ishuman(source))
+ var/mob/living/carbon/human/H = source
+ var/obj/item/organ/external/affected = H.get_organ(target_zone)
+ if(affected)
+ affected.implants += src
+ part = affected
+ if(part)
+ forceMove(part)
+ else
+ forceMove(source)
+
listening_objects |= src
- return 1
+
+// Takes place after handle_implant, if that returns TRUE
+/obj/item/weapon/implant/proc/post_implant(var/mob/source)
/obj/item/weapon/implant/proc/get_data()
return "No information available"
@@ -49,6 +63,12 @@
icon_state = "implant_melted"
malfunction = MALFUNCTION_PERMANENT
+/obj/item/weapon/implant/proc/implant_loadout(var/mob/living/carbon/human/H)
+ if(H)
+ var/obj/item/organ/external/affected = H.organs_by_name[BP_HEAD]
+ if(handle_implant(H, affected))
+ post_implant(H)
+
/obj/item/weapon/implant/Destroy()
if(part)
part.implants.Remove(src)
@@ -69,6 +89,11 @@
else
..()
+
+
+//////////////////////////////
+// Tracking Implant
+//////////////////////////////
GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking)
/obj/item/weapon/implant/tracking
@@ -84,9 +109,8 @@ GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking
id = rand(1, 1000)
..()
-/obj/item/weapon/implant/tracking/implanted(var/mob/source)
+/obj/item/weapon/implant/tracking/post_implant(var/mob/source)
processing_objects.Add(src)
- return 1
/obj/item/weapon/implant/tracking/Destroy()
processing_objects.Remove(src)
@@ -142,7 +166,9 @@ Implant Specifics:
"}
spawn(delay)
malfunction--
-
+//////////////////////////////
+// Death Explosive Implant
+//////////////////////////////
/obj/item/weapon/implant/dexplosive
name = "explosive"
desc = "And boom goes the weasel."
@@ -177,7 +203,9 @@ Implant Specifics:
"}
/obj/item/weapon/implant/dexplosive/islegal()
return 0
-//BS12 Explosive
+//////////////////////////////
+// Explosive Implant
+//////////////////////////////
/obj/item/weapon/implant/explosive
name = "explosive implant"
desc = "A military grade micro bio-explosive. Highly dangerous."
@@ -249,15 +277,13 @@ Implant Specifics:
"}
if(t)
t.hotspot_expose(3500,125)
-/obj/item/weapon/implant/explosive/implanted(mob/source as mob)
+/obj/item/weapon/implant/explosive/post_implant(mob/source as mob)
elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion")
phrase = input("Choose activation phrase:") as text
var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "")
phrase = replace_characters(phrase, replacechars)
usr.mind.store_memory("Explosive implant in [source] can be activated by saying something containing the phrase ''[src.phrase]'', say [src.phrase] to attempt to activate.", 0, 0)
usr << "The implanted explosive implant in [source] can be activated by saying something containing the phrase ''[src.phrase]'', say [src.phrase] to attempt to activate."
- listening_objects |= src
- return 1
/obj/item/weapon/implant/explosive/emp_act(severity)
if (malfunction)
@@ -311,6 +337,9 @@ Implant Specifics:
"}
explosion(get_turf(imp_in), -1, -1, 1, 3)
qdel(src)
+//////////////////////////////
+// Chemical Implant
+//////////////////////////////
GLOBAL_LIST_BOILERPLATE(all_chem_implants, /obj/item/weapon/implant/chem)
/obj/item/weapon/implant/chem
@@ -336,20 +365,17 @@ Can only be loaded while still in its original case.
the implant may become unstable and either pre-maturely inject the subject or simply break."}
return dat
-
/obj/item/weapon/implant/chem/New()
..()
var/datum/reagents/R = new/datum/reagents(50)
reagents = R
R.my_atom = src
-
/obj/item/weapon/implant/chem/trigger(emote, source as mob)
if(emote == "deathgasp")
src.activate(src.reagents.total_volume)
return
-
/obj/item/weapon/implant/chem/activate(var/cause)
if((!cause) || (!src.imp_in)) return 0
var/mob/living/carbon/R = src.imp_in
@@ -384,6 +410,9 @@ the implant may become unstable and either pre-maturely inject the subject or si
spawn(20)
malfunction--
+//////////////////////////////
+// Loyalty Implant
+//////////////////////////////
/obj/item/weapon/implant/loyalty
name = "loyalty implant"
desc = "Makes you loyal or such."
@@ -401,20 +430,24 @@ the implant may become unstable and either pre-maturely inject the subject or si
Integrity: Implant will last so long as the nanobots are inside the bloodstream."}
return dat
-
-/obj/item/weapon/implant/loyalty/implanted(mob/M)
- if(!istype(M, /mob/living/carbon/human)) return 0
+/obj/item/weapon/implant/loyalty/handle_implant(mob/M, target_zone = BP_TORSO)
+ . = ..(M, target_zone)
+ if(!istype(M, /mob/living/carbon/human))
+ . = FALSE
var/mob/living/carbon/human/H = M
var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role)
if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE))
H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [using_map.company_name] try to invade your mind!")
- return 0
- else
- clear_antag_roles(H.mind, 1)
- H << "You feel a surge of loyalty towards [using_map.company_name]."
- return 1
+ . = FALSE
+/obj/item/weapon/implant/loyalty/post_implant(mob/M)
+ var/mob/living/carbon/human/H = M
+ clear_antag_roles(H.mind, 1)
+ to_chat(H, "You feel a surge of loyalty towards [using_map.company_name].")
+//////////////////////////////
+// Adrenaline Implant
+//////////////////////////////
/obj/item/weapon/implant/adrenalin
name = "adrenalin"
desc = "Removes all stuns and knockdowns."
@@ -445,14 +478,13 @@ the implant may become unstable and either pre-maturely inject the subject or si
return
-
-/obj/item/weapon/implant/adrenalin/implanted(mob/source)
+/obj/item/weapon/implant/adrenalin/post_implant(mob/source)
source.mind.store_memory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", 0, 0)
source << "The implanted freedom implant can be activated by using the pale emote, say *pale to attempt to activate."
- listening_objects |= src
- return 1
-
+//////////////////////////////
+// Death Alarm Implant
+//////////////////////////////
/obj/item/weapon/implant/death_alarm
name = "death alarm implant"
desc = "An alarm which monitors host vital signs and transmits a radio message upon death."
@@ -529,11 +561,13 @@ the implant may become unstable and either pre-maturely inject the subject or si
spawn(20)
malfunction--
-/obj/item/weapon/implant/death_alarm/implanted(mob/source as mob)
+/obj/item/weapon/implant/death_alarm/post_implant(mob/source as mob)
mobname = source.real_name
processing_objects.Add(src)
- return 1
+//////////////////////////////
+// Compressed Matter Implant
+//////////////////////////////
/obj/item/weapon/implant/compressed
name = "compressed matter implant"
desc = "Based on compressed matter technology, can store a single item."
@@ -571,13 +605,12 @@ the implant may become unstable and either pre-maturely inject the subject or si
scanned.loc = t
qdel(src)
-/obj/item/weapon/implant/compressed/implanted(mob/source as mob)
+/obj/item/weapon/implant/compressed/post_implant(mob/source)
src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink")
if (source.mind)
source.mind.store_memory("Compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0)
source << "The implanted compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate."
- listening_objects |= src
- return 1
+
/obj/item/weapon/implant/compressed/islegal()
return 0
diff --git a/code/game/objects/items/weapons/implants/implant_vr.dm b/code/game/objects/items/weapons/implants/implant_vr.dm
index 4b796cc56e6..ebcc2d9f546 100644
--- a/code/game/objects/items/weapons/implants/implant_vr.dm
+++ b/code/game/objects/items/weapons/implants/implant_vr.dm
@@ -3,43 +3,39 @@
desc = "Allows the user to understand and speak almost all known languages.."
var/uses = 1
- get_data()
- var/dat = {"
-Implant Specifications:
-Name: Language Implant
-Life: One day.
-Important Notes: Personnel with this implant can speak almost all known languages.
-
-Implant Details: Subjects injected with implant can understand and speak almost all known languages.
-Function: Contains specialized nanobots to stimulate the brain so the user can speak and understand previously unknown languages.
-Special Features: Will allow the user to understand almost all languages.
-Integrity: Implant can only be used once before the nanobots are depleted."}
- return dat
+/obj/item/weapon/implant/vrlanguage/get_data()
+ var/dat = {"
+ Implant Specifications:
+ Name: Language Implant
+ Life: One day.
+ Important Notes: Personnel with this implant can speak almost all known languages.
+
+ Implant Details: Subjects injected with implant can understand and speak almost all known languages.
+ Function: Contains specialized nanobots to stimulate the brain so the user can speak and understand previously unknown languages.
+ Special Features: Will allow the user to understand almost all languages.
+ Integrity: Implant can only be used once before the nanobots are depleted."}
+ return dat
+/obj/item/weapon/implant/vrlanguage/trigger(emote, mob/source as mob)
+ if (src.uses < 1)
+ return 0
+ if (emote == "smile")
+ src.uses--
+ to_chat(source,"You suddenly feel as if you can understand other languages!")
+ source.add_language(LANGUAGE_CHIMPANZEE)
+ source.add_language(LANGUAGE_NEAERA)
+ source.add_language(LANGUAGE_STOK)
+ source.add_language(LANGUAGE_FARWA)
+ source.add_language(LANGUAGE_UNATHI)
+ source.add_language(LANGUAGE_SIIK)
+ source.add_language(LANGUAGE_SKRELLIAN)
+ source.add_language(LANGUAGE_SCHECHI)
+ source.add_language(LANGUAGE_BIRDSONG)
+ source.add_language(LANGUAGE_SAGARU)
+ source.add_language(LANGUAGE_CANILUNZT)
+ source.add_language(LANGUAGE_SOL_COMMON) //In case they're giving a xenomorph an implant or something.
- trigger(emote, mob/source as mob)
- if (src.uses < 1) return 0
- if (emote == "smile")
- src.uses--
- source << "You suddenly feel as if you can understand other languages!"
- source.add_language(LANGUAGE_CHIMPANZEE)
- source.add_language(LANGUAGE_NEAERA)
- source.add_language(LANGUAGE_STOK)
- source.add_language(LANGUAGE_FARWA)
- source.add_language(LANGUAGE_UNATHI)
- source.add_language(LANGUAGE_SIIK)
- source.add_language(LANGUAGE_SKRELLIAN)
- source.add_language(LANGUAGE_SCHECHI)
- source.add_language(LANGUAGE_BIRDSONG)
- source.add_language(LANGUAGE_SAGARU)
- source.add_language(LANGUAGE_CANILUNZT)
- source.add_language(LANGUAGE_SOL_COMMON) //In case they're giving a xenomorph an implant or something.
-
-
- return
-
-
- implanted(mob/source)
- source.mind.store_memory("A implant can be activated by using the smile emote, say *smile to attempt to activate.", 0, 0)
- source << "The implanted language implant can be activated by using the smile emote, say *smile to attempt to activate."
- return 1
+/obj/item/weapon/implant/vrlanguage/post_implant(mob/source)
+ source.mind.store_memory("A implant can be activated by using the smile emote, say *smile to attempt to activate.", 0, 0)
+ to_chat(source,"The implanted language implant can be activated by using the smile emote, say *smile to attempt to activate.")
+ return 1
diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm
index 44b33721cf0..c05d52442c1 100644
--- a/code/game/objects/items/weapons/implants/implantchair.dm
+++ b/code/game/objects/items/weapons/implants/implantchair.dm
@@ -135,10 +135,9 @@
for (var/mob/O in viewers(M, null))
O.show_message("\The [M] has been implanted by \the [src].", 1)
- if(imp.implanted(M))
- imp.loc = M
- imp.imp_in = M
- imp.implanted = 1
+ if(imp.handle_implant(M, BP_TORSO))
+ imp.post_implant(M)
+
implant_list -= imp
break
return
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm
index d99c5f5ff24..c1b0d5db8dd 100644
--- a/code/game/objects/items/weapons/implants/implanter.dm
+++ b/code/game/objects/items/weapons/implants/implanter.dm
@@ -56,16 +56,11 @@
add_attack_logs(user,M,"Implanted with [imp.name] using [name]")
- if(src.imp.implanted(M))
- src.imp.loc = M
- src.imp.imp_in = M
- src.imp.implanted = 1
- if (ishuman(M))
- var/mob/living/carbon/human/H = M
- var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
- affected.implants += src.imp
- imp.part = affected
+ if(imp.handle_implant(M))
+ imp.post_implant(M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
BITSET(H.hud_updateflag, IMPLOYAL_HUD)
BITSET(H.hud_updateflag, BACKUP_HUD) //VOREStation Add - Backup HUD updates
diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implantfreedom.dm
index 92021a46a2f..fab692775d3 100644
--- a/code/game/objects/items/weapons/implants/implantfreedom.dm
+++ b/code/game/objects/items/weapons/implants/implantfreedom.dm
@@ -16,7 +16,9 @@
/obj/item/weapon/implant/freedom/trigger(emote, mob/living/carbon/source as mob)
- if (src.uses < 1) return 0
+ if (src.uses < 1)
+ return 0
+
if (emote == src.activation_emote)
src.uses--
source << "You feel a faint click."
@@ -46,13 +48,9 @@
W.layer = initial(W.layer)
return
-
-/obj/item/weapon/implant/freedom/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/freedom/post_implant(mob/source)
source.mind.store_memory("Freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0)
source << "The implanted freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate."
- listening_objects |= src
- return 1
-
/obj/item/weapon/implant/freedom/get_data()
var/dat = {"
diff --git a/code/game/objects/items/weapons/implants/implantlanguage.dm b/code/game/objects/items/weapons/implants/implantlanguage.dm
index d813a8d3888..7c6e33508b0 100644
--- a/code/game/objects/items/weapons/implants/implantlanguage.dm
+++ b/code/game/objects/items/weapons/implants/implantlanguage.dm
@@ -4,7 +4,26 @@
/obj/item/weapon/implant/language
name = "GalCom language implant"
- desc = "An implant allowing someone to speak and hear the range of frequencies used in Galactic Common, as well as produce any phonemes that they usually cannot. Only helps with hearing and producing sounds, not understanding them."
+ desc = "An implant allowing someone to speak the range of frequencies used in Galactic Common, as well as produce any phonemes that they usually cannot. Only helps with producing sounds, not understanding them."
+ var/list/languages = list(LANGUAGE_GALCOM) // List of languages that this assists with
+
+/obj/item/weapon/implant/language/post_implant(mob/M) // Amends the mob's voice organ, then deletes itself
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/internal/voicebox/V = locate() in H.internal_organs
+ if(V)
+ var/list/need_amend = list() // If they've already got all the languages they need, then they don't need this implant to do anything
+ for(var/L in languages)
+ if(L in V.will_assist_languages)
+ continue
+ else
+ need_amend |= L
+ if(LAZYLEN(need_amend))
+ if(V.robotic < ORGAN_ASSISTED)
+ V.mechassist()
+ for(var/L in need_amend)
+ V.add_assistable_langs(L)
+ qdel_null(src)
/obj/item/weapon/implant/language/get_data()
var/dat = {"
@@ -14,16 +33,19 @@
Important Notes: Affects hearing and speech.
Implant Details:
-Function: Allows a being otherwise incapable to both hear the frequencies Galactic Common is generally spoken at, as well as to produce the phonemes of the language.
+Function: Allows a being otherwise incapable of speaking Galactic Common to produce the phonemes of the language.
Special Features: None.
Integrity: Implant will function for expected life, barring physical damage."}
return dat
+
+// EAL Implant
/obj/item/weapon/implant/language/eal
name = "EAL language implant"
- desc = "An implant allowing an organic to both hear and speak Encoded Audio Language accurately. Only helps with hearing and producing sounds, not understanding them."
+ desc = "An implant allowing an organic to speak Encoded Audio Language passably. Only helps with producing sounds, not understanding them."
+ languages = list(LANGUAGE_EAL)
-/obj/item/weapon/implant/language/get_data()
+/obj/item/weapon/implant/language/eal/get_data()
var/dat = {"
Implant Specifications:
Name: Vey-Med L-2 Encoded Audio Language Implant
@@ -31,7 +53,25 @@
Important Notes: Affects hearing and speech.
Implant Details:
-Function: Allows an organic to accurately process and speak Encoded Audio Language.
+Function: Allows an organic to accurately speak Encoded Audio Language.
+Special Features: None.
+Integrity: Implant will function for expected life, barring physical damage."}
+ return dat
+
+/obj/item/weapon/implant/language/skrellian
+ name = "Skrellian language implant"
+ desc = "An implant allowing someone to speak the range of frequencies used in Skrellian, as well as produce any phonemes that they usually cannot. Only helps with hearing and producing sounds, not understanding them."
+ languages = list(LANGUAGE_SKRELLIAN)
+
+/obj/item/weapon/implant/language/skrellian/get_data()
+ var/dat = {"
+Implant Specifications:
+Name: Vey-Med L-1 Galactic Common Implant
+Life: 5 years
+Important Notes: Affects hearing and speech.
+
+Implant Details:
+Function: Allows a being otherwise incapable of speaking Skrellian to produce the phonemes of the language.
Special Features: None.
Integrity: Implant will function for expected life, barring physical damage."}
return dat
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implantreagent_vr.dm b/code/game/objects/items/weapons/implants/implantreagent_vr.dm
index 1c4e9a9b040..83a586d2ba1 100644
--- a/code/game/objects/items/weapons/implants/implantreagent_vr.dm
+++ b/code/game/objects/items/weapons/implants/implantreagent_vr.dm
@@ -30,7 +30,7 @@
update()
return
-/obj/item/weapon/implant/reagent_generator/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
assigned_proc = new assigned_proc(source, verb_name, verb_desc)
diff --git a/code/game/objects/items/weapons/implants/implantuplink.dm b/code/game/objects/items/weapons/implants/implantuplink.dm
index 644ebf1bb7a..82809cfe61a 100644
--- a/code/game/objects/items/weapons/implants/implantuplink.dm
+++ b/code/game/objects/items/weapons/implants/implantuplink.dm
@@ -11,15 +11,13 @@
..()
return
-/obj/item/weapon/implant/uplink/implanted(mob/source)
+/obj/item/weapon/implant/uplink/post_implant(mob/source)
+ listening_objects |= src
activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink")
source.mind.store_memory("Uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0)
source << "The implanted uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate."
- listening_objects |= src
- return 1
-
/obj/item/weapon/implant/uplink/trigger(emote, mob/source as mob)
if(hidden_uplink && usr == source) // Let's not have another people activate our uplink
hidden_uplink.check_trigger(source, emote, activation_emote)
- return
+ return
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm
index 43183d45f44..aec6a790b21 100644
--- a/code/game/objects/items/weapons/policetape.dm
+++ b/code/game/objects/items/weapons/policetape.dm
@@ -4,6 +4,9 @@
icon = 'icons/policetape.dmi'
icon_state = "tape"
w_class = ITEMSIZE_SMALL
+
+ toolspeed = 3 //You can use it in surgery. It's stupid, but you can.
+
var/turf/start
var/turf/end
var/tape_type = /obj/item/tape
diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm
index 5a575155888..e3afddba4c5 100644
--- a/code/game/objects/items/weapons/tape.dm
+++ b/code/game/objects/items/weapons/tape.dm
@@ -5,8 +5,12 @@
icon_state = "taperoll"
w_class = ITEMSIZE_TINY
+ toolspeed = 2 //It is now used in surgery as a not awful, but probably dangerous option, due to speed.
+
/obj/item/weapon/tape_roll/attack(var/mob/living/carbon/human/H, var/mob/user)
if(istype(H))
+ if(user.a_intent == I_HELP)
+ return
var/can_place = 0
if(istype(user, /mob/living/silicon/robot))
can_place = 1
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index a10d8db9999..1f1dfbf36ca 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -84,16 +84,16 @@
if(rotting)
if(reinf_material)
- user << "\The [reinf_material.display_name] feels porous and crumbly."
+ to_chat(user, "\The [reinf_material.display_name] feels porous and crumbly.")
else
- user << "\The [material.display_name] crumbles under your touch!"
+ to_chat(user, "\The [material.display_name] crumbles under your touch!")
dismantle_wall()
return 1
if(..()) return 1
if(!can_open)
- user << "You push the wall, but nothing happens."
+ to_chat(user, "You push the wall, but nothing happens.")
playsound(src, 'sound/weapons/Genhit.ogg', 25, 1)
else
toggle_open(user)
@@ -138,11 +138,12 @@
user.setClickCooldown(user.get_attack_speed(W))
if (!user.)
- user << "You don't have the dexterity to do this!"
+ to_chat(user, "You don't have the dexterity to do this!")
return
//get the user's location
- if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such
+ if(!istype(user.loc, /turf))
+ return //can't do this stuff whilst inside objects and such
if(W)
radiate()
@@ -181,13 +182,13 @@
if(istype(W, /obj/item/weapon/weldingtool) )
var/obj/item/weapon/weldingtool/WT = W
if( WT.remove_fuel(0,user) )
- user << "You burn away the fungi with \the [WT]."
+ to_chat(user, "You burn away the fungi with \the [WT].")
playsound(src, WT.usesound, 10, 1)
for(var/obj/effect/overlay/wallrot/WR in src)
qdel(WR)
return
else if(!is_sharp(W) && W.force >= 10 || W.force >= 20)
- user << "\The [src] crumbles away under the force of your [W.name]."
+ to_chat(user, "\The [src] crumbles away under the force of your [W.name].")
src.dismantle_wall(1)
return
@@ -207,7 +208,7 @@
var/obj/item/weapon/melee/energy/blade/EB = W
EB.spark_system.start()
- user << "You slash \the [src] with \the [EB]; the thermite ignites!"
+ to_chat(user, "You slash \the [src] with \the [EB]; the thermite ignites!")
playsound(src, "sparks", 50, 1)
playsound(src, 'sound/weapons/blade1.ogg', 50, 1)
@@ -224,13 +225,13 @@
return
if(WT.remove_fuel(0,user))
- user << "You start repairing the damage to [src]."
+ to_chat(user, "You start repairing the damage to [src].")
playsound(src.loc, WT.usesound, 100, 1)
if(do_after(user, max(5, damage / 5) * WT.toolspeed) && WT && WT.isOn())
- user << "You finish repairing the damage to [src]."
+ to_chat(user, "You finish repairing the damage to [src].")
take_damage(-damage)
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
user.update_examine_panel(src)
return
@@ -247,7 +248,7 @@
if(!WT.isOn())
return
if(!WT.remove_fuel(0,user))
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
dismantle_verb = "cutting"
dismantle_sound = W.usesound
@@ -264,7 +265,7 @@
if(dismantle_verb)
- user << "You begin [dismantle_verb] through the outer plating."
+ to_chat(user, "You begin [dismantle_verb] through the outer plating.")
if(dismantle_sound)
playsound(src, dismantle_sound, 100, 1)
@@ -274,7 +275,7 @@
if(!do_after(user,cut_delay * W.toolspeed))
return
- user << "You remove the outer plating."
+ to_chat(user, "You remove the outer plating.")
dismantle_wall()
user.visible_message("The wall was torn open by [user]!")
return
@@ -287,24 +288,24 @@
playsound(src, W.usesound, 100, 1)
construction_stage = 5
user.update_examine_panel(src)
- user << "You cut through the outer grille."
+ to_chat(user, "You cut through the outer grille.")
update_icon()
return
if(5)
if (istype(W, /obj/item/weapon/screwdriver))
- user << "You begin removing the support lines."
+ to_chat(user, "You begin removing the support lines.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 5)
return
construction_stage = 4
user.update_examine_panel(src)
update_icon()
- user << "You unscrew the support lines."
+ to_chat(user, "You unscrew the support lines.")
return
else if (istype(W, /obj/item/weapon/wirecutters))
construction_stage = 6
user.update_examine_panel(src)
- user << "You mend the outer grille."
+ to_chat(user, "You mend the outer grille.")
playsound(src, W.usesound, 100, 1)
update_icon()
return
@@ -317,51 +318,51 @@
if(WT.remove_fuel(0,user))
cut_cover=1
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
else if (istype(W, /obj/item/weapon/pickaxe/plasmacutter))
cut_cover = 1
if(cut_cover)
- user << "You begin slicing through the metal cover."
+ to_chat(user, "You begin slicing through the metal cover.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user, 60 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4)
return
construction_stage = 3
user.update_examine_panel(src)
update_icon()
- user << "You press firmly on the cover, dislodging it."
+ to_chat(user, "You press firmly on the cover, dislodging it.")
return
else if (istype(W, /obj/item/weapon/screwdriver))
- user << "You begin screwing down the support lines."
+ to_chat(user, "You begin screwing down the support lines.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4)
return
construction_stage = 5
user.update_examine_panel(src)
update_icon()
- user << "You screw down the support lines."
+ to_chat(user, "You screw down the support lines.")
return
if(3)
if (istype(W, /obj/item/weapon/crowbar))
- user << "You struggle to pry off the cover."
+ to_chat(user, "You struggle to pry off the cover.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 3)
return
construction_stage = 2
user.update_examine_panel(src)
update_icon()
- user << "You pry off the cover."
+ to_chat(user, "You pry off the cover.")
return
if(2)
if (istype(W, /obj/item/weapon/wrench))
- user << "You start loosening the anchoring bolts which secure the support rods to their frame."
+ to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 2)
return
construction_stage = 1
user.update_examine_panel(src)
update_icon()
- user << "You remove the bolts anchoring the support rods."
+ to_chat(user, "You remove the bolts anchoring the support rods.")
return
if(1)
var/cut_cover
@@ -370,28 +371,28 @@
if( WT.remove_fuel(0,user) )
cut_cover=1
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter))
cut_cover = 1
if(cut_cover)
- user << "You begin slicing through the support rods."
+ to_chat(user, "You begin slicing through the support rods.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,70 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 1)
return
construction_stage = 0
user.update_examine_panel(src)
update_icon()
- user << "The slice through the support rods."
+ to_chat(user, "The slice through the support rods.")
return
if(0)
if(istype(W, /obj/item/weapon/crowbar))
- user << "You struggle to pry off the outer sheath."
+ to_chat(user, "You struggle to pry off the outer sheath.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || !user || !W || !T )
return
if(user.loc == T && user.get_active_hand() == W )
- user << "You pry off the outer sheath."
+ to_chat(user, "You pry off the outer sheath.")
dismantle_wall()
return
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 13368bb7ed7..1c700eec854 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -33,18 +33,18 @@
/turf/space/attackby(obj/item/C as obj, mob/user as mob)
- if (istype(C, /obj/item/stack/rods))
+ if(istype(C, /obj/item/stack/rods))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
return
var/obj/item/stack/rods/R = C
if (R.use(1))
- user << "Constructing support lattice ..."
+ to_chat(user, "Constructing support lattice ...")
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
ReplaceWithLattice()
return
- if (istype(C, /obj/item/stack/tile/floor))
+ if(istype(C, /obj/item/stack/tile/floor))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
var/obj/item/stack/tile/floor/S = C
@@ -56,7 +56,33 @@
ChangeTurf(/turf/simulated/floor/airless)
return
else
- user << "The plating is going to need some support."
+ to_chat(user, "The plating is going to need some support.")
+
+ if(istype(C, /obj/item/stack/tile/roofing))
+ var/turf/T = GetAbove(src)
+ var/obj/item/stack/tile/roofing/R = C
+
+ // Patch holes in the ceiling
+ if(T)
+ if(istype(T, /turf/simulated/open) || istype(T, /turf/space))
+ // Must be build adjacent to an existing floor/wall, no floating floors
+ var/turf/simulated/A = locate(/turf/simulated/floor) in T.CardinalTurfs()
+ if(!A)
+ A = locate(/turf/simulated/wall) in T.CardinalTurfs()
+ if(!A)
+ to_chat(user, "There's nothing to attach the ceiling to!")
+ return
+
+ if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating
+ T.ReplaceWithLattice()
+ T.ChangeTurf(/turf/simulated/floor)
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] expands the ceiling.", "You expand the ceiling.")
+ else
+ to_chat(user, "There aren't any holes in the ceiling to patch here.")
+ return
+ // Space shouldn't have weather of the sort planets with atmospheres do.
+ // If that's changed, then you'll want to swipe the rest of the roofing code from code/game/turfs/simulated/floor_attackby.dm
return
@@ -64,7 +90,7 @@
/turf/space/Entered(atom/movable/A as mob|obj)
if(movement_disabled)
- usr << "Movement is admin-disabled." //This is to identify lag problems
+ to_chat(usr, "Movement is admin-disabled.") //This is to identify lag problems
return
..()
if ((!(A) || src != A.loc)) return
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index b355ec6328b..1d776866612 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -40,6 +40,7 @@
var/old_affecting_lights = affecting_lights
var/old_lighting_overlay = lighting_overlay
var/old_corners = corners
+ var/old_outdoors = outdoors
//world << "Replacing [src.type] with [N]"
@@ -108,3 +109,4 @@
lighting_build_overlay()
else
lighting_clear_overlay()
+ outdoors = old_outdoors
\ No newline at end of file
diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm
index 22689f17188..13c6e6a767a 100644
--- a/code/modules/admin/verbs/antag-ooc.dm
+++ b/code/modules/admin/verbs/antag-ooc.dm
@@ -12,7 +12,7 @@
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)
+ if(!A || !A.can_speak_aooc || !A.can_hear_aooc)
to_chat(usr, "Sorry, but your antagonist type is not allowed to speak in AOOC.")
return
@@ -36,7 +36,7 @@
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.
+ if((M.mind && M.mind.special_role && A && A.can_hear_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_aooc(msg,src)
\ No newline at end of file
diff --git a/code/modules/artifice/deadringer.dm b/code/modules/artifice/deadringer.dm
new file mode 100644
index 00000000000..99061b6624a
--- /dev/null
+++ b/code/modules/artifice/deadringer.dm
@@ -0,0 +1,184 @@
+/obj/item/weapon/deadringer
+ name = "silver pocket watch"
+ desc = "A fancy silver-plated digital pocket watch. Looks expensive."
+ icon = 'icons/obj/deadringer.dmi'
+ icon_state = "deadringer"
+ w_class = ITEMSIZE_SMALL
+ slot_flags = SLOT_ID | SLOT_BELT | SLOT_TIE
+ origin_tech = list(TECH_ILLEGAL = 3)
+ var/activated = 0
+ var/timer = 0
+ var/bruteloss_prev = 999999
+ var/fireloss_prev = 999999
+ var/mob/living/carbon/human/corpse = null
+ var/mob/living/carbon/human/watchowner = null
+
+
+/obj/item/weapon/deadringer/New()
+ ..()
+ processing_objects |= src
+
+/obj/item/weapon/deadringer/Destroy() //just in case some smartass tries to stay invisible by destroying the watch
+ uncloak()
+ processing_objects -= src
+ ..()
+
+
+/obj/item/weapon/deadringer/dropped()
+ if(timer > 20)
+ uncloak()
+ watchowner = null
+ return
+
+/obj/item/weapon/deadringer/attack_self(var/mob/living/user as mob)
+ var/mob/living/H = src.loc
+ if (!istype(H, /mob/living/carbon/human))
+ to_chat(H,"You have no clue what to do with this thing.")
+ return
+ if(!activated)
+ if(timer == 0)
+ to_chat(H, "You press a small button on [src]'s side. It starts to hum quietly.")
+ bruteloss_prev = H.getBruteLoss()
+ fireloss_prev = H.getFireLoss()
+ activated = 1
+ return
+ else
+ to_chat(H,"You press a small button on [src]'s side. It buzzes a little.")
+ return
+ if(activated)
+ to_chat(H,"You press a small button on [src]'s side. It stops humming.")
+ activated = 0
+ return
+
+
+/obj/item/weapon/deadringer/process()
+ if(activated)
+ if (ismob(src.loc))
+ var/mob/living/carbon/human/H = src.loc
+ watchowner = H
+ if(H.getBruteLoss() > bruteloss_prev || H.getFireLoss() > fireloss_prev)
+ deathprevent()
+ activated = 0
+ if(watchowner.isSynthetic())
+ to_chat(watchowner, "You fade into nothingness! [src]'s screen blinks, being unable to copy your synthetic body!")
+ else
+ to_chat(watchowner, "You fade into nothingness, leaving behind a fake body!")
+ icon_state = "deadringer_cd"
+ timer = 50
+ return
+ if(timer > 0)
+ timer--
+ if(timer == 20)
+ uncloak()
+ if(corpse)
+ new /obj/effect/effect/smoke/chem(corpse.loc)
+ qdel(corpse)
+ if(timer == 0)
+ icon_state = "deadringer"
+ return
+
+
+/obj/item/weapon/deadringer/proc/deathprevent()
+ for(var/mob/living/simple_animal/D in oviewers(7, src))
+ D.LoseTarget()
+ watchowner.emote("deathgasp")
+ watchowner.invisibility = 85
+ watchowner.alpha = 127
+ makeacorpse(watchowner)
+ for(var/mob/living/simple_animal/D in oviewers(7, src))
+ D.LoseTarget()
+ return
+
+/obj/item/weapon/deadringer/proc/uncloak()
+ if(watchowner)
+ watchowner.invisibility = 0
+ watchowner.alpha = 255
+ playsound(get_turf(src), 'sound/effects/uncloak.ogg', 35, 1, -1)
+ return
+
+/obj/item/weapon/deadringer/proc/makeacorpse(var/mob/living/carbon/human/H)
+ if(H.isSynthetic())
+ return
+ corpse = new /mob/living/carbon/human(H.loc)
+ corpse.setDNA(H.dna.Clone())
+ corpse.death(1) //Kills the new mob
+ var/obj/item/clothing/temp = null
+ if(H.get_equipped_item(slot_w_uniform))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/under/chameleon/changeling(corpse), slot_w_uniform)
+ temp = corpse.get_equipped_item(slot_w_uniform)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_w_uniform)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_wear_suit))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/suit/chameleon/changeling(corpse), slot_wear_suit)
+ temp = corpse.get_equipped_item(slot_wear_suit)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_wear_suit)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_shoes))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/shoes/chameleon/changeling(corpse), slot_shoes)
+ temp = corpse.get_equipped_item(slot_shoes)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_shoes)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_gloves))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/gloves/chameleon/changeling(corpse), slot_gloves)
+ temp = corpse.get_equipped_item(slot_gloves)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_gloves)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_l_ear))
+ temp = H.get_equipped_item(slot_l_ear)
+ corpse.equip_to_slot_or_del(new temp.type(corpse), slot_l_ear)
+ temp = corpse.get_equipped_item(slot_l_ear)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_glasses))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/glasses/chameleon/changeling(corpse), slot_glasses)
+ temp = corpse.get_equipped_item(slot_glasses)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_glasses)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_wear_mask))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/mask/chameleon/changeling(corpse), slot_wear_mask)
+ temp = corpse.get_equipped_item(slot_wear_mask)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_wear_mask)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_head))
+ corpse.equip_to_slot_or_del(new /obj/item/clothing/head/chameleon/changeling(corpse), slot_head)
+ temp = corpse.get_equipped_item(slot_head)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_head)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_belt))
+ corpse.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/chameleon/changeling(corpse), slot_belt)
+ temp = corpse.get_equipped_item(slot_belt)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_belt)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ if(H.get_equipped_item(slot_back))
+ corpse.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/chameleon/changeling(corpse), slot_back)
+ temp = corpse.get_equipped_item(slot_back)
+ var/obj/item/clothing/c_type = H.get_equipped_item(slot_back)
+ temp.disguise(c_type.type)
+ temp.canremove = 0
+ corpse.identifying_gender = H.identifying_gender
+ corpse.flavor_texts = H.flavor_texts.Copy()
+ corpse.real_name = H.real_name
+ corpse.name = H.name
+ corpse.set_species(corpse.dna.species)
+ corpse.change_hair(H.h_style)
+ corpse.change_facial_hair(H.f_style)
+ corpse.change_hair_color(H.r_hair, H.g_hair, H.b_hair)
+ corpse.change_facial_hair_color(H.r_facial, H.g_facial, H.b_facial)
+ corpse.change_skin_color(H.r_skin, H.g_skin, H.b_skin)
+ corpse.adjustFireLoss(H.getFireLoss())
+ corpse.adjustBruteLoss(H.getBruteLoss())
+ corpse.UpdateAppearance()
+ corpse.regenerate_icons()
+ for(var/obj/item/organ/internal/I in corpse.internal_organs)
+ var/obj/item/organ/internal/G = I
+ G.Destroy()
+ return
+
+
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 07f45a9c6fd..6b93b33fafc 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -71,8 +71,8 @@ datum/preferences/proc/set_biological_gender(var/gender)
. += "Nickname: "
. += "[pref.nickname]"
. += "
"
- . += "Biological Gender: [gender2text(pref.biological_gender)]
"
- . += "Gender Identity: [gender2text(pref.identifying_gender)]
"
+ . += "Biological Sex: [gender2text(pref.biological_gender)]
"
+ . += "Pronouns: [gender2text(pref.identifying_gender)]
"
. += "Age: [pref.age]
"
. += "Spawn Point: [pref.spawnpoint]
"
if(config.allow_Metadata)
@@ -111,13 +111,13 @@ datum/preferences/proc/set_biological_gender(var/gender)
return TOPIC_NOACTION
else if(href_list["bio_gender"])
- var/new_gender = input(user, "Choose your character's biological gender:", "Character Preference", pref.biological_gender) as null|anything in get_genders()
+ var/new_gender = input(user, "Choose your character's biological sex:", "Character Preference", pref.biological_gender) as null|anything in get_genders()
if(new_gender && CanUseTopic(user))
pref.set_biological_gender(new_gender)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["id_gender"])
- var/new_gender = input(user, "Choose your character's identifying gender:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list
+ var/new_gender = input(user, "Choose your character's pronouns:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list
if(new_gender && CanUseTopic(user))
pref.identifying_gender = new_gender
return TOPIC_REFRESH
@@ -158,4 +158,4 @@ datum/preferences/proc/set_biological_gender(var/gender)
return possible_genders
possible_genders = possible_genders.Copy()
possible_genders |= NEUTER
- return possible_genders
\ No newline at end of file
+ return possible_genders
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm
index 76178dada21..52fce45031e 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm
@@ -116,22 +116,28 @@
path = /obj/item/weapon/cell/device
/datum/gear/utility/implant
- exploitable = 1
-/* VOREStation Edit - Make languages great again
-/datum/gear/utility/implant/eal //This does nothing if you don't actually know EAL.
- display_name = "implant, language, EAL"
- path = /obj/item/weapon/implant/language/eal
- cost = 2
slot = "implant"
- exploitable = 1*/
+ exploitable = 1
/datum/gear/utility/implant/tracking
display_name = "implant, tracking"
path = /obj/item/weapon/implant/tracking/weak
cost = 0 //VOREStation Edit. Changed cost to 0
- slot = "implant"
- exploitable = 1
+/* VOREStation Edit - Make languages great again
+/datum/gear/utility/implant/language
+ cost = 2
+ exploitable = 0
+/datum/gear/utility/implant/language/eal
+ display_name = "vocal synthesizer, EAL"
+ description = "A surgically implanted vocal synthesizer which allows the owner to speak EAL, if they know it."
+ path = /obj/item/weapon/implant/language/eal
+
+/datum/gear/utility/implant/language/skrellian
+ display_name = "vocal synthesizer, Skrellian"
+ description = "A surgically implanted vocal synthesizer which allows the owner to speak Common Skrellian, if they know it."
+ path = /obj/item/weapon/implant/language/skrellian
+*/
/datum/gear/utility/pen
display_name = "Fountain Pen"
path = /obj/item/weapon/pen/fountain
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 6e75d97a0d9..232ef46e3e3 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -53,6 +53,7 @@
recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1)
recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0)
recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20)
+ recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20)
recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60)
recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1)
recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1)
diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm
index d602bf71bb8..40fe94b7f54 100644
--- a/code/modules/mob/language/generic.dm
+++ b/code/modules/mob/language/generic.dm
@@ -133,6 +133,6 @@
key = "s"
flags = SIGNLANG|NO_STUTTER|NONVERBAL
-/datum/language/sign/can_speak_special(var/mob/speaker)
+/datum/language/sign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format
var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands
return (hands || !iscarbon(speaker))
diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm
index c6089a8788e..66e0e5e0f01 100644
--- a/code/modules/mob/language/language.dm
+++ b/code/modules/mob/language/language.dm
@@ -133,7 +133,15 @@
return speech_verb
/datum/language/proc/can_speak_special(var/mob/speaker)
- return 1
+ . = TRUE
+ if(ishuman(speaker))
+ var/mob/living/carbon/human/H = speaker
+ if(src.name in H.species.assisted_langs)
+ . = FALSE
+ var/obj/item/organ/internal/voicebox/vox = locate() in H.internal_organs // Only voiceboxes for now. Maybe someday it'll include other organs, but I'm not that clever
+ if(vox)
+ if(!vox.is_broken() && (src in vox.assists_languages))
+ . = TRUE
// Language handling.
/mob/proc/add_language(var/language)
diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm
index 2c395bca761..c80f606ae6d 100644
--- a/code/modules/mob/language/station.dm
+++ b/code/modules/mob/language/station.dm
@@ -63,6 +63,14 @@
"ka","aasi","far","wa","baq","ara","qara","zir","saam","mak","hrar","nja","rir","khan","jun","dar","rik","kah",
"hal","ket","jurl","mah","tul","cresh","azu","ragh","mro","mra","mrro","mrra")
+/datum/language/tajaran/get_random_name(var/gender)
+ var/new_name = ..(gender,1)
+ if(prob(50))
+ new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]"
+ else
+ new_name += " [..(gender,1)]"
+ return new_name
+
/datum/language/tajaranakhani
name = LANGUAGE_AKHANI
desc = "The language of the sea-faring Njarir'Akhan Tajaran. Borrowing some elements from Siik, the language is distinctly more structured."
@@ -77,15 +85,6 @@
"kar","yar","kzar","rha","hrar","err","fer","rir","rar","yarr","arr","ii'r","jar","kur","ran","rii","ii",
"nai","ou","kah","oa","ama","uuk","bel","chi","ayt","kay","kas","akor","tam","yir","enai")
-/datum/language/tajaran/get_random_name(var/gender)
-
- var/new_name = ..(gender,1)
- if(prob(50))
- new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]"
- else
- new_name += " [..(gender,1)]"
- return new_name
-
/datum/language/tajsign
name = LANGUAGE_ALAI
desc = "A standardized Tajaran sign language that was developed in Zarraya and gradually adopted by other nations, incorporating \
@@ -95,6 +94,19 @@
key = "l"
flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL
+/datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format
+ var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this.
+ if(iscarbon(speaker))
+ var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands
+ if(!hands)
+ return FALSE
+ if(ishuman(speaker))
+ var/mob/living/carbon/human/H = speaker
+ if(H.species.get_bodytype(H) in allowed_species)
+ return TRUE
+
+ return FALSE
+
/datum/language/skrell
name = LANGUAGE_SKRELLIAN
desc = "A set of warbles and hums, the language itself a complex mesh of both melodic and rhythmic components, exceptionally capable of conveying intent and emotion of the speaker."
@@ -161,11 +173,6 @@
syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz","shh","shk")
space_chance = 10
-/datum/language/machine/can_speak_special(var/mob/speaker)
- var/obj/item/weapon/implant/language/eal/beep = locate() in speaker
- return ((beep && beep.implanted) || speaker.isSynthetic() || isvoice(speaker))
- //thank you sweet zuhayr
-
/datum/language/machine/get_random_name()
if(prob(70))
return "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index eb473989f2d..676eedbdd98 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -14,9 +14,10 @@
var/muzzled = is_muzzled()
//var/m_type = 1
- for (var/obj/item/weapon/implant/I in src)
- if (I.implanted)
- I.trigger(act, src)
+ for(var/obj/item/organ/O in src.organs)
+ for (var/obj/item/weapon/implant/I in O)
+ if (I.implanted)
+ I.trigger(act, src)
if(src.stat == 2.0 && (act != "deathgasp"))
return
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 792011043a3..edf1bdd6c6f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -166,25 +166,12 @@
update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message)
if(update) UpdateDamageIcon()
-/mob/living/carbon/human/proc/implant_loadout(var/datum/gear/G = new/datum/gear/utility/implant)
- var/obj/item/weapon/implant/I = new G.path(src)
- I.imp_in = src
- I.implanted = 1
- var/obj/item/organ/external/affected = src.organs_by_name[BP_HEAD]
- affected.implants += I
- I.part = affected
- I.implanted(src)
-
/mob/living/carbon/human/proc/implant_loyalty(override = FALSE) // Won't override by default.
if(!config.use_loyalty_implants && !override) return // Nuh-uh.
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src)
- L.imp_in = src
- L.implanted = 1
- var/obj/item/organ/external/affected = src.organs_by_name[BP_HEAD]
- affected.implants += L
- L.part = affected
- L.implanted(src)
+ if(L.handle_implant(src, BP_HEAD))
+ L.post_implant(src)
/mob/living/carbon/human/proc/is_loyalty_implanted()
for(var/L in src.contents)
@@ -1139,6 +1126,8 @@
remove_language(species.language)
if(species.default_language)
remove_language(species.default_language)
+ for(var/datum/language/L in species.assisted_langs)
+ remove_language(L)
// Clear out their species abilities.
species.remove_inherent_verbs(src)
holder_type = null
diff --git a/code/modules/mob/living/carbon/human/species/outsider/event.dm b/code/modules/mob/living/carbon/human/species/outsider/event.dm
index 3e75acae9c0..477b14c0c46 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/event.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/event.dm
@@ -70,6 +70,7 @@ Variables you may want to make use of are:
num_alternate_languages = 3
species_language = LANGUAGE_GALCOM
secondary_langs = list()
+ assisted_langs = list()
name_language = null // Use the first-name last-name generator rather than a language scrambler
min_age = 0
diff --git a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
index 5d81bb4c9c5..d0f40f693d6 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
@@ -25,6 +25,8 @@
genders = list(NEUTER)
+ assisted_langs = list()
+
/datum/species/shadow/handle_death(var/mob/living/carbon/human/H)
spawn(1)
new /obj/effect/decal/cleanable/ash(H.loc)
diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
index 9fab4751cc7..525a6118826 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
@@ -7,6 +7,7 @@
language = LANGUAGE_GALCOM
species_language = LANGUAGE_VOX
num_alternate_languages = 1
+ assisted_langs = list(LANGUAGE_ROOTGLOBAL)
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong)
rarity_value = 4
blurb = "The Vox are the broken remnants of a once-proud race, now reduced to little more than \
@@ -71,6 +72,7 @@
has_organ = list(
O_HEART = /obj/item/organ/internal/heart/vox,
O_LUNGS = /obj/item/organ/internal/lungs/vox,
+ O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver/vox,
O_KIDNEYS = /obj/item/organ/internal/kidneys/vox,
O_BRAIN = /obj/item/organ/internal/brain/vox,
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index b1557f3a28d..a1d1a932771 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -52,13 +52,17 @@
// Language/culture vars.
var/default_language = LANGUAGE_GALCOM // Default language is used when 'say' is used without modifiers.
var/language = LANGUAGE_GALCOM // Default racial language, if any.
- var/species_language = LANGUAGE_GALCOM // Used on the Character Setup screen
+ var/list/species_language = list(LANGUAGE_GALCOM) // Used on the Character Setup screen
var/list/secondary_langs = list() // The names of secondary languages that are available to this species.
var/list/speech_sounds = list() // A list of sounds to potentially play when speaking.
var/list/speech_chance = list() // The likelihood of a speech sound playing.
var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation
var/name_language = LANGUAGE_GALCOM // The language to use when determining names for this species, or null to use the first name/last name generator
+ // The languages the species can't speak without an assisted organ.
+ // This list is a guess at things that no one other than the parent species should be able to speak
+ var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_TERMINUS, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX)
+
//Soundy emotey things.
var/scream_verb = "screams"
var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace!
@@ -183,6 +187,7 @@
var/list/has_organ = list( // which required-organ checks are conducted.
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
+ O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
diff --git a/code/modules/mob/living/carbon/human/species/station/alraune.dm b/code/modules/mob/living/carbon/human/species/station/alraune.dm
index 0f8d7b5622a..703986ceb58 100644
--- a/code/modules/mob/living/carbon/human/species/station/alraune.dm
+++ b/code/modules/mob/living/carbon/human/species/station/alraune.dm
@@ -3,7 +3,6 @@
name_plural = "Alraunes"
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite)
num_alternate_languages = 2
- language = LANGUAGE_ROOTLOCAL
slowdown = 1 //slow, they're plants. Not as slow as full diona.
total_health = 100 //standard
brute_mod = 1 //nothing special
diff --git a/code/modules/mob/living/carbon/human/species/station/golem.dm b/code/modules/mob/living/carbon/human/species/station/golem.dm
index 9ec7a2b0056..3b091668138 100644
--- a/code/modules/mob/living/carbon/human/species/station/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/station/golem.dm
@@ -11,6 +11,8 @@
spawn_flags = SPECIES_IS_RESTRICTED
siemens_coefficient = 0
+ assisted_langs = list()
+
breath_type = null
poison_type = null
diff --git a/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm b/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm
index 180732b0aaa..56b5c360354 100644
--- a/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm
+++ b/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm
@@ -45,6 +45,7 @@
has_organ = list(
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
+ O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index 01af604992e..b78d5307076 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -30,6 +30,7 @@ var/datum/species/shapeshifter/promethean/prometheans
health_hud_intensity = 2
num_alternate_languages = 3
species_language = LANGUAGE_SOL_COMMON
+ assisted_langs = list(LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) // Prometheans are weird, let's just assume they can use basically any language.
breath_type = null
poison_type = null
diff --git a/code/modules/mob/living/carbon/human/species/station/seromi.dm b/code/modules/mob/living/carbon/human/species/station/seromi.dm
index fe21426805d..6cd1a757cd7 100644
--- a/code/modules/mob/living/carbon/human/species/station/seromi.dm
+++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm
@@ -104,6 +104,7 @@
has_organ = list(
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
+ O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index 19376b10f9d..788ac2bfeb0 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -12,6 +12,7 @@
species_language = LANGUAGE_SOL_COMMON
secondary_langs = list(LANGUAGE_SOL_COMMON, LANGUAGE_TERMINUS)
name_language = null // Use the first-name last-name generator rather than a language scrambler
+ assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX)
min_age = 17
max_age = 130
@@ -217,6 +218,7 @@
has_organ = list( //No appendix.
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
+ O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
@@ -243,6 +245,7 @@
secondary_langs = list(LANGUAGE_SKRELLIAN, LANGUAGE_SCHECHI)
name_language = LANGUAGE_SKRELLIAN
species_language = LANGUAGE_SKRELLIAN
+ assisted_langs = list(LANGUAGE_EAL, LANGUAGE_TERMINUS, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX)
health_hud_intensity = 2
water_movement = -3
@@ -317,13 +320,14 @@
hud_type = /datum/hud_data/diona
siemens_coefficient = 0.3
show_ssd = "completely quiescent"
- num_alternate_languages = 2
- secondary_langs = list(LANGUAGE_ROOTGLOBAL)
- name_language = LANGUAGE_ROOTLOCAL
- species_language = LANGUAGE_ROOTLOCAL
health_hud_intensity = 2.5
item_slowdown_mod = 0.25
+ num_alternate_languages = 2
+ name_language = LANGUAGE_ROOTLOCAL
+ species_language = LANGUAGE_ROOTLOCAL
+ secondary_langs = list(LANGUAGE_ROOTGLOBAL)
+ assisted_langs = list(LANGUAGE_VOX) // Diona are weird, let's just assume they can use basically any language.
min_age = 1
max_age = 300
diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
index b027407cf18..76f82ec5133 100644
--- a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
+++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
@@ -16,6 +16,8 @@
speech_bubble_appearance = "cyber"
+ assisted_langs = list()
+
male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg')
male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg'
diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
index d851c40255f..1d2ce593071 100644
--- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
+++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
@@ -5,6 +5,7 @@
default_language = "Xenomorph"
language = "Hivemind"
+ assisted_langs = list()
unarmed_types = list(/datum/unarmed_attack/claws/strong/xeno, /datum/unarmed_attack/bite/strong/xeno)
hud_type = /datum/hud_data/alien
rarity_value = 3
diff --git a/code/modules/mob/living/silicon/ai/icons.dm b/code/modules/mob/living/silicon/ai/icons.dm
index 2d8bc0d0026..c9891f9ae8a 100644
--- a/code/modules/mob/living/silicon/ai/icons.dm
+++ b/code/modules/mob/living/silicon/ai/icons.dm
@@ -84,6 +84,7 @@ var/list/datum/ai_icon/ai_icons
/datum/ai_icon/glitchman
name = "Glitchman"
alive_icon = "ai-glitchman"
+ dead_icon = "ai-glitchman-crash"
/datum/ai_icon/goon
name = "Goon"
@@ -110,6 +111,7 @@ var/list/datum/ai_icon/ai_icons
name = "Inverted"
alive_icon = "ai-u"
alive_light = "#81DDFF"
+ dead_icon = "ai-u-crash"
/datum/ai_icon/lonestar
name = "Lonestar"
@@ -163,14 +165,87 @@ var/list/datum/ai_icon/ai_icons
/datum/ai_icon/trapped
name = "Trapped"
alive_icon = "ai-hades"
- dead_icon = "ai-hades_dead"
+ dead_icon = "ai-hades-crash"
-/datum/ai_icon/triumvirate_static
+/datum/ai_icon/triumvirate
name = "Triumvirate"
alive_icon = "ai-triumvirate"
alive_light = "#020B2B"
/datum/ai_icon/triumvirate_static
name = "Triumvirate Static"
- alive_icon = "ai-static"
+ alive_icon = "ai-triumvirate-malf"
alive_light = "#020B2B"
+
+//Eros Research Platform Ports
+
+/datum/ai_icon/clown2
+ name = "Honk"
+ alive_icon = "ai-clown2"
+ dead_icon = "ai-clown2-crash"
+
+/datum/ai_icon/boxfort
+ name = "Boxfort"
+ alive_icon = "ai-boxfort"
+ dead_icon = "ai-boxfort_dead"
+
+/datum/ai_icon/ravensdale
+ name = "Integration"
+ alive_icon = "ai-ravensdale"
+ dead_icon = "ai-ravensdale-crash"
+
+/datum/ai_icon/gentoo
+ name = "Gentoo"
+ alive_icon = "ai-gentoo"
+ dead_icon = "ai-gentoo_dead"
+
+/datum/ai_icon/serithi
+ name = "Mechanicus"
+ alive_icon = "ai-serithi"
+ dead_icon = "ai-serithi-crash"
+
+/datum/ai_icon/alien
+ name = "Xenomorph"
+ alive_icon = "ai-alien"
+ dead_icon = "ai-alien-crash"
+
+/datum/ai_icon/syndicat
+ name = "Syndi-cat"
+ alive_icon = "ai-syndicatmeow"
+
+/datum/ai_icon/wasp
+ name = "Wasp"
+ alive_icon = "ai-wasp"
+
+/datum/ai_icon/house
+ name = "Doctor"
+ alive_icon = "ai-house"
+
+/datum/ai_icon/fabulous
+ name = "Fabulous"
+ alive_icon = "ai-fabulous"
+
+/datum/ai_icon/yesman
+ name = "Yes Man"
+ alive_icon = "ai-yes-man"
+ dead_icon = "ai-alien-crash"
+
+/datum/ai_icon/royal
+ name = "Royal"
+ alive_icon = "ai-royal"
+
+/datum/ai_icon/pirate
+ name = "Pirate"
+ alive_icon = "ai-pirate"
+
+/datum/ai_icon/gygas
+ name = "Love"
+ alive_icon = "ai-gygas"
+
+/datum/ai_icon/xerxes
+ name = "Xerxes"
+ alive_icon = "ai-xerxes"
+
+/datum/ai_icon/godfrey
+ name = "Godfrey"
+ alive_icon = "ai-godfrey"
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
index 12b44099804..04a96408b3e 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
@@ -216,6 +216,7 @@ var/global/list/robot_modules = list(
..()
src.modules += new /obj/item/device/healthanalyzer(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src)
+ src.modules += new /obj/item/weapon/autopsy_scanner(src)
src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src)
src.modules += new /obj/item/weapon/surgical/hemostat/cyborg(src)
src.modules += new /obj/item/weapon/surgical/retractor/cyborg(src)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
index ac41265fac1..63e4f359be0 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
@@ -148,6 +148,7 @@
src.modules += new /obj/item/weapon/reagent_containers/borghypo/merc(src)
// Surgery things.
+ src.modules += new /obj/item/weapon/autopsy_scanner(src)
src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src)
src.modules += new /obj/item/weapon/surgical/hemostat/cyborg(src)
src.modules += new /obj/item/weapon/surgical/retractor/cyborg(src)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 566af1d8056..6eb4f221645 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -796,6 +796,8 @@
var/mob/living/L = target_mob
if(L.stat != DEAD)
return 1
+ if(L.invisibility < INVISIBILITY_LEVEL_ONE)
+ return 1
if (istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
if (M.occupant)
@@ -915,6 +917,8 @@
continue
else if(L in friends)
continue
+ else if(L.invisibility >= INVISIBILITY_LEVEL_ONE)
+ continue
else if(!SA_attackable(L))
continue
else if(!special_target_check(L))
@@ -1242,7 +1246,7 @@
ai_log("AttackTarget() Bailing because we're disabled",2)
LoseTarget()
return 0
- if(!target_mob || !SA_attackable(target_mob))
+ if(!target_mob || !SA_attackable(target_mob) || (target_mob.invisibility >= INVISIBILITY_LEVEL_ONE)) //if the target went invisible, you can't follow it
LoseTarget()
return 0
if(!(target_mob in ListTargets(view_range)))
diff --git a/code/modules/organs/internal/voicebox.dm b/code/modules/organs/internal/voicebox.dm
new file mode 100644
index 00000000000..4de69fe8f2b
--- /dev/null
+++ b/code/modules/organs/internal/voicebox.dm
@@ -0,0 +1,42 @@
+/*
+ * Voicebox/Vocal Synthesizers
+ * TL;DR: Assists with speaking languages that a species doesn't normally have,
+ * such as EAL. Not standard or organic, because at the moment it's undesireable to completely mute characters.
+ */
+
+/obj/item/organ/internal/voicebox
+ name = "larynx"
+ icon_state = "larynx"
+ parent_organ = BP_TORSO // We don't have a neck area
+ organ_tag = O_VOICE
+ will_assist_languages = list(LANGUAGE_GALCOM)
+
+/obj/item/organ/internal/voicebox/New()
+ ..()
+ amend_assist_langs()
+
+/obj/item/organ/internal/voicebox/proc/amend_assist_langs() // Adds the list of language datums assisted by the voicebox to the list used in speaking
+ for(var/L in will_assist_languages)
+ assists_languages |= all_languages[L]
+
+/obj/item/organ/internal/voicebox/proc/add_assistable_langs(var/language) // Adds a new language (by string/define) to the list of things the voicebox can assist
+ will_assist_languages |= language
+ amend_assist_langs() // Can't think of a better place to put this, makes the voicebox actually start to assist with the added language
+
+/////////////////////////////////
+// Voicebox Subtypes
+/////////////////////////////////
+
+/obj/item/organ/internal/voicebox/assist // In the off chance we get a species that doesn't speak GalCom by default
+
+/obj/item/organ/internal/voicebox/assist/New()
+ ..()
+ mechassist()
+
+/obj/item/organ/internal/voicebox/robot
+ name = "vocal synthesizer"
+ will_assist_languages = list(LANGUAGE_GALCOM, LANGUAGE_EAL) // Synthetics spawn with this by default
+
+/obj/item/organ/internal/voicebox/robot/New()
+ ..()
+ robotize()
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index d649b951b06..f07a6b3192b 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -31,6 +31,10 @@ var/list/organ_cache = list()
var/rejecting // Is this organ already being rejected?
var/preserved = 0 // If this is 1, prevents organ decay.
+ // Language vars. Putting them here in case we decide to do something crazy with sign-or-other-nonverbal languages.
+ var/list/will_assist_languages = list()
+ var/list/datum/language/assists_languages = list()
+
/obj/item/organ/Destroy()
if(owner) owner = null
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index a6c89678d52..c3c709852d0 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -72,6 +72,8 @@
var/open = 0
var/stage = 0
var/cavity = 0
+ var/burn_stage = 0 //Surgical repair stage for burn.
+ var/brute_stage = 0 //Surgical repair stage for brute.
// HUD element variable, see organ_icon.dm get_damage_hud_image()
var/image/hud_damage_image
diff --git a/code/modules/organs/robolimbs_vr.dm b/code/modules/organs/robolimbs_vr.dm
index ee689e32375..cdf873b2ec4 100644
--- a/code/modules/organs/robolimbs_vr.dm
+++ b/code/modules/organs/robolimbs_vr.dm
@@ -86,6 +86,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Tajara"
/obj/item/weapon/disk/limb/dsi_tajaran
@@ -99,6 +100,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Unathi"
/obj/item/weapon/disk/limb/dsi_lizard
@@ -112,6 +114,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Sergal"
/obj/item/weapon/disk/limb/dsi_sergal
@@ -125,6 +128,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Nevrean"
/obj/item/weapon/disk/limb/dsi_nevrean
@@ -138,6 +142,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Vulpkanin"
/obj/item/weapon/disk/limb/dsi_vulpkanin
@@ -151,6 +156,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Akula"
/obj/item/weapon/disk/limb/dsi_akula
@@ -164,6 +170,7 @@
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
+ skin_tone = 1
suggested_species = "Vasilissan"
/obj/item/weapon/disk/limb/dsi_spider
@@ -174,6 +181,7 @@
desc = "This limb has a thin synthflesh casing with a few connection ports."
icon = 'icons/mob/human_races/cyberlimbs/DSITeshari/dsi_teshari.dmi'
lifelike = 1
+ skin_tone = 1
suggested_species = "Teshari"
/datum/robolimb/dsi_teshari/New()
diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm
index 449d7c51371..568d45088cd 100644
--- a/code/modules/organs/subtypes/standard.dm
+++ b/code/modules/organs/subtypes/standard.dm
@@ -23,10 +23,11 @@
organ_rel_size = 70
base_miss_chance = 10
-/obj/item/organ/external/chest/robotize(var/company, var/skip_prosthetics = 0, var/keep_organs = 0)
+/obj/item/organ/external/chest/robotize()
if(..() && robotic != ORGAN_NANOFORM) //VOREStation Edit
- // Give them a new cell.
- owner.internal_organs_by_name["cell"] = new /obj/item/organ/internal/cell(owner,1)
+ // Give them fancy new organs.
+ owner.internal_organs_by_name[O_CELL] = new /obj/item/organ/internal/cell(owner,1)
+ owner.internal_organs_by_name[O_VOICE] = new /obj/item/organ/internal/voicebox/robot(owner, 1)
/obj/item/organ/external/chest/handle_germ_effects()
. = ..() //Should return an infection level
diff --git a/code/modules/power/fusion/core/core_control.dm b/code/modules/power/fusion/core/core_control.dm
index bb4e04b1e90..54d96883a74 100644
--- a/code/modules/power/fusion/core/core_control.dm
+++ b/code/modules/power/fusion/core/core_control.dm
@@ -3,21 +3,20 @@
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "core_control"
light_color = COLOR_ORANGE
-
+ circuit = /obj/item/weapon/circuitboard/fusion_core_control
var/id_tag
var/scan_range = 25
var/list/connected_devices = list()
var/obj/machinery/power/fusion_core/cur_viewed_device
/obj/machinery/computer/fusion_core_control/attackby(var/obj/item/thing, var/mob/user)
+ ..()
if(ismultitool(thing))
var/new_ident = input("Enter a new ident tag.", "Core Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
cur_viewed_device = null
return
- else
- return ..()
/obj/machinery/computer/fusion_core_control/attack_ai(mob/user)
attack_hand(user)
@@ -28,6 +27,11 @@
/obj/machinery/computer/fusion_core_control/interact(mob/user)
+ if(stat & (BROKEN|NOPOWER))
+ user.unset_machine()
+ user << browse(null, "window=fusion_control")
+ return
+
if(!cur_viewed_device || !check_core_status(cur_viewed_device))
cur_viewed_device = null
@@ -174,3 +178,19 @@
if(C.idle_power_usage > C.avail())
return
. = 1
+
+/obj/machinery/computer/fusion_core_control/update_icon()
+ if(stat & (BROKEN))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "broken"
+ set_light(0)
+
+ if(stat & (NOPOWER))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "computer"
+ set_light(0)
+
+ if(!stat & (BROKEN|NOPOWER))
+ icon = initial(icon)
+ icon_state = initial(icon_state)
+ set_light(light_range_on, light_power_on)
diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm
index 1efb09d777b..f5d85fb4bf6 100644
--- a/code/modules/power/fusion/core/core_field.dm
+++ b/code/modules/power/fusion/core/core_field.dm
@@ -35,7 +35,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics,
/obj/machinery/air_sensor,
- /mob/observer/dead,
+ /mob/observer,
/obj/machinery/power/hydromagnetic_trap
)
@@ -672,4 +672,4 @@
#undef FUSION_HEAT_CAP
#undef FUSION_MAX_ENVIRO_HEAT
-#undef PLASMA_TEMP_RADIATION_DIVISIOR
\ No newline at end of file
+#undef PLASMA_TEMP_RADIATION_DIVISIOR
diff --git a/code/modules/power/fusion/fuel_assembly/fuel_control.dm b/code/modules/power/fusion/fuel_assembly/fuel_control.dm
index 6d95e358d86..e765c4d4959 100644
--- a/code/modules/power/fusion/fuel_assembly/fuel_control.dm
+++ b/code/modules/power/fusion/fuel_assembly/fuel_control.dm
@@ -2,6 +2,7 @@
name = "fuel injection control computer"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "fuel"
+ circuit = /obj/item/weapon/circuitboard/fusion_fuel_control
var/id_tag
var/scan_range = 25
@@ -94,9 +95,25 @@
/obj/machinery/computer/fusion_fuel_control/attackby(var/obj/item/W, var/mob/user)
+ ..()
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Fuel Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
- return ..()
+
+/obj/machinery/computer/fusion_fuel_control/update_icon()
+ if(stat & (BROKEN))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "broken"
+ set_light(0)
+
+ if(stat & (NOPOWER))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "computer"
+ set_light(0)
+
+ if(!stat & (BROKEN|NOPOWER))
+ icon = initial(icon)
+ icon_state = initial(icon_state)
+ set_light(light_range_on, light_power_on)
diff --git a/code/modules/power/fusion/gyrotron/gyrotron_control.dm b/code/modules/power/fusion/gyrotron/gyrotron_control.dm
index 9f6c59c7537..eb735a81f34 100644
--- a/code/modules/power/fusion/gyrotron/gyrotron_control.dm
+++ b/code/modules/power/fusion/gyrotron/gyrotron_control.dm
@@ -3,6 +3,7 @@
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "engine"
light_color = COLOR_BLUE
+ circuit = /obj/item/weapon/circuitboard/gyrotron_control
var/id_tag
var/scan_range = 25
@@ -16,6 +17,11 @@
/obj/machinery/computer/gyrotron_control/interact(var/mob/user)
+ if(stat & (BROKEN|NOPOWER))
+ user.unset_machine()
+ user << browse(null, "window=gyrotron_controller_[id_tag]")
+ return
+
if(!id_tag)
to_chat(user, "This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.")
return
@@ -89,9 +95,25 @@
return 0
/obj/machinery/computer/gyrotron_control/attackby(var/obj/item/W, var/mob/user)
+ ..()
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Gyrotron Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
- return ..()
+
+/obj/machinery/computer/gyrotron_control/update_icon()
+ if(stat & (BROKEN))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "broken"
+ set_light(0)
+
+ if(stat & (NOPOWER))
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "computer"
+ set_light(0)
+
+ if(!stat & (BROKEN|NOPOWER))
+ icon = initial(icon)
+ icon_state = initial(icon_state)
+ set_light(light_range_on, light_power_on)
diff --git a/code/modules/resleeving/implant.dm b/code/modules/resleeving/implant.dm
index 0bfe571a8b9..adb3d38e1c3 100644
--- a/code/modules/resleeving/implant.dm
+++ b/code/modules/resleeving/implant.dm
@@ -27,13 +27,9 @@
SStranscore.implants -= src
return ..()
-/obj/item/weapon/implant/backup/implanted(var/mob/living/carbon/human/H)
- ..()
+/obj/item/weapon/implant/backup/post_implant(var/mob/living/carbon/human/H)
if(istype(H))
- var/obj/item/weapon/implant/backup/other_imp = locate(/obj/item/weapon/implant/backup,H)
- if(other_imp && other_imp.imp_in == H)
- qdel(other_imp) //implant fight
-
+ BITSET(H.hud_updateflag, BACKUP_HUD)
SStranscore.implants |= src
return 1
@@ -107,18 +103,10 @@
M.visible_message("[M] has been backup implanted by [user].")
var/obj/item/weapon/implant/backup/imp = imps[imps.len]
- if(imp.implanted(M))
- imp.forceMove(M)
+ if(imp.handle_implant(M,user.zone_sel.selecting))
+ imp.post_implant(M)
imps -= imp
- imp.imp_in = M
- imp.implanted = 1
add_attack_logs(user,M,"Implanted backup implant")
- if (ishuman(M))
- var/mob/living/carbon/human/H = M
- var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
- affected.implants += imp
- imp.part = affected
- BITSET(H.hud_updateflag, BACKUP_HUD)
update()
diff --git a/code/modules/resleeving/machines.dm b/code/modules/resleeving/machines.dm
index 787d867eb89..69f0cfebd1a 100644
--- a/code/modules/resleeving/machines.dm
+++ b/code/modules/resleeving/machines.dm
@@ -538,14 +538,8 @@
//Give them a backup implant
var/obj/item/weapon/implant/backup/new_imp = new()
- if(new_imp.implanted(occupant))
- new_imp.loc = occupant
- new_imp.imp_in = occupant
- new_imp.implanted = 1
- //Put it in the head! Makes sense.
- var/obj/item/organ/external/affected = occupant.get_organ(BP_HEAD)
- affected.implants += new_imp
- new_imp.part = affected
+ if(new_imp.handle_implant(occupant, BP_HEAD))
+ new_imp.post_implant(occupant)
//Inform them and make them a little dizzy.
if(confuse_amount + blur_amount <= 16)
diff --git a/code/modules/surgery/external_repair.dm b/code/modules/surgery/external_repair.dm
new file mode 100644
index 00000000000..b26d803b343
--- /dev/null
+++ b/code/modules/surgery/external_repair.dm
@@ -0,0 +1,215 @@
+//Procedures in this file: Organic limb repair
+//////////////////////////////////////////////////////////////////
+// LIMB REPAIR SURGERY //
+//////////////////////////////////////////////////////////////////
+/datum/surgery_step/repairflesh/
+ priority = 1
+ can_infect = 1
+ blood_level = 1
+ req_open = 1
+
+/datum/surgery_step/repairflesh/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work.
+ return 0
+ if (isslime(target))
+ return 0
+ if (target_zone == O_EYES || target_zone == O_MOUTH)
+ return 0
+ if (!hasorgans(target))
+ return 0
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if (affected == null)
+ return 0
+ if (affected.is_stump())
+ return 0
+ if (affected.robotic >= ORGAN_ROBOT)
+ return 0
+ return 1
+
+
+//////////////////////////////////////////////////////////////////
+// SCAN STEP //
+//////////////////////////////////////////////////////////////////
+
+/datum/surgery_step/repairflesh/scan_injury
+ allowed_tools = list(
+ /obj/item/weapon/autopsy_scanner = 100,
+ /obj/item/device/healthanalyzer = 80,
+ /obj/item/device/analyzer = 10
+ )
+
+ priority = 2
+
+ can_infect = 0 //The only exception here. Sweeping a scanner probably won't transfer many germs.
+
+ min_duration = 20
+ max_duration = 40
+
+/datum/surgery_step/repairflesh/scan_injury/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if(..())
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(affected.burn_stage || affected.brute_stage)
+ return 0
+ return 1
+ return 0
+
+/datum/surgery_step/repairflesh/scan_injury/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user] begins scanning [target]'s [affected] with \the [tool].", \
+ "You begin scanning [target]'s [affected] with \the [tool].")
+ ..()
+
+/datum/surgery_step/repairflesh/scan_injury/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user] finishes scanning [target]'s [affected].", \
+ "You finish scanning [target]'s [affected].")
+ if(affected.brute_dam)
+ to_chat(user, "The muscle in [target]'s [affected] is notably bruised.")
+ if(affected.status & ORGAN_BROKEN)
+ to_chat(user, "\The [target]'s [affected] is broken!")
+ affected.brute_stage = max(1, affected.brute_stage)
+ if(affected.burn_dam)
+ to_chat(user, "\The muscle in [target]'s [affected] is notably charred.")
+ affected.burn_stage = max(1, affected.burn_stage)
+
+/datum/surgery_step/repairflesh/scan_injury/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user]'s hand slips, dropping \the [tool] onto [target]'s [affected]!" , \
+ "Your hand slips, dropping \the [tool] onto [target]'s [affected]!" )
+ affected.createwound(BRUISE, 10)
+
+//////////////////////////////////////////////////////////////////
+// BURN STEP //
+//////////////////////////////////////////////////////////////////
+
+/datum/surgery_step/repairflesh/repair_burns
+ allowed_tools = list(
+ /obj/item/stack/medical/advanced/ointment = 100,
+ /obj/item/weapon/surgical/FixOVein = 100,
+ /obj/item/weapon/surgical/hemostat = 60,
+ /obj/item/stack/medical/ointment = 50,
+ /obj/item/weapon/tape_roll = 30,
+ /obj/item/taperoll = 10
+ )
+
+ priority = 3
+
+ min_duration = 90
+ max_duration = 120
+
+/datum/surgery_step/repairflesh/repair_burns/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if(..())
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(affected.burn_stage < 1 || !(affected.burn_dam))
+ return 0
+ if(affected.burn_dam < affected.brute_dam)
+ return 0
+ return 1
+ return 0
+
+/datum/surgery_step/repairflesh/repair_burns/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll))
+ user.visible_message("[user] begins taping up [target]'s [affected] with \the [tool].", \
+ "You begin taping up [target]'s [affected] with \the [tool].")
+ affected.jostle_bone(10)
+ else if(istype(tool, /obj/item/weapon/surgical/hemostat) || istype(tool, /obj/item/weapon/surgical/FixOVein))
+ user.visible_message("[user] begins mending the charred blood vessels in [target]'s [affected] with \the [tool].", \
+ "You begin mending the charred blood vessels in [target]'s [affected] with \the [tool].")
+ else
+ user.visible_message("[user] begins coating the charred tissue in [target]'s [affected] with \the [tool].", \
+ "You begin coating the charred tissue in [target]'s [affected] with \the [tool].")
+ ..()
+
+/datum/surgery_step/repairflesh/repair_burns/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll))
+ user.visible_message("[user] finishes taping up [target]'s [affected] with \the [tool].", \
+ "You finish taping up [target]'s [affected] with \the [tool].")
+ affected.createwound(BRUISE, 10)
+ affected.heal_damage(0, 25, 0, 0)
+ if(!(affected.burn_dam))
+ affected.burn_stage = 0
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/T = tool
+ T.use(1)
+ ..()
+
+/datum/surgery_step/repairflesh/repair_burns/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user]'s hand slips, tearing up [target]'s [affected] with \the [tool].", \
+ "Your hand slips, tearing up [target]'s [affected] with \the [tool].")
+ affected.createwound(BRUISE, 10)
+ affected.createwound(CUT, 5)
+ if(istype(tool, /obj/item/stack) && prob(30))
+ var/obj/item/stack/T = tool
+ T.use(1)
+ ..()
+
+//////////////////////////////////////////////////////////////////
+// BRUTE STEP //
+//////////////////////////////////////////////////////////////////
+
+/datum/surgery_step/repairflesh/repair_brute
+ allowed_tools = list(
+ /obj/item/stack/medical/advanced/bruise_pack = 100,
+ /obj/item/weapon/surgical/cautery = 100,
+ /obj/item/weapon/surgical/bonesetter = 60,
+ /obj/item/stack/medical/bruise_pack = 50,
+ /obj/item/weapon/tape_roll = 40,
+ /obj/item/taperoll = 10
+ )
+
+ priority = 3
+
+ min_duration = 90
+ max_duration = 120
+
+/datum/surgery_step/repairflesh/repair_brute/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if(..())
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(affected.brute_stage < 1 || !(affected.brute_dam))
+ return 0
+ if(affected.brute_dam < affected.burn_dam)
+ return 0
+ return 1
+ return 0
+
+/datum/surgery_step/repairflesh/repair_brute/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll))
+ user.visible_message("[user] begins taping up [target]'s [affected] with \the [tool].", \
+ "You begin taping up [target]'s [affected] with \the [tool].")
+ affected.jostle_bone(10)
+ else if(istype(tool, /obj/item/weapon/surgical/FixOVein) || istype(tool, /obj/item/weapon/surgical/bonesetter))
+ user.visible_message("[user] begins mending the torn tissue in [target]'s [affected] with \the [tool].", \
+ "You begin mending the torn tissue in [target]'s [affected] with \the [tool].")
+ else
+ user.visible_message("[user] begins coating the tissue in [target]'s [affected] with \the [tool].", \
+ "You begin coating the tissue in [target]'s [affected] with \the [tool].")
+ ..()
+
+/datum/surgery_step/repairflesh/repair_brute/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll))
+ user.visible_message("[user] finishes taping up [target]'s [affected] with \the [tool].", \
+ "You finish taping up [target]'s [affected] with \the [tool].")
+ affected.createwound(BRUISE, 10)
+ affected.heal_damage(25, 0, 0, 0)
+ if(!(affected.brute_dam))
+ affected.brute_stage = 0
+ if(istype(tool, /obj/item/stack))
+ var/obj/item/stack/T = tool
+ T.use(1)
+ ..()
+
+/datum/surgery_step/repairflesh/repair_brute/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user]'s hand slips, tearing up [target]'s [affected] with \the [tool].", \
+ "Your hand slips, tearing up [target]'s [affected] with \the [tool].")
+ affected.createwound(BRUISE, 10)
+ affected.createwound(CUT, 5)
+ if(istype(tool, /obj/item/stack) && prob(30))
+ var/obj/item/stack/T = tool
+ T.use(1)
+ ..()
diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm
index 4b0e1ece7b8..b01e3a9e2c2 100644
--- a/code/modules/vore/fluffstuff/custom_items_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_items_vr.dm
@@ -725,7 +725,7 @@
random_emote = list("hisses softly with a blush on his face", "yelps in embarrassment", "grunts a little")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_roiz
-/obj/item/weapon/implant/reagent_generator/roiz/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/roiz/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
@@ -793,7 +793,7 @@
random_emote = list("hisses softly with a blush on her face", "bites down on her lower lip", "lets out a light huff")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_jasmine
-/obj/item/weapon/implant/reagent_generator/jasmine/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/jasmine/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
@@ -861,7 +861,7 @@
random_emote = list("hisses softly with a blush on her face", "yelps in embarrassment", "grunts a little")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_yonra
-/obj/item/weapon/implant/reagent_generator/yonra/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/yonra/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
@@ -945,7 +945,7 @@
random_emote = list("trembles and huffs, panting from the exertion.", "sees what has happened and covers her face with both hands!", "whimpers softly, her legs shivering, knees pointed inward from the feeling.")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_rischi
-/obj/item/weapon/implant/reagent_generator/rischi/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/rischi/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
@@ -1011,7 +1011,7 @@
self_emote_descriptor = list("grab", "pick", "snatch")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_pumila_apple
-/obj/item/weapon/implant/reagent_generator/pumila_apple/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/pumila_apple/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
@@ -1704,7 +1704,7 @@
random_emote = list("hisses softly with a blush on his face", "yelps in embarrassment", "grunts a little")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_evian
-/obj/item/weapon/implant/reagent_generator/evian/implanted(mob/living/carbon/source)
+/obj/item/weapon/implant/reagent_generator/evian/post_implant(mob/living/carbon/source)
processing_objects += src
to_chat(source, "You implant [source] with \the [src].")
source.verbs |= assigned_proc
diff --git a/config/alienwhitelist.txt b/config/alienwhitelist.txt
index 18604aaf622..d1874e6b2be 100644
--- a/config/alienwhitelist.txt
+++ b/config/alienwhitelist.txt
@@ -23,6 +23,7 @@ seiga - Vox
sepulchre - Vox
sepulchre - Xenomorph Hybrid
silverTalismen - Diona
+silverTalismen - Vox
silvertalismen - Xenochimera
singo - Gutter
some~user - Species
diff --git a/config/jobwhitelist.txt b/config/jobwhitelist.txt
index 168eccbcda9..e615f5eafd7 100644
--- a/config/jobwhitelist.txt
+++ b/config/jobwhitelist.txt
@@ -7,3 +7,4 @@ whiskyrose - clown
tinybear16 - clown
chargae - mime
verkister - clown
+H0lySquirr3l - clown
diff --git a/html/changelogs/Anewbe - Languages.yml b/html/changelogs/Anewbe - Languages.yml
new file mode 100644
index 00000000000..da9a2f7b42c
--- /dev/null
+++ b/html/changelogs/Anewbe - Languages.yml
@@ -0,0 +1,40 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Anewbe
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - tweak: "Certain languages now require assistance for a species to speak, but not understand, much like EAL."
+ - tweak: "Alai can only be `spoken` by Taj and Teshari."
+ - rscadd: "Adds a voicebox/larynx organ. Its only purpose at the moment is to assist in speaking certain langauges."
+ - tweak: "Language implants, like the EAL implant, now affect the voicebox organ, instead of being a freefloating implant."
+ - rscadd: "Adds a language implant for Common Skrellian."
\ No newline at end of file
diff --git a/html/changelogs/Atermonera - Ceilings.yml b/html/changelogs/Atermonera - Ceilings.yml
new file mode 100644
index 00000000000..760df592f50
--- /dev/null
+++ b/html/changelogs/Atermonera - Ceilings.yml
@@ -0,0 +1,7 @@
+author: Atermonera
+delete-after: True
+changes:
+ - rscadd: "Steel sheets can be used to construct Roofing Tiles"
+ - rscadd: "Roofing tiles can be used on tiles under open spaces or space tiles in multiZ maps to place a lattice and plating on the space above"
+ - rscadd: "Roofing tiles can be used on outdoor turfs to make them indoors"
+ - rscadd: "Both functions work together on multiZ maps with outdoor turfs, only one roofing tile is used per tile roofed."
diff --git a/html/changelogs/Mechoid - Surgical.yml b/html/changelogs/Mechoid - Surgical.yml
new file mode 100644
index 00000000000..844f31e035a
--- /dev/null
+++ b/html/changelogs/Mechoid - Surgical.yml
@@ -0,0 +1,7 @@
+
+author: Mechoid
+
+delete-after: True
+
+changes:
+ - rscadd: "Adds a new surgical procedure for fixing brute and burn on limbs."
diff --git a/html/changelogs/Mewchild - PR - 5396.yml b/html/changelogs/Mewchild - PR - 5396.yml
new file mode 100644
index 00000000000..75998b87c92
--- /dev/null
+++ b/html/changelogs/Mewchild - PR - 5396.yml
@@ -0,0 +1,4 @@
+author: Mewchild
+delete-after: True
+changes:
+ - rscadd: "Ports several AI core sprites from ages and places past"
diff --git a/icons/effects/timestop.dmi b/icons/effects/timestop.dmi
new file mode 100644
index 00000000000..0e69eba9848
Binary files /dev/null and b/icons/effects/timestop.dmi differ
diff --git a/icons/mob/AI.dmi b/icons/mob/AI.dmi
index f5fbc438a76..d0946d1564c 100644
Binary files a/icons/mob/AI.dmi and b/icons/mob/AI.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/DSIVulpkanin/dsi_vulpkanin.dmi b/icons/mob/human_races/cyberlimbs/DSIVulpkanin/dsi_vulpkanin.dmi
index bef68bd7d79..79943fa9e91 100644
Binary files a/icons/mob/human_races/cyberlimbs/DSIVulpkanin/dsi_vulpkanin.dmi and b/icons/mob/human_races/cyberlimbs/DSIVulpkanin/dsi_vulpkanin.dmi differ
diff --git a/icons/mob/vore/wings_vr.dmi b/icons/mob/vore/wings_vr.dmi
index aedb041a018..f4241e295c9 100644
Binary files a/icons/mob/vore/wings_vr.dmi and b/icons/mob/vore/wings_vr.dmi differ
diff --git a/icons/obj/deadringer.dmi b/icons/obj/deadringer.dmi
new file mode 100644
index 00000000000..62200577825
Binary files /dev/null and b/icons/obj/deadringer.dmi differ
diff --git a/icons/obj/pda.dmi b/icons/obj/pda.dmi
index 9928e2fee21..aaedd149689 100644
Binary files a/icons/obj/pda.dmi and b/icons/obj/pda.dmi differ
diff --git a/icons/obj/storage_vr.dmi b/icons/obj/storage_vr.dmi
index 7d4ab399154..74dc0935ddc 100644
Binary files a/icons/obj/storage_vr.dmi and b/icons/obj/storage_vr.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 1bd5df7f9a2..c19111ab72d 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/maps/submaps/surface_submaps/mountains/deadspy.dmm b/maps/submaps/surface_submaps/mountains/deadspy.dmm
new file mode 100644
index 00000000000..f255e79cd77
--- /dev/null
+++ b/maps/submaps/surface_submaps/mountains/deadspy.dmm
@@ -0,0 +1,31 @@
+"a" = (/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/obj/effect/decal/cleanable/molten_item,/turf/template_noop,/area/submap/deadspy)
+"b" = (/obj/item/weapon/flamethrower,/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/turf/template_noop,/area/submap/deadspy)
+"c" = (/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/obj/effect/decal/cleanable/ash,/obj/random/landmine,/turf/template_noop,/area/submap/deadspy)
+"d" = (/obj/item/weapon/material/butterfly,/obj/effect/decal/cleanable/liquid_fuel,/turf/template_noop,/area/submap/deadspy)
+"e" = (/obj/item/weapon/flame/lighter/zippo,/obj/effect/decal/cleanable/liquid_fuel,/turf/template_noop,/area/submap/deadspy)
+"f" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/turf/template_noop,/area/submap/deadspy)
+"g" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/random/landmine,/turf/template_noop,/area/submap/deadspy)
+"h" = (/obj/item/weapon/deadringer,/obj/effect/decal/cleanable/liquid_fuel,/turf/template_noop,/area/submap/deadspy)
+"i" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/item/weapon/storage/fancy/cigarettes/professionals,/turf/template_noop,/area/submap/deadspy)
+"j" = (/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/turf/template_noop,/area/submap/deadspy)
+"k" = (/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/obj/effect/decal/cleanable/ash,/turf/template_noop,/area/submap/deadspy)
+"l" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/molten_item,/turf/template_noop,/area/submap/deadspy)
+"m" = (/obj/effect/decal/remains/human,/obj/item/clothing/mask/balaclava,/obj/item/clothing/under/suit_jacket/really_black,/obj/effect/decal/cleanable/ash,/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/ash,/turf/template_noop,/area/submap/deadspy)
+"n" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/ash,/turf/template_noop,/area/submap/deadspy)
+"o" = (/obj/effect/decal/cleanable/liquid_fuel,/obj/effect/decal/cleanable/liquid_fuel,/obj/random/landmine,/turf/template_noop,/area/submap/deadspy)
+"p" = (/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel,/obj/random/landmine,/turf/template_noop,/area/submap/deadspy)
+"q" = (/obj/effect/decal/remains/xeno,/obj/item/clothing/mask/gas,/obj/item/clothing/suit/fire/firefighter,/turf/template_noop,/area/submap/deadspy)
+"r" = (/turf/template_noop,/area/submap/deadspy)
+"s" = (/obj/effect/decal/remains/human,/obj/item/weapon/wrench,/obj/item/clothing/head/hardhat,/turf/template_noop,/area/submap/deadspy)
+"t" = (/obj/machinery/porta_turret/poi{desc = "Looking at this heavy caliber, tripod-mounted, little ol' number makes you want to square-dance."; lethal = 0; name = "sentry turret"},/turf/template_noop,/area/submap/deadspy)
+"u" = (/obj/item/weapon/card/emag_broken,/turf/template_noop,/area/submap/deadspy)
+
+(1,1,1) = {"
+qrrrrrr
+rabfjcr
+rjgldjs
+rjemnjt
+rjhoiju
+rpjkjjr
+rrrrrrr
+"}
diff --git a/maps/submaps/surface_submaps/mountains/mountains.dm b/maps/submaps/surface_submaps/mountains/mountains.dm
index dd409e0e62f..56a267c4756 100644
--- a/maps/submaps/surface_submaps/mountains/mountains.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains.dm
@@ -31,6 +31,7 @@
#include "SupplyDrop1.dmm"
#include "BlastMine1.dmm"
#include "crashedcontainmentshuttle.dmm"
+#include "deadspy.dmm"
#endif
// The 'mountains' is the mining z-level, and has a lot of caves.
@@ -191,6 +192,12 @@
mappath = 'maps/submaps/surface_submaps/mountains/crashedcontainmentshuttle.dmm'
cost = 30
+/datum/map_template/surface/mountains/normal/deadspy
+ name = "Spy Remains"
+ desc = "W+M1 = Salt."
+ mappath = 'maps/submaps/surface_submaps/mountains/deadspy.dmm'
+ cost = 15
+
/**************
* Deep Caves *
@@ -265,4 +272,3 @@
desc = "An abandoned blast mining site, seems that local wildlife has moved in."
mappath = 'maps/submaps/surface_submaps/mountains/BlastMine1.dmm'
cost = 20
-
diff --git a/maps/submaps/surface_submaps/mountains/mountains_areas.dm b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
index 3baf48c75c6..f1045f22f05 100644
--- a/maps/submaps/surface_submaps/mountains/mountains_areas.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
@@ -88,4 +88,7 @@
name = "Blast Mine 1"
/area/submap/crashedcontainmentshuttle
- name = "Crashed Containment Shuttle"
\ No newline at end of file
+ name = "Crashed Containment Shuttle"
+
+/area/submap/deadspy
+ name = "Dead Spy"
\ No newline at end of file
diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm
index 40bb62f291d..3682a113b83 100644
--- a/maps/tether/tether-06-station2.dmm
+++ b/maps/tether/tether-06-station2.dmm
@@ -295,7 +295,14 @@
/turf/simulated/floor,
/area/security/riot_control)
"aF" = (
-/obj/random/trash,
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/railing{
+ icon_state = "railing0";
+ dir = 1
+ },
+/obj/structure/railing{
+ dir = 8
+ },
/turf/simulated/floor/tiled/dark,
/area/security/brig)
"aG" = (
@@ -422,6 +429,12 @@
/turf/simulated/wall/r_wall,
/area/security/brig)
"aT" = (
+/obj/structure/sink{
+ dir = 4;
+ icon_state = "sink";
+ pixel_x = 11;
+ pixel_y = 0
+ },
/turf/simulated/floor/tiled/freezer,
/area/security/brig/bathroom)
"aU" = (
@@ -1070,6 +1083,12 @@
pixel_y = -8;
req_access = list(1,2)
},
+/obj/structure/sink{
+ icon_state = "sink";
+ dir = 8;
+ pixel_x = -12;
+ pixel_y = 2
+ },
/turf/simulated/floor/tiled,
/area/security/brig)
"bJ" = (
@@ -1276,24 +1295,33 @@
/turf/simulated/wall/r_wall,
/area/engineering/shaft)
"bX" = (
-/turf/space,
-/obj/structure/shuttle/engine/propulsion{
- dir = 8;
- icon_state = "propulsion_l"
- },
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1/station{
- base_turf = /turf/simulated/mineral/floor/vacuum
- })
-"bY" = (
-/turf/space,
-/obj/structure/shuttle/engine/propulsion{
+/obj/random/trash,
+/obj/structure/railing{
dir = 8
},
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1/station{
- base_turf = /turf/simulated/mineral/floor/vacuum
- })
+/obj/structure/railing,
+/turf/simulated/floor/tiled/dark,
+/area/security/brig)
+"bY" = (
+/obj/effect/floor_decal/borderfloor/shifted{
+ icon_state = "borderfloor_shifted";
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/lightorange/border/shifted{
+ icon_state = "bordercolor_shifted";
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/lightorange{
+ icon_state = "corner_white";
+ dir = 5
+ },
+/obj/machinery/light/small{
+ icon_state = "bulb1";
+ dir = 1
+ },
+/obj/structure/bed/padded,
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
"bZ" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
@@ -1314,15 +1342,27 @@
/turf/simulated/floor/tiled,
/area/security/brig)
"ca" = (
-/turf/space,
-/obj/structure/shuttle/engine/propulsion{
- dir = 8;
- icon_state = "propulsion_r"
+/obj/effect/floor_decal/borderfloor/shifted{
+ icon_state = "borderfloor_shifted";
+ dir = 1
},
-/turf/simulated/shuttle/plating/airless/carry,
-/area/shuttle/large_escape_pod1/station{
- base_turf = /turf/simulated/mineral/floor/vacuum
- })
+/obj/effect/floor_decal/corner/lightorange/border/shifted{
+ icon_state = "bordercolor_shifted";
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/lightorange{
+ icon_state = "corner_white";
+ dir = 5
+ },
+/obj/machinery/light/small{
+ icon_state = "bulb1";
+ dir = 1
+ },
+/obj/structure/bed/padded,
+/obj/item/weapon/bedsheet,
+/obj/item/weapon/pen/crayon/green,
+/turf/simulated/floor/tiled/dark,
+/area/security/brig)
"cb" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/unary/outlet_injector{
@@ -1334,6 +1374,39 @@
/obj/effect/floor_decal/industrial/outline/yellow,
/turf/simulated/floor/tiled/steel_dirty,
/area/security/brig)
+"cc" = (
+/obj/effect/floor_decal/borderfloor/shifted{
+ icon_state = "borderfloor_shifted";
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/lightorange/border/shifted{
+ icon_state = "bordercolor_shifted";
+ dir = 1
+ },
+/obj/effect/floor_decal/corner/lightorange{
+ icon_state = "corner_white";
+ dir = 5
+ },
+/obj/machinery/light/small{
+ icon_state = "bulb1";
+ dir = 1
+ },
+/obj/structure/bed/padded,
+/obj/item/weapon/bedsheet,
+/turf/simulated/floor/tiled/dark,
+/area/security/brig)
+"cd" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/structure/table/steel,
+/obj/item/weapon/storage/laundry_basket,
+/turf/simulated/floor/tiled/steel_dirty,
+/area/security/brig)
+"ce" = (
+/obj/machinery/washing_machine,
+/turf/simulated/floor/tiled/steel_dirty,
+/area/security/brig)
"cf" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
@@ -1376,6 +1449,82 @@
/obj/structure/ladder,
/turf/simulated/floor/plating,
/area/engineering/shaft)
+"cl" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/door/airlock/security{
+ name = "Interrogation";
+ req_access = newlist();
+ req_one_access = list(2,4)
+ },
+/turf/simulated/floor/tiled/dark,
+/area/security/interrogation)
+"cm" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "brig_lockdown";
+ name = "Security Blast Doors";
+ opacity = 0
+ },
+/obj/machinery/door/airlock/glass_security{
+ id_tag = "briginner";
+ name = "Brig";
+ req_access = list(2);
+ req_one_access = newlist()
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
+"cn" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/green,
+/obj/machinery/door/blast/regular{
+ density = 0;
+ dir = 4;
+ icon_state = "pdoor0";
+ id = "brig_lockdown";
+ name = "Security Blast Doors";
+ opacity = 0
+ },
+/obj/structure/disposalpipe/segment,
+/obj/machinery/door/airlock/glass_security{
+ id_tag = "briginner";
+ name = "Brig";
+ req_access = list(2);
+ req_one_access = newlist()
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
+"co" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/machinery/door/airlock/glass_security{
+ name = "Brig Cells";
+ req_access = newlist();
+ req_one_access = list(2,4)
+ },
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
"cp" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
@@ -1385,6 +1534,16 @@
},
/turf/simulated/floor/tiled,
/area/security/brig/visitation)
+"cq" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/glass_security{
+ name = "Brig Cells";
+ req_access = newlist();
+ req_one_access = list(2,4)
+ },
+/obj/structure/disposalpipe/segment,
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
"cr" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
@@ -1394,6 +1553,96 @@
},
/turf/simulated/floor/tiled,
/area/security/brig)
+"cs" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/door/airlock/glass_security{
+ id_tag = "brigouter";
+ name = "Brig";
+ req_access = list(2);
+ req_one_access = newlist()
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
+"ct" = (
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/obj/effect/floor_decal/industrial/warning{
+ dir = 8
+ },
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
+"cu" = (
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/green{
+ icon_state = "intact";
+ dir = 4
+ },
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/machinery/door/airlock/glass_security{
+ id_tag = "brigouter";
+ name = "Brig";
+ req_access = list(2);
+ req_one_access = newlist()
+ },
+/turf/simulated/floor/tiled,
+/area/security/brig)
+"cv" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/green{
+ icon_state = "intact";
+ dir = 4
+ },
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/machinery/button/remote/airlock{
+ id = "brigouter";
+ name = "Outer Brig Doors";
+ pixel_x = 6;
+ pixel_y = -24
+ },
+/obj/machinery/button/remote/airlock{
+ id = "briginner";
+ name = "Inner Brig Doors";
+ pixel_x = -6;
+ pixel_y = -24
+ },
+/obj/effect/floor_decal/industrial/warning{
+ dir = 8
+ },
+/turf/simulated/floor/tiled,
+/area/security/security_cell_hallway)
"cw" = (
/obj/effect/floor_decal/borderfloor/shifted{
icon_state = "borderfloor_shifted";
@@ -1417,25 +1666,24 @@
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
"cx" = (
-/obj/effect/floor_decal/borderfloor/shifted{
- icon_state = "borderfloor_shifted";
- dir = 1
+/obj/machinery/door/firedoor/glass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/obj/effect/floor_decal/corner/lightorange/border/shifted{
- icon_state = "bordercolor_shifted";
- dir = 1
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
},
-/obj/effect/floor_decal/corner/lightorange{
- icon_state = "corner_white";
- dir = 5
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
},
-/obj/structure/bed,
-/obj/machinery/light/small{
- icon_state = "bulb1";
- dir = 1
+/obj/machinery/door/airlock/security{
+ name = "Observation";
+ req_one_access = list(1,4)
},
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
+/turf/simulated/floor/tiled/dark,
+/area/security/interrogation)
"cy" = (
/obj/effect/floor_decal/borderfloor/shifted{
icon_state = "borderfloor_shifted";
@@ -1582,25 +1830,15 @@
/turf/simulated/floor/tiled/dark,
/area/security/brig)
"cL" = (
-/obj/effect/floor_decal/borderfloor/shifted{
- icon_state = "borderfloor_shifted";
- dir = 1
+/turf/space,
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8;
+ icon_state = "propulsion_l"
},
-/obj/effect/floor_decal/corner/lightorange/border/shifted{
- icon_state = "bordercolor_shifted";
- dir = 1
- },
-/obj/effect/floor_decal/corner/lightorange{
- icon_state = "corner_white";
- dir = 5
- },
-/obj/structure/bed,
-/obj/machinery/light/small{
- icon_state = "bulb1";
- dir = 1
- },
-/turf/simulated/floor/tiled/dark,
-/area/security/brig)
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1/station{
+ base_turf = /turf/simulated/mineral/floor/vacuum
+ })
"cM" = (
/obj/effect/floor_decal/borderfloor/shifted{
icon_state = "borderfloor_shifted";
@@ -1744,6 +1982,15 @@
},
/turf/simulated/floor/tiled/dark,
/area/security/recstorage)
+"cW" = (
+/turf/space,
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8
+ },
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1/station{
+ base_turf = /turf/simulated/mineral/floor/vacuum
+ })
"cX" = (
/obj/machinery/door/firedoor/glass,
/obj/structure/cable/green{
@@ -1975,6 +2222,16 @@
/obj/machinery/door/window/brigdoor/eastright,
/turf/simulated/floor/tiled,
/area/security/brig/visitation)
+"dm" = (
+/turf/space,
+/obj/structure/shuttle/engine/propulsion{
+ dir = 8;
+ icon_state = "propulsion_r"
+ },
+/turf/simulated/shuttle/plating/airless/carry,
+/area/shuttle/large_escape_pod1/station{
+ base_turf = /turf/simulated/mineral/floor/vacuum
+ })
"dn" = (
/obj/effect/floor_decal/industrial/warning,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
@@ -2748,12 +3005,6 @@
},
/turf/simulated/floor/tiled,
/area/security/brig)
-"eV" = (
-/obj/machinery/light{
- dir = 4
- },
-/turf/simulated/floor/tiled/steel_dirty,
-/area/security/brig)
"fc" = (
/obj/effect/floor_decal/borderfloor{
dir = 4
@@ -3319,30 +3570,6 @@
"gw" = (
/turf/simulated/open,
/area/engineering/locker_room)
-"gx" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "brig_lockdown";
- name = "Security Blast Doors";
- opacity = 0
- },
-/obj/machinery/door/airlock/glass_security{
- id_tag = "brigouter";
- name = "Brig";
- req_access = list(2)
- },
-/turf/simulated/floor/tiled,
-/area/security/brig)
"gy" = (
/obj/effect/floor_decal/borderfloor{
dir = 1;
@@ -3359,30 +3586,6 @@
},
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
-"gB" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/door/airlock/glass_security{
- name = "Brig Cells";
- req_access = list(1)
- },
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
-"gC" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/glass_security{
- name = "Brig Cells";
- req_access = list(1)
- },
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
"gE" = (
/obj/machinery/atmospherics/unary/vent_pump/on{
dir = 1
@@ -4057,24 +4260,6 @@
},
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
-"hX" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/door/airlock/security{
- name = "Observation"
- },
-/turf/simulated/floor/tiled/dark,
-/area/security/interrogation)
"hY" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 9
@@ -16886,32 +17071,6 @@
},
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
-"FO" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/green{
- icon_state = "intact";
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 4;
- icon_state = "1-4"
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
"FR" = (
/obj/effect/floor_decal/rust,
/obj/random/junk,
@@ -16948,33 +17107,6 @@
},
/turf/simulated/floor/tiled/dark,
/area/tether/station/public_meeting_room)
-"Gl" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/green{
- icon_state = "intact";
- dir = 4
- },
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/door/airlock/glass_security{
- id_tag = "briginner";
- name = "Brig";
- req_access = list(2)
- },
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/simulated/floor/tiled,
-/area/security/brig)
"Go" = (
/obj/effect/floor_decal/rust,
/turf/simulated/floor/plating,
@@ -17259,15 +17391,6 @@
/obj/machinery/door/firedoor/glass,
/turf/simulated/floor/plating,
/area/maintenance/station/sec_lower)
-"JI" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/door/airlock/glass_security{
- id_tag = "briginner";
- name = "Brig";
- req_access = list(2)
- },
-/turf/simulated/floor/tiled,
-/area/security/brig)
"JK" = (
/obj/structure/cable{
d1 = 1;
@@ -18028,14 +18151,6 @@
/obj/structure/closet/emcloset,
/turf/simulated/floor,
/area/maintenance/station/sec_lower)
-"Qe" = (
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/turf/simulated/floor/tiled,
-/area/security/security_cell_hallway)
"Qk" = (
/obj/effect/floor_decal/rust,
/obj/random/trash,
@@ -18785,20 +18900,6 @@
},
/turf/simulated/floor/tiled,
/area/security/security_cell_hallway)
-"Vu" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/door/airlock/security{
- name = "Interrogation";
- req_access = list(2)
- },
-/turf/simulated/floor/tiled/dark,
-/area/security/interrogation)
"Vw" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -18824,25 +18925,6 @@
},
/turf/simulated/floor/tiled,
/area/tether/station/public_meeting_room)
-"VB" = (
-/obj/machinery/door/firedoor/glass,
-/obj/machinery/atmospherics/pipe/simple/hidden/green,
-/obj/machinery/door/blast/regular{
- density = 0;
- dir = 4;
- icon_state = "pdoor0";
- id = "brig_lockdown";
- name = "Security Blast Doors";
- opacity = 0
- },
-/obj/machinery/door/airlock/glass_security{
- id_tag = "brigouter";
- name = "Brig";
- req_access = list(2)
- },
-/obj/structure/disposalpipe/segment,
-/turf/simulated/floor/tiled,
-/area/security/brig)
"VF" = (
/obj/machinery/door/firedoor/glass,
/obj/structure/cable/green{
@@ -26639,7 +26721,7 @@ eq
eQ
dn
IZ
-gx
+cm
HK
Xx
hQ
@@ -26781,7 +26863,7 @@ bB
bE
dQ
Ye
-VB
+cn
YK
Nc
hQ
@@ -26924,8 +27006,8 @@ bF
ZH
Fb
Rq
-JI
-Gl
+cs
+cu
hQ
Er
jg
@@ -27066,8 +27148,8 @@ cP
Em
Em
YE
-Qe
-FO
+ct
+cv
TY
TY
jh
@@ -27204,8 +27286,8 @@ bK
dp
Jc
bK
-eV
-bK
+cd
+ce
bK
Zu
Ng
@@ -27477,8 +27559,8 @@ at
Et
HP
aS
-am
aF
+bX
aS
cK
cO
@@ -27622,16 +27704,16 @@ aS
Ew
am
aS
-cL
+ca
cQ
aS
-cL
+cc
cQ
aS
-cL
+cc
cQ
aS
-cL
+cc
cQ
aS
gy
@@ -28059,7 +28141,7 @@ KQ
bQ
bd
KQ
-gB
+co
gX
hu
FI
@@ -28201,7 +28283,7 @@ Vm
fc
fI
ga
-gC
+cq
gY
hv
hW
@@ -28342,11 +28424,11 @@ dU
cU
fd
fd
-Vu
+cl
fd
fd
fd
-hX
+cx
fd
aj
jO
@@ -28614,10 +28696,10 @@ TW
WJ
RS
aj
-cx
+bY
cC
aj
-cx
+bY
cC
cA
cV
@@ -29946,11 +30028,11 @@ AN
AN
Bw
yY
-bX
-bY
-bY
-bY
-ca
+cL
+cW
+cW
+cW
+dm
yY
ac
ac
diff --git a/maps/tether/tether-07-station3.dmm b/maps/tether/tether-07-station3.dmm
index 43f3805407b..35244523190 100644
--- a/maps/tether/tether-07-station3.dmm
+++ b/maps/tether/tether-07-station3.dmm
@@ -380,7 +380,7 @@
/area/maintenance/station/sec_upper)
"aJ" = (
/obj/structure/lattice,
-/obj/structure/catwalk,
+/obj/structure/railing,
/turf/space,
/area/space)
"aK" = (
@@ -594,6 +594,8 @@
phorontanks = 0
},
/obj/machinery/light,
+/obj/effect/floor_decal/borderfloor/corner2,
+/obj/effect/floor_decal/corner/red/bordercorner2,
/turf/simulated/floor/tiled,
/area/security/eva)
"aX" = (
@@ -726,6 +728,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
+/obj/machinery/hologram/holopad,
/turf/simulated/floor/tiled/dark,
/area/security/armory/red)
"bm" = (
@@ -1076,20 +1079,9 @@
/turf/simulated/floor/tiled,
/area/security/hallwayaux)
"bJ" = (
-/obj/effect/floor_decal/borderfloor{
- dir = 6
- },
-/obj/effect/floor_decal/corner/red/border{
- dir = 6
- },
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 6
- },
-/obj/effect/floor_decal/corner/red/bordercorner2{
- dir = 6
- },
-/obj/machinery/suit_cycler/security,
-/turf/simulated/floor/tiled,
+/obj/structure/closet/emcloset,
+/obj/effect/decal/cleanable/cobweb,
+/turf/simulated/floor,
/area/security/eva)
"bK" = (
/obj/effect/floor_decal/borderfloor,
@@ -1439,6 +1431,7 @@
},
/obj/structure/window/reinforced,
/obj/structure/table/rack/shelf/steel,
+/obj/item/weapon/gun/energy/ionrifle/pistol,
/turf/simulated/floor/tiled/dark,
/area/security/armory/blue)
"cl" = (
@@ -3425,31 +3418,18 @@
/turf/simulated/floor/tiled/dark,
/area/security/evidence_storage)
"fM" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 8
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/structure/cable/green{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
},
-/obj/structure/window/reinforced{
- dir = 4
- },
-/obj/effect/floor_decal/borderfloorwhite/corner2{
- dir = 6
- },
-/obj/effect/floor_decal/borderfloorwhite/corner2{
- dir = 5
- },
-/obj/effect/floor_decal/corner/white/bordercorner2{
- icon_state = "bordercolorcorner2";
- dir = 6
- },
-/obj/effect/floor_decal/corner/white/bordercorner2{
- icon_state = "bordercolorcorner2";
- dir = 5
- },
-/turf/simulated/floor/tiled/white,
-/area/security/forensics)
+/obj/machinery/hologram/holopad,
+/turf/simulated/floor/tiled/dark,
+/area/security/armory/blue)
"fN" = (
/obj/machinery/door/firedoor/glass,
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
@@ -4123,19 +4103,28 @@
/turf/simulated/floor,
/area/security/eva)
"gZ" = (
+/obj/machinery/alarm{
+ pixel_y = 22
+ },
/obj/structure/closet/emcloset,
/turf/simulated/floor,
/area/security/eva)
"ha" = (
-/obj/machinery/alarm{
- pixel_y = 22
+/obj/machinery/atmospherics/pipe/manifold/hidden{
+ dir = 1;
+ icon_state = "map"
},
-/obj/machinery/atmospherics/portables_connector,
-/obj/machinery/portable_atmospherics/canister/air/airlock,
+/obj/machinery/meter,
/turf/simulated/floor,
/area/security/eva)
"hb" = (
-/obj/machinery/atmospherics/portables_connector,
+/obj/machinery/light/small{
+ dir = 4;
+ pixel_y = 0
+ },
+/obj/machinery/atmospherics/portables_connector{
+ dir = 8
+ },
/obj/machinery/portable_atmospherics/canister/air/airlock,
/turf/simulated/floor,
/area/security/eva)
@@ -4321,18 +4310,18 @@
/turf/simulated/floor,
/area/security/eva)
"hw" = (
-/obj/machinery/atmospherics/pipe/manifold/hidden,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/hidden{
+ dir = 5;
+ icon_state = "intact"
+ },
/turf/simulated/floor,
/area/security/eva)
"hx" = (
-/obj/machinery/atmospherics/pipe/simple/hidden{
- dir = 9;
- icon_state = "intact"
- },
-/obj/machinery/light/small{
- dir = 4;
- pixel_y = 0
+/obj/machinery/atmospherics/portables_connector{
+ dir = 8
},
+/obj/machinery/portable_atmospherics/canister/air/airlock,
/turf/simulated/floor,
/area/security/eva)
"hy" = (
@@ -5540,17 +5529,15 @@
/turf/simulated/floor/tiled/dark,
/area/security/armory/blue)
"jh" = (
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 8
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/structure/cable/green{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/turf/simulated/floor/tiled/dark,
-/area/security/armory/blue)
+/obj/machinery/hologram/holopad,
+/turf/simulated/floor/tiled,
+/area/security/briefing_room)
"ji" = (
/obj/effect/floor_decal/borderfloorblack{
dir = 4
@@ -5987,11 +5974,6 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/table/woodentable,
-/obj/item/device/flashlight/lamp/green{
- dir = 2;
- pixel_x = -10;
- pixel_y = 12
- },
/obj/machinery/computer/skills{
icon_state = "laptop";
dir = 4
@@ -6128,6 +6110,11 @@
},
/obj/structure/table/woodentable,
/obj/item/weapon/stamp/hos,
+/obj/item/device/flashlight/lamp/green{
+ dir = 2;
+ pixel_x = -4;
+ pixel_y = 12
+ },
/turf/simulated/floor/carpet,
/area/crew_quarters/heads/hos)
"jY" = (
@@ -6482,6 +6469,9 @@
},
/obj/structure/closet/secure_closet/hos2,
/obj/machinery/light,
+/obj/machinery/keycard_auth{
+ pixel_y = -28
+ },
/turf/simulated/floor/wood,
/area/crew_quarters/heads/hos)
"kH" = (
@@ -6702,6 +6692,9 @@
/obj/effect/floor_decal/borderfloorblack,
/obj/effect/floor_decal/borderfloorblack/corner2,
/obj/structure/table/rack/shelf/steel,
+/obj/item/clothing/glasses/hud/security,
+/obj/item/clothing/glasses/hud/security,
+/obj/item/clothing/glasses/hud/security,
/turf/simulated/floor/tiled/dark,
/area/security/security_equiptment_storage)
"lb" = (
@@ -7537,6 +7530,7 @@
},
/obj/structure/table/steel,
/obj/item/weapon/storage/box/nifsofts_security,
+/obj/item/weapon/hand_labeler,
/turf/simulated/floor/tiled/dark,
/area/security/security_lockerroom)
"my" = (
@@ -8045,14 +8039,14 @@
/turf/simulated/floor/tiled,
/area/security/briefing_room)
"nu" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
+/obj/structure/cable/green{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
},
+/obj/machinery/hologram/holopad,
/turf/simulated/floor/tiled,
-/area/security/briefing_room)
+/area/security/security_processing)
"nv" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 9
@@ -9549,7 +9543,10 @@
/turf/simulated/floor/tiled,
/area/security/hallway)
"pS" = (
-/obj/effect/floor_decal/rust,
+/obj/random/trash_pile,
+/obj/effect/decal/cleanable/cobweb{
+ icon_state = "cobweb2"
+ },
/turf/simulated/floor,
/area/maintenance/station/sec_upper)
"pT" = (
@@ -11991,6 +11988,17 @@
dir = 8
},
/obj/machinery/vending/snack,
+/obj/machinery/embedded_controller/radio/airlock/airlock_controller{
+ frequency = 1379;
+ id_tag = "sec_fore_airlock";
+ pixel_x = 24;
+ pixel_y = 0;
+ req_one_access = list(13);
+ tag_airpump = "sec_fore_pump";
+ tag_chamber_sensor = "sec_fore_sensor";
+ tag_exterior_door = "sec_fore_outer";
+ tag_interior_door = "sec_fore_inner"
+ },
/turf/simulated/floor/tiled,
/area/hallway/station/upper)
"tt" = (
@@ -12575,8 +12583,8 @@
pixel_y = 24
},
/obj/structure/cable{
- icon_state = "0-2";
- d2 = 2
+ d2 = 8;
+ icon_state = "0-8"
},
/turf/simulated/floor/plating,
/area/storage/emergency_storage/emergency3)
@@ -14134,13 +14142,20 @@
},
/obj/structure/table/reinforced,
/obj/item/weapon/paper_bin{
- pixel_x = -3;
+ pixel_x = 4;
pixel_y = 7
},
/obj/item/weapon/pen/blue{
pixel_x = 5;
pixel_y = 5
},
+/obj/machinery/button/remote/airlock{
+ id = "BrigFoyer";
+ name = "Brig Foyer";
+ pixel_x = -6;
+ pixel_y = 0;
+ req_access = list(1)
+ },
/turf/simulated/floor/tiled,
/area/security/lobby)
"wR" = (
@@ -14156,22 +14171,32 @@
/turf/simulated/floor/tiled,
/area/security/observation)
"wS" = (
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 8
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
},
-/obj/effect/floor_decal/borderfloor/corner2{
- dir = 10;
- icon_state = "borderfloorcorner2";
- pixel_x = 0
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
},
-/obj/effect/floor_decal/corner/red/bordercorner2{
- dir = 8
+/obj/structure/window/reinforced{
+ dir = 4
},
-/obj/effect/floor_decal/corner/red/bordercorner2{
- dir = 10
+/obj/effect/floor_decal/borderfloorwhite/corner2{
+ dir = 6
},
-/turf/simulated/floor/tiled,
-/area/security/lobby)
+/obj/effect/floor_decal/borderfloorwhite/corner2{
+ dir = 5
+ },
+/obj/effect/floor_decal/corner/white/bordercorner2{
+ icon_state = "bordercolorcorner2";
+ dir = 6
+ },
+/obj/effect/floor_decal/corner/white/bordercorner2{
+ icon_state = "bordercolorcorner2";
+ dir = 5
+ },
+/obj/machinery/hologram/holopad,
+/turf/simulated/floor/tiled/white,
+/area/security/forensics)
"wT" = (
/obj/structure/table/reinforced,
/obj/item/weapon/storage/box/cups,
@@ -16440,9 +16465,6 @@
/turf/simulated/floor/tiled,
/area/hallway/station/upper)
"Ai" = (
-/obj/machinery/light{
- dir = 1
- },
/obj/effect/floor_decal/borderfloor{
dir = 1
},
@@ -17774,6 +17796,7 @@
dir = 1
},
/obj/machinery/computer/timeclock/premade/south,
+/obj/machinery/light,
/turf/simulated/floor/tiled,
/area/hallway/station/upper)
"Cn" = (
@@ -17856,6 +17879,10 @@
},
/turf/simulated/floor/tiled,
/area/hallway/station/upper)
+"Cu" = (
+/obj/machinery/hologram/holopad,
+/turf/simulated/floor/tiled/dark,
+/area/lawoffice)
"Cv" = (
/obj/effect/floor_decal/borderfloor{
dir = 6
@@ -27242,6 +27269,74 @@
},
/turf/simulated/floor,
/area/maintenance/station/sec_upper)
+"Rf" = (
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 8
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 10;
+ icon_state = "borderfloorcorner2";
+ pixel_x = 0
+ },
+/obj/effect/floor_decal/corner/red/bordercorner2{
+ dir = 8
+ },
+/obj/effect/floor_decal/corner/red/bordercorner2{
+ dir = 10
+ },
+/obj/machinery/hologram/holopad,
+/turf/simulated/floor/tiled,
+/area/security/lobby)
+"Rg" = (
+/obj/structure/catwalk,
+/turf/space,
+/area/space)
+"Rh" = (
+/obj/structure/lattice,
+/obj/structure/railing{
+ dir = 8
+ },
+/turf/space,
+/area/space)
+"Ri" = (
+/obj/structure/railing{
+ dir = 8
+ },
+/turf/space,
+/area/space)
+"Rj" = (
+/obj/structure/railing,
+/obj/structure/railing{
+ dir = 8
+ },
+/turf/space,
+/area/space)
+"Rk" = (
+/obj/effect/floor_decal/rust,
+/obj/effect/decal/cleanable/cobweb,
+/turf/simulated/floor,
+/area/maintenance/station/sec_upper)
+"Rl" = (
+/obj/effect/floor_decal/borderfloor{
+ dir = 6
+ },
+/obj/effect/floor_decal/corner/red/border{
+ dir = 6
+ },
+/obj/effect/floor_decal/borderfloor/corner2{
+ dir = 6
+ },
+/obj/effect/floor_decal/corner/red/bordercorner2{
+ dir = 6
+ },
+/obj/machinery/suit_cycler/security,
+/obj/machinery/meter,
+/turf/simulated/floor/tiled,
+/area/security/eva)
+"Rm" = (
+/obj/effect/decal/cleanable/cobweb,
+/turf/simulated/wall/r_wall,
+/area/security/lobby)
"SW" = (
/turf/simulated/mineral/vacuum,
/area/space)
@@ -31710,7 +31805,7 @@ fr
qd
fJ
rh
-fM
+wS
sO
tJ
qc
@@ -32541,7 +32636,7 @@ ih
ix
ih
jb
-jh
+fM
ih
jF
bd
@@ -32666,7 +32761,7 @@ aa
ae
ae
ae
-aJ
+Rg
ae
ae
ab
@@ -32808,7 +32903,7 @@ aa
ad
aa
aa
-aJ
+Rg
aa
aa
ab
@@ -32949,8 +33044,8 @@ aa
aa
ad
aa
-aa
-aJ
+ed
+Rg
bh
aa
aa
@@ -33091,8 +33186,8 @@ aa
aa
ae
ae
-ae
aJ
+Rg
bh
aa
aa
@@ -33233,8 +33328,8 @@ aa
aa
ad
aa
-aa
-aJ
+ed
+Rg
bh
aa
aa
@@ -33376,7 +33471,7 @@ aa
ad
aa
aa
-aJ
+Rg
aa
aa
aa
@@ -33420,7 +33515,7 @@ tS
uK
vz
wh
-wh
+Cu
xC
ym
zm
@@ -33518,7 +33613,7 @@ aa
ae
ae
ae
-aJ
+Rg
ae
ae
ae
@@ -33660,7 +33755,7 @@ aa
ad
aa
aa
-aJ
+Rg
aa
aa
aa
@@ -33801,8 +33896,8 @@ aa
aa
ad
aa
-aa
-aJ
+ed
+Rg
bh
aa
ab
@@ -33943,8 +34038,8 @@ aa
aa
ae
ae
-ae
aJ
+Rg
bh
aa
ab
@@ -34085,8 +34180,8 @@ aa
aa
ad
aa
-aa
-aJ
+ed
+Rg
bh
aa
ab
@@ -34131,7 +34226,7 @@ uP
uP
uP
uP
-uP
+Rm
uP
uP
Ag
@@ -34228,7 +34323,7 @@ aa
ad
aa
aa
-aJ
+Rg
ae
ae
cv
@@ -34370,7 +34465,7 @@ aa
ae
ae
ae
-aJ
+Rg
cv
cv
cv
@@ -34512,7 +34607,7 @@ aa
ad
aa
aa
-aJ
+Rg
cv
cv
cv
@@ -34654,7 +34749,7 @@ aa
ad
aa
aa
-aJ
+Rg
cv
cv
cv
@@ -34689,7 +34784,7 @@ of
oD
pn
DP
-qi
+nu
qN
rx
qQ
@@ -34796,7 +34891,7 @@ aa
ae
ae
ae
-aJ
+Rg
cv
cv
cv
@@ -34840,7 +34935,7 @@ tW
uT
vH
wn
-wS
+Rf
wn
yt
zq
@@ -34938,7 +35033,7 @@ aa
ad
aa
aa
-aJ
+Rg
cv
cv
cv
@@ -35080,7 +35175,7 @@ aa
ad
aa
aa
-aJ
+Rg
cv
cv
cv
@@ -35222,7 +35317,11 @@ aa
ae
ae
ae
-aJ
+Rg
+cv
+cv
+cv
+cv
cv
cv
cv
@@ -35232,10 +35331,6 @@ cv
cv
cv
cv
-hp
-hp
-hp
-hp
iC
bP
cn
@@ -35364,11 +35459,11 @@ aa
ad
aa
aa
-aJ
-aJ
-aJ
-aJ
-SW
+Rg
+Rg
+Rg
+Rg
+gg
SW
ab
ab
@@ -35507,10 +35602,10 @@ ad
aa
aa
aa
-ae
-aa
-aJ
-SW
+Rh
+Ri
+Rj
+gg
SW
ab
ab
@@ -35651,8 +35746,8 @@ aa
aa
ae
aa
-aJ
-SW
+ed
+gg
SW
ab
ab
@@ -35793,8 +35888,8 @@ aa
aa
aO
aa
-aJ
-SW
+ed
+gg
ab
ab
ab
@@ -35935,8 +36030,8 @@ aa
aa
aa
aa
-aJ
-SW
+aa
+gg
ab
ab
ab
@@ -36077,8 +36172,8 @@ aa
aa
aa
aa
-aJ
-aJ
+aa
+gg
ab
ab
ab
@@ -36103,7 +36198,7 @@ lh
lH
lH
lH
-nu
+jh
lH
ok
oK
@@ -36220,7 +36315,7 @@ aa
aa
aa
aa
-aJ
+gg
ab
ab
ab
@@ -36362,7 +36457,7 @@ aa
aa
aa
aa
-aJ
+gg
ab
ab
ab
@@ -36370,7 +36465,7 @@ aU
bk
ht
hP
-bJ
+Rl
aU
iH
iT
@@ -36534,7 +36629,7 @@ nT
on
oM
le
-pS
+Rk
fq
qV
fc
@@ -37077,7 +37172,7 @@ aa
aa
ab
bc
-gZ
+bJ
ay
hQ
bm
@@ -37219,9 +37314,9 @@ aa
aa
ab
bc
+gZ
ha
hw
-hQ
hZ
dA
iq
@@ -37361,11 +37456,11 @@ aa
aa
ab
bc
+bc
hb
hx
-aF
bc
-db
+pS
eW
pN
iq
@@ -37502,7 +37597,7 @@ aa
aa
aa
ab
-bc
+ab
bc
bc
bc
diff --git a/nano/images/nanomap_z1.png b/nano/images/nanomap_z1.png
index 58a2ee22bd8..10dc0a5ff38 100644
Binary files a/nano/images/nanomap_z1.png and b/nano/images/nanomap_z1.png differ
diff --git a/nano/images/nanomap_z10.png b/nano/images/nanomap_z10.png
index 360d2439748..c8d1590e75f 100644
Binary files a/nano/images/nanomap_z10.png and b/nano/images/nanomap_z10.png differ
diff --git a/nano/images/nanomap_z2.png b/nano/images/nanomap_z2.png
index ad72fbd06ff..babe33e4f1f 100644
Binary files a/nano/images/nanomap_z2.png and b/nano/images/nanomap_z2.png differ
diff --git a/nano/images/nanomap_z3.png b/nano/images/nanomap_z3.png
index 6478ada84d6..1b8991eb26e 100644
Binary files a/nano/images/nanomap_z3.png and b/nano/images/nanomap_z3.png differ
diff --git a/nano/images/nanomap_z5.png b/nano/images/nanomap_z5.png
index 75c80590afc..ede2cb688e5 100644
Binary files a/nano/images/nanomap_z5.png and b/nano/images/nanomap_z5.png differ
diff --git a/nano/images/nanomap_z6.png b/nano/images/nanomap_z6.png
index 1a77e7ff9da..a69095c38fe 100644
Binary files a/nano/images/nanomap_z6.png and b/nano/images/nanomap_z6.png differ
diff --git a/nano/images/nanomap_z7.png b/nano/images/nanomap_z7.png
index b74c9df99de..14345cd4e4f 100644
Binary files a/nano/images/nanomap_z7.png and b/nano/images/nanomap_z7.png differ
diff --git a/nano/images/nanomap_z8.png b/nano/images/nanomap_z8.png
index 319c0161e00..9b3b9377542 100644
Binary files a/nano/images/nanomap_z8.png and b/nano/images/nanomap_z8.png differ
diff --git a/nano/images/nanomap_z9.png b/nano/images/nanomap_z9.png
index 473a77a266a..6b766c4d28f 100644
Binary files a/nano/images/nanomap_z9.png and b/nano/images/nanomap_z9.png differ
diff --git a/sound/effects/uncloak.ogg b/sound/effects/uncloak.ogg
new file mode 100644
index 00000000000..a2cedc8c731
Binary files /dev/null and b/sound/effects/uncloak.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index 5331c30de21..3e19dfa5b1e 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1406,6 +1406,7 @@
#include "code\modules\alarm\fire_alarm.dm"
#include "code\modules\alarm\motion_alarm.dm"
#include "code\modules\alarm\power_alarm.dm"
+#include "code\modules\artifice\deadringer.dm"
#include "code\modules\assembly\assembly.dm"
#include "code\modules\assembly\helpers.dm"
#include "code\modules\assembly\holder.dm"
@@ -2328,6 +2329,7 @@
#include "code\modules\organs\internal\liver.dm"
#include "code\modules\organs\internal\lungs.dm"
#include "code\modules\organs\internal\organ_internal.dm"
+#include "code\modules\organs\internal\voicebox.dm"
#include "code\modules\organs\subtypes\diona.dm"
#include "code\modules\organs\subtypes\indestructible.dm"
#include "code\modules\organs\subtypes\machine.dm"
@@ -2707,6 +2709,7 @@
#include "code\modules\surgery\_defines.dm"
#include "code\modules\surgery\bones.dm"
#include "code\modules\surgery\encased.dm"
+#include "code\modules\surgery\external_repair.dm"
#include "code\modules\surgery\face.dm"
#include "code\modules\surgery\generic.dm"
#include "code\modules\surgery\implant.dm"