diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm
index 399c7e879b..0976ed5ea3 100644
--- a/code/__defines/chemistry.dm
+++ b/code/__defines/chemistry.dm
@@ -35,6 +35,7 @@
#define CE_ALCOHOL_TOXIC "alcotoxic" // Liver damage
#define CE_SPEEDBOOST "gofast" // Hyperzine
#define CE_SLOWDOWN "goslow" // Slowdown
+#define CE_ANTACID "nopuke" // Don't puke.
#define REAGENTS_PER_SHEET 20
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index efb94d4963..de9ffa6cf9 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -194,10 +194,24 @@
#define O_KIDNEYS "kidneys"
#define O_APPENDIX "appendix"
#define O_VOICE "voicebox"
-#define O_STANDARD list(O_EYES, O_HEART, O_LUNGS, O_BRAIN, O_LIVER, O_KIDNEYS, O_APPENDIX, O_VOICE)
+#define O_SPLEEN "spleen"
+#define O_STOMACH "stomach"
+#define O_INTESTINE "intestine"
+#define O_STANDARD list(O_EYES, O_HEART, O_LUNGS, O_BRAIN, O_LIVER, O_KIDNEYS, O_SPLEEN, O_APPENDIX, O_VOICE, O_STOMACH, O_INTESTINE)
// Augments
-#define O_AUG_TSHADE "integrated thermolensing implant"
+#define O_AUG_EYES "occular augment"
+
+#define O_AUG_L_FOREARM "left forearm augment"
+#define O_AUG_R_FOREARM "right forearm augment"
+#define O_AUG_L_UPPERARM "left upperarm augment"
+#define O_AUG_R_UPPERARM "right upperarm augment"
+#define O_AUG_L_HAND "left hand augment"
+#define O_AUG_R_HAND "right hand augment"
+
+#define O_AUG_RIBS "rib augment"
+#define O_AUG_SPINE "spinal augment"
+#define O_AUG_PELVIC "pelvic augment"
// Non-Standard organs
#define O_MOUTH "mouth"
diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm
index e345b18505..554a826f20 100644
--- a/code/datums/supplypacks/medical.dm
+++ b/code/datums/supplypacks/medical.dm
@@ -349,3 +349,24 @@
cost = 250
containertype = /obj/structure/largecrate
containername = "Industrial Chemical distiller crate"
+
+/datum/supply_pack/med/oxypump
+ name = "Oxygen pump crate"
+ contains = list(/obj/machinery/oxygen_pump/mobile = 1)
+ cost = 125
+ containertype = /obj/structure/largecrate
+ containername = "Oxygen pump crate"
+
+/datum/supply_pack/med/anestheticpump
+ name = "Anesthetic pump crate"
+ contains = list(/obj/machinery/oxygen_pump/mobile/anesthetic = 1)
+ cost = 130
+ containertype = /obj/structure/largecrate
+ containername = "Anesthetic pump crate"
+
+/datum/supply_pack/med/stablepump
+ name = "Portable stabilizer crate"
+ contains = list(/obj/machinery/oxygen_pump/mobile/stabilizer = 1)
+ cost = 175
+ containertype = /obj/structure/largecrate
+ containername = "Portable stabilizer crate"
diff --git a/code/datums/supplypacks/misc.dm b/code/datums/supplypacks/misc.dm
index bf5b8ba53b..7f4f0362db 100644
--- a/code/datums/supplypacks/misc.dm
+++ b/code/datums/supplypacks/misc.dm
@@ -170,3 +170,12 @@
cost = 25
containertype = /obj/structure/closet/crate/freezer
containername = "emergency rations"
+
+/datum/supply_pack/misc/medical_rations
+ name = "Emergency - VitaPaste"
+ contains = list(
+ /obj/item/weapon/storage/mre/menu13 = 2
+ )
+ cost = 40
+ containertype = /obj/structure/closet/crate/freezer
+ containername = "emergency rations"
diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm
index 7e3e2f3005..e36396c9cd 100644
--- a/code/datums/uplink/implants.dm
+++ b/code/datums/uplink/implants.dm
@@ -23,3 +23,53 @@
name = "Uplink Implant" //Original name: "Uplink Implant (Contains 5 Telecrystals)"
item_cost = 50 //Original cost: 10
path = /obj/item/weapon/storage/box/syndie_kit/imp_uplink
+
+/datum/uplink_item/item/implants/imp_shades
+ name = "Integrated Thermal-Shades Implant (Organic)"
+ item_cost = 80
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug
+
+/datum/uplink_item/item/implants/imp_taser
+ name = "Integrated Taser Implant (Organic)"
+ item_cost = 30
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/taser
+
+/datum/uplink_item/item/implants/imp_laser
+ name = "Integrated Laser Implant (Organic)"
+ item_cost = 50
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/laser
+
+/datum/uplink_item/item/implants/imp_dart
+ name = "Integrated Dart Implant (Organic)"
+ item_cost = 60
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/dart
+
+/datum/uplink_item/item/implants/imp_toolkit
+ name = "Integrated Toolkit Implant (Organic)"
+ item_cost = 80
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/toolkit
+
+/datum/uplink_item/item/implants/imp_medkit
+ name = "Integrated Medkit Implant (Organic)"
+ item_cost = 60
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/medkit
+
+/datum/uplink_item/item/implants/imp_analyzer
+ name = "Integrated Research Scanner Implant (Organic)"
+ item_cost = 20
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/analyzer
+
+/datum/uplink_item/item/implants/imp_sword
+ name = "Integrated Sword Implant (Organic)"
+ item_cost = 40
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/sword
+
+/datum/uplink_item/item/implants/imp_sprinter
+ name = "Integrated Sprinter Implant (Organic)"
+ item_cost = 40
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/sprinter
+
+/datum/uplink_item/item/implants/imp_sprinter
+ name = "Integrated Surge Implant (Organic)"
+ item_cost = 40
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/surge
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 66702a0734..b2b9c51f4d 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -381,6 +381,7 @@ var/global/datum/controller/occupations/job_master
if(G.slot == "implant")
var/obj/item/weapon/implant/I = G.spawn_item(H)
+ I.invisibility = 100
I.implant_loadout(H)
continue
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index f60fcabbfa..19c790b06b 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -21,6 +21,10 @@
var/loaded_dna //Blood sample for DNA hashing.
var/malfunctioning = FALSE // May cause rejection, or the printing of some alien limb instead!
+ var/complex_organs = FALSE // Can it print more 'complex' organs?
+
+ var/anomalous_organs = FALSE // Can it print anomalous organs?
+
// These should be subtypes of /obj/item/organ
// Costs roughly 20u Phoron (1 sheet) per internal organ, limbs are 60u for limb and extremity
var/list/products = list(
@@ -29,6 +33,7 @@
"Kidneys" = list(/obj/item/organ/internal/kidneys,20),
"Eyes" = list(/obj/item/organ/internal/eyes, 20),
"Liver" = list(/obj/item/organ/internal/liver, 20),
+ "Spleen" = list(/obj/item/organ/internal/spleen, 20),
"Arm, Left" = list(/obj/item/organ/external/arm, 40),
"Arm, Right" = list(/obj/item/organ/external/arm/right, 40),
"Leg, Left" = list(/obj/item/organ/external/leg, 40),
@@ -39,6 +44,18 @@
"Hand, Right" = list(/obj/item/organ/external/hand/right, 20)
)
+ var/list/complex_products = list(
+ "Brain" = list(/obj/item/organ/internal/brain, 60),
+ "Larynx" = list(/obj/item/organ/internal/voicebox, 20),
+ "Head" = list(/obj/item/organ/external/head, 40)
+ )
+
+ var/list/anomalous_products = list(
+ "Lymphatic Complex" = list(/obj/item/organ/internal/immunehub, 120),
+ "Respiration Nexus" = list(/obj/item/organ/internal/lungs/replicant/mending, 80),
+ "Adrenal Valve Cluster" = list(/obj/item/organ/internal/heart/replicant/rage, 80)
+ )
+
/obj/machinery/organ_printer/attackby(var/obj/item/O, var/mob/user)
if(default_deconstruction_screwdriver(user, O))
updateUsrDialog()
@@ -90,6 +107,17 @@
else
malfunctioning = initial(malfunctioning)
+ if(manip_rating >= 3)
+ complex_organs = TRUE
+ if(manip_rating >= 4)
+ anomalous_organs = TRUE
+ if(manip_rating >= 5)
+ malfunctioning = TRUE
+ else
+ complex_organs = initial(complex_organs)
+ anomalous_organs = initial(anomalous_organs)
+ malfunctioning = initial(malfunctioning)
+
. = ..()
/obj/machinery/organ_printer/attack_hand(mob/user)
@@ -113,7 +141,17 @@
to_chat(user, "\The [src] can't operate without a reagent reservoir!")
/obj/machinery/organ_printer/proc/printing_menu(mob/user)
- var/choice = input("What would you like to print?") as null|anything in products
+ var/list/possible_list = list()
+
+ possible_list |= products
+
+ if(complex_organs)
+ possible_list |= complex_products
+
+ if(anomalous_organs)
+ possible_list |= anomalous_products
+
+ var/choice = input("What would you like to print?") as null|anything in possible_list
if(!choice || printing || (stat & (BROKEN|NOPOWER)))
return
diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm
index 74cc399beb..7665fd0e83 100644
--- a/code/game/machinery/oxygen_pump.dm
+++ b/code/game/machinery/oxygen_pump.dm
@@ -4,7 +4,7 @@
/obj/machinery/oxygen_pump
name = "emergency oxygen pump"
icon = 'icons/obj/walllocker.dmi'
- desc = "A wall mounted oxygen pump with a retractable face mask that you can pull over your face in case of emergencies."
+ desc = "A wall mounted oxygen pump with a retractable mask that you can pull over your face in case of emergencies."
icon_state = "oxygen_tank"
anchored = TRUE
@@ -236,3 +236,76 @@
icon_state_closed = "anesthetic_tank"
icon_state_open = "anesthetic_tank_open"
mask_type = /obj/item/clothing/mask/breath/anesthetic
+
+/obj/machinery/oxygen_pump/mobile
+ name = "portable oxygen pump"
+ icon = 'icons/obj/atmos.dmi'
+ desc = "A portable oxygen pump with a retractable mask that you can pull over your face in case of emergencies."
+ icon_state = "medpump"
+ icon_state_open = "medpump_open"
+ icon_state_closed = "medpump"
+
+ anchored = FALSE
+ density = TRUE
+
+ mask_type = /obj/item/clothing/mask/gas/clear
+
+ var/last_area = null
+
+/obj/machinery/oxygen_pump/mobile/process()
+ ..()
+
+ var/turf/T = get_turf(src)
+
+ if(!last_area && T)
+ last_area = T.loc
+
+ if(last_area != T.loc)
+ power_change()
+ last_area = T.loc
+
+/obj/machinery/oxygen_pump/mobile/anesthetic
+ name = "portable anesthetic pump"
+ spawn_type = /obj/item/weapon/tank/anesthetic
+ icon_state = "medpump_n2o"
+ icon_state_closed = "medpump_n2o"
+ icon_state_open = "medpump_n2o_open"
+ mask_type = /obj/item/clothing/mask/breath/anesthetic
+
+/obj/machinery/oxygen_pump/mobile/stabilizer
+ name = "portable patient stabilizer"
+ desc = "A portable oxygen pump with a retractable mask used for stabilizing patients in the field."
+
+/obj/machinery/oxygen_pump/mobile/stabilizer/process()
+ if(breather)
+ if(!can_apply_to_target(breather))
+ if(tank)
+ tank.forceMove(src)
+ breather.remove_from_mob(contained)
+ contained.forceMove(src)
+ src.visible_message("\The [contained] rapidly retracts back into \the [src]!")
+ breather = null
+ use_power = 1
+ else if(!breather.internal && tank)
+ breather.internal = tank
+ if(breather.internals)
+ breather.internals.icon_state = "internal0"
+
+ if(breather) // Safety.
+ if(ishuman(breather))
+ var/mob/living/carbon/human/H = breather
+
+ if(H.stat == DEAD)
+ H.add_modifier(/datum/modifier/bloodpump_corpse, 6 SECONDS)
+
+ else
+ H.add_modifier(/datum/modifier/bloodpump, 6 SECONDS)
+
+ var/turf/T = get_turf(src)
+
+ if(!last_area && T)
+ last_area = T.loc
+
+ if(last_area != T.loc)
+ power_change()
+ last_area = T.loc
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index 6a3e13e376..eed2aa1f60 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -522,3 +522,232 @@
S.reagents.add_reagent(reagent,amount)
S.chassis.use_power(energy_drain)
return 1
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone
+ name = "crisis dronebay"
+ desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of moderately stabilizing a patient near the exosuit."
+ icon_state = "mecha_dronebay"
+ origin_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_BIO = 5, TECH_DATA = 4)
+ range = MELEE|RANGED
+ equip_cooldown = 3 SECONDS
+ required_type = list(/obj/mecha/medical)
+
+ var/droid_state = "med_droid"
+
+ var/beam_state = "medbeam"
+
+ var/enabled = FALSE
+
+ var/icon/drone_overlay
+
+ var/max_distance = 3
+
+ var/damcap = 60
+ var/heal_dead = FALSE // Does this device heal the dead?
+
+ var/brute_heal = 0.5 // Amount of bruteloss healed.
+ var/burn_heal = 0.5 // Amount of fireloss healed.
+ var/tox_heal = 0.5 // Amount of toxloss healed.
+ var/oxy_heal = 1 // Amount of oxyloss healed.
+ var/rad_heal = 0 // Amount of radiation healed.
+ var/clone_heal = 0 // Amount of cloneloss healed.
+ var/hal_heal = 0.2 // Amount of halloss healed.
+ var/bone_heal = 0 // Percent chance it will heal a broken bone. this does not mean 'make it not instantly re-break'.
+
+ var/mob/living/Target = null
+ var/datum/beam/MyBeam = null
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Initialize()
+ ..()
+ drone_overlay = new(src.icon, icon_state = droid_state)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/attach(obj/mecha/M as obj)
+ . = ..(M)
+ if(chassis)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/detach(atom/moveto=null)
+ shut_down()
+ . = ..(moveto)
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/critfail()
+ . = ..()
+ STOP_PROCESSING(SSobj, src)
+ shut_down()
+ if(chassis && chassis.occupant)
+ to_chat(chassis.occupant, "\The [chassis] shudders as something jams!")
+ log_message("[src.name] has malfunctioned. Maintenance required.")
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/process() // Will continually try to find the nearest person above the threshold that is a valid target, and try to heal them.
+ if(chassis && enabled && chassis.has_charge(energy_drain) && (chassis.occupant || enable_special))
+ var/mob/living/Targ = Target
+ var/TargDamage = 0
+
+ if(!valid_target(Target))
+ Target = null
+
+ if(Target)
+ TargDamage = (Targ.getOxyLoss() + Targ.getFireLoss() + Targ.getBruteLoss() + Targ.getToxLoss())
+
+ for(var/mob/living/Potential in viewers(max_distance, chassis))
+ if(!valid_target(Potential))
+ continue
+
+ var/tallydamage = 0
+ if(oxy_heal)
+ tallydamage += Potential.getOxyLoss()
+ if(burn_heal)
+ tallydamage += Potential.getFireLoss()
+ if(brute_heal)
+ tallydamage += Potential.getBruteLoss()
+ if(tox_heal)
+ tallydamage += Potential.getToxLoss()
+ if(hal_heal)
+ tallydamage += Potential.getHalLoss()
+ if(clone_heal)
+ tallydamage += Potential.getCloneLoss()
+ if(rad_heal)
+ tallydamage += Potential.radiation / 2
+
+ if(tallydamage > TargDamage)
+ Target = Potential
+
+ if(MyBeam && !valid_target(MyBeam.target))
+ QDEL_NULL(MyBeam)
+
+ if(Target)
+ if(MyBeam && MyBeam.target != Target)
+ QDEL_NULL(MyBeam)
+
+ if(valid_target(Target))
+ if(!MyBeam)
+ MyBeam = chassis.Beam(Target,icon='icons/effects/beam.dmi',icon_state=beam_state,time=3 SECONDS,maxdistance=max_distance,beam_type = /obj/effect/ebeam,beam_sleep_time=2)
+ heal_target(Target)
+
+ else
+ shut_down()
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/valid_target(var/mob/living/L)
+ . = TRUE
+
+ if(!L || !istype(L))
+ return FALSE
+
+ if(get_dist(L, src) > max_distance)
+ return FALSE
+
+ if(!(L in viewers(max_distance, chassis)))
+ return FALSE
+
+ if(!unique_patient_checks(L))
+ return FALSE
+
+ if(L.stat == DEAD && !heal_dead)
+ return FALSE
+
+ var/tallydamage = 0
+ if(oxy_heal)
+ tallydamage += L.getOxyLoss()
+ if(burn_heal)
+ tallydamage += L.getFireLoss()
+ if(brute_heal)
+ tallydamage += L.getBruteLoss()
+ if(tox_heal)
+ tallydamage += L.getToxLoss()
+ if(hal_heal)
+ tallydamage += L.getHalLoss()
+ if(clone_heal)
+ tallydamage += L.getCloneLoss()
+ if(rad_heal)
+ tallydamage += L.radiation / 2
+
+ if(tallydamage < damcap)
+ return FALSE
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/shut_down()
+ if(enabled)
+ chassis.visible_message("\The [chassis]'s [src] buzzes as its drone returns to port.")
+ toggle_drone()
+ if(!isnull(Target))
+ Target = null
+ if(MyBeam)
+ QDEL_NULL(MyBeam)
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/unique_patient_checks(var/mob/living/L) // Anything special for subtypes. Does it only work on Robots? Fleshies? A species?
+ . = TRUE
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/heal_target(var/mob/living/L) // We've done all our special checks, just get to fixing damage.
+ chassis.use_power(energy_drain)
+ if(istype(L))
+ L.adjustBruteLoss(brute_heal * -1)
+ L.adjustFireLoss(burn_heal * -1)
+ L.adjustToxLoss(tox_heal * -1)
+ L.adjustOxyLoss(oxy_heal * -1)
+ L.adjustCloneLoss(clone_heal * -1)
+ L.adjustHalLoss(hal_heal * -1)
+ L.radiation = max(0, L.radiation - rad_heal)
+
+ if(ishuman(L) && bone_heal)
+ var/mob/living/carbon/human/H = L
+
+ if(H.bad_external_organs.len)
+ for(var/obj/item/organ/external/E in H.bad_external_organs)
+ if(prob(bone_heal))
+ E.status &= ~ORGAN_BROKEN
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/proc/toggle_drone()
+ ..()
+ if(chassis)
+ enabled = !enabled
+ if(enabled)
+ set_ready_state(0)
+ log_message("Activated.")
+ chassis.overlays += drone_overlay
+ else
+ set_ready_state(1)
+ log_message("Deactivated.")
+ chassis.overlays -= drone_overlay
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/Topic(href, href_list)
+ ..()
+ if(href_list["toggle_drone"])
+ toggle_drone()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/get_equip_info()
+ if(!chassis) return
+ return "* [src.name] - [enabled?"Dea":"A"]ctivate"
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/rad
+ name = "hazmat dronebay"
+ desc = "A small shoulder-mounted dronebay containing a rapid response drone capable of purging a patient near the exosuit of radiation damage."
+ icon_state = "mecha_dronebay_rad"
+
+ droid_state = "rad_drone"
+ beam_state = "g_beam"
+
+ tox_heal = 0.5
+ rad_heal = 5
+ clone_heal = 0.2
+ hal_heal = 0.2
+
+/obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer
+ name = "mounted humanoid scanner"
+ desc = "An exosuit-mounted scanning device."
+ icon_state = "mecha_analyzer_health"
+ origin_tech = list(TECH_MATERIAL = 5, TECH_MAGNET = 5, TECH_BIO = 5)
+ equip_cooldown = 5 SECONDS
+ energy_drain = 100
+ range = MELEE
+ equip_type = EQUIP_UTILITY
+ ready_sound = 'sound/weapons/flash.ogg'
+ required_type = list(/obj/mecha/medical)
+
+ tooltype = /obj/item/device/healthanalyzer/advanced
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 0d13deeb6e..294c453524 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -169,6 +169,30 @@ HALOGEN COUNTER - Radcount on mobs
dat += stomachunknownreagents[d]
else
dat += "Unknown substance[(unknown > 1)?"s":""] found in subject's stomach.
"
+ if(C.touching && C.touching.total_volume)
+ var/unknown = 0
+ var/touchreagentdata[0]
+ var/touchunknownreagents[0]
+ for(var/B in C.touching.reagent_list)
+ var/datum/reagent/T = B
+ if(T.scannable)
+ touchreagentdata["[T.id]"] = "\t[round(C.touching.get_reagent_amount(T.id), 1)]u [T.name]
"
+ if (advscan == 0 || showadvscan == 0)
+ dat += "[T.name] found in subject's dermis.
"
+ else
+ ++unknown
+ touchunknownreagents["[T.id]"] = "\t[round(C.ingested.get_reagent_amount(T.id), 1)]u [T.name]
"
+ if(advscan >= 1 && showadvscan == 1)
+ dat += "Beneficial reagents detected in subject's dermis:
"
+ for(var/d in touchreagentdata)
+ dat += touchreagentdata[d]
+ if(unknown)
+ if(advscan >= 3 && showadvscan == 1)
+ dat += "Warning: Non-medical reagent[(unknown > 1)?"s":""] found in subject's dermis:
"
+ for(var/d in touchunknownreagents)
+ dat += touchunknownreagents[d]
+ else
+ dat += "Unknown substance[(unknown > 1)?"s":""] found in subject's dermis.
"
if(C.virus2.len)
for (var/ID in C.virus2)
if (ID in virusDB)
diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm
index 3483dfbc61..d92cd5f8dd 100644
--- a/code/game/objects/items/stacks/matter_synth.dm
+++ b/code/game/objects/items/stacks/matter_synth.dm
@@ -50,4 +50,9 @@
/datum/matter_synth/wire
name = "Wire Synthesizer"
max_energy = 50
- recharge_rate = 2
\ No newline at end of file
+ recharge_rate = 2
+
+/datum/matter_synth/bandage
+ name = "Bandage Synthesizer"
+ max_energy = 10
+ recharge_rate = 1
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 1a428263ec..d1d208db08 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -11,6 +11,8 @@
var/heal_burn = 0
var/apply_sounds
+ var/upgrade_to // The type path this stack can be upgraded to.
+
/obj/item/stack/medical/attack(mob/living/carbon/M as mob, mob/user as mob)
if (!istype(M))
user << "\The [src] cannot be applied to [M]!"
@@ -59,6 +61,80 @@
use(1)
M.updatehealth()
+
+/obj/item/stack/medical/proc/upgrade_stack(var/upgrade_amount)
+ . = FALSE
+
+ var/turf/T = get_turf(src)
+
+ if(ispath(upgrade_to) && use(upgrade_amount))
+ var/obj/item/stack/medical/M = new upgrade_to(T, upgrade_amount)
+ return M
+
+ return .
+
+/obj/item/stack/medical/crude_pack
+ name = "crude bandage"
+ singular_name = "crude bandage length"
+ desc = "Some bandages to wrap around bloody stumps."
+ icon_state = "gauze"
+ origin_tech = list(TECH_BIO = 1)
+ no_variants = FALSE
+ apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg')
+
+ upgrade_to = /obj/item/stack/medical/bruise_pack
+
+/obj/item/stack/medical/crude_pack/attack(mob/living/carbon/M as mob, mob/user as mob)
+ if(..())
+ return 1
+
+ if (istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
+
+ if(affecting.open)
+ to_chat(user, "The [affecting.name] is cut open, you'll need more than a bandage!")
+ return
+
+ if(affecting.is_bandaged())
+ to_chat(user, "The wounds on [M]'s [affecting.name] have already been bandaged.")
+ return 1
+ else
+ user.visible_message("\The [user] starts bandaging [M]'s [affecting.name].", \
+ "You start bandaging [M]'s [affecting.name]." )
+ var/used = 0
+ for (var/datum/wound/W in affecting.wounds)
+ if (W.internal)
+ continue
+ if(W.bandaged)
+ continue
+ if(used == amount)
+ break
+ if(!do_mob(user, M, W.damage/3))
+ to_chat(user, "You must stand still to bandage wounds.")
+ break
+
+ if(affecting.is_bandaged()) // We do a second check after the delay, in case it was bandaged after the first check.
+ to_chat(user, "The wounds on [M]'s [affecting.name] have already been bandaged.")
+ return 1
+
+ if (W.current_stage <= W.max_bleeding_stage)
+ user.visible_message("\The [user] bandages \a [W.desc] on [M]'s [affecting.name].", \
+ "You bandage \a [W.desc] on [M]'s [affecting.name]." )
+ else
+ user.visible_message("\The [user] places a bandage over \a [W.desc] on [M]'s [affecting.name].", \
+ "You place a bandage over \a [W.desc] on [M]'s [affecting.name]." )
+ W.bandage()
+ playsound(src, pick(apply_sounds), 25)
+ used++
+ affecting.update_damages()
+ if(used == amount)
+ if(affecting.is_bandaged())
+ to_chat(user, "\The [src] is used up.")
+ else
+ to_chat(user, "\The [src] is used up, but there are more wounds to treat on \the [affecting.name].")
+ use(used)
+
/obj/item/stack/medical/bruise_pack
name = "roll of gauze"
singular_name = "gauze length"
@@ -68,6 +144,8 @@
no_variants = FALSE
apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg')
+ upgrade_to = /obj/item/stack/medical/advanced/bruise_pack
+
/obj/item/stack/medical/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob)
if(..())
return 1
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index c5be255204..984c5b97f6 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -24,6 +24,9 @@
var/list/datum/matter_synth/synths = null
var/no_variants = TRUE // Determines whether the item should update it's sprites based on amount.
+ var/pass_color = FALSE // Will the item pass its own color var to the created item? Dyed cloth, wood, etc.
+ var/strict_color_stacking = FALSE // Will the stack merge with other stacks that are different colors? (Dyed cloth, wood, etc)
+
/obj/item/stack/New(var/loc, var/amount=null)
..()
if (!stacktype)
@@ -159,6 +162,17 @@
for (var/obj/item/I in O)
qdel(I)
+ if ((pass_color || recipe.pass_color))
+ if(!color)
+ if(recipe.use_material)
+ var/material/MAT = get_material_by_name(recipe.use_material)
+ if(MAT.icon_colour)
+ O.color = MAT.icon_colour
+ else
+ return
+ else
+ O.color = color
+
/obj/item/stack/Topic(href, href_list)
..()
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
@@ -242,6 +256,9 @@
return 0
if ((stacktype != S.stacktype) && !type_verified)
return 0
+ if ((strict_color_stacking || S.strict_color_stacking) && S.color != color)
+ return 0
+
if (isnull(tamount))
tamount = src.get_amount()
@@ -355,8 +372,9 @@
var/one_per_turf = 0
var/on_floor = 0
var/use_material
+ var/pass_color
- New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null)
+ New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, pass_stack_color)
src.title = title
src.result_type = result_type
src.req_amount = req_amount
@@ -366,6 +384,7 @@
src.one_per_turf = one_per_turf
src.on_floor = on_floor
src.use_material = supplied_material
+ src.pass_color = pass_stack_color
/*
* Recipe list datum
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index dd3ddb29ca..12315972a2 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -80,6 +80,10 @@
name = "\improper \"LiquidProtein\" ration"
icon_state = "liquidprotein"
+/obj/item/trash/liquidvitamin
+ name = "\improper \"VitaPaste\" ration"
+ icon_state = "liquidvitamin"
+
/obj/item/trash/tastybread
name = "bread tube"
icon_state = "tastybread"
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 1804d576fd..c00d396e4d 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -13,6 +13,7 @@
var/implant_color = "b"
var/allow_reagents = 0
var/malfunction = 0
+ var/initialize_loc = BP_TORSO
show_messages = 1
/obj/item/weapon/implant/proc/trigger(emote, source as mob)
@@ -30,7 +31,7 @@
var/mob/living/carbon/human/H = source
var/obj/item/organ/external/affected = H.get_organ(target_zone)
if(affected)
- affected.implants += src
+ affected.implants |= src
part = affected
if(part)
forceMove(part)
@@ -65,8 +66,9 @@
/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]
+ var/obj/item/organ/external/affected = H.organs_by_name[initialize_loc]
if(handle_implant(H, affected))
+ invisibility = initial(invisibility)
post_implant(H)
/obj/item/weapon/implant/Destroy()
@@ -110,7 +112,7 @@ GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking
..()
/obj/item/weapon/implant/tracking/post_implant(var/mob/source)
- START_PROCESSING(SSobj, src)
+ START_PROCESSING(SSobj, src)
/obj/item/weapon/implant/tracking/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -563,7 +565,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/weapon/implant/death_alarm/post_implant(mob/source as mob)
mobname = source.real_name
- START_PROCESSING(SSobj, src)
+ START_PROCESSING(SSobj, src)
//////////////////////////////
// Compressed Matter Implant
diff --git a/code/game/objects/items/weapons/implants/implantaugment.dm b/code/game/objects/items/weapons/implants/implantaugment.dm
new file mode 100644
index 0000000000..10873d1d06
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implantaugment.dm
@@ -0,0 +1,196 @@
+//////////////////////////////
+// Nanite Organ Implant
+//////////////////////////////
+/obj/item/weapon/implant/organ
+ name = "nanite fabrication implant"
+ desc = "A buzzing implant covered in a writhing layer of metal insects."
+ icon_state = "implant_evil"
+ origin_tech = list(TECH_MATERIAL = 5, TECH_BIO = 2, TECH_ILLEGAL = 2)
+
+ var/organ_to_implant = /obj/item/organ/internal/augment/bioaugment/thermalshades
+ var/organ_display_name = "unknown organ"
+
+/obj/item/weapon/implant/organ/get_data()
+ var/dat = {"
+Implant Specifications:
+Name: \"GreyDoctor\" Class Nanite Hive
+Life: Activates upon implantation, destroying itself in the process.
+Important Notes: Nanites will fail to complete their task if a suitable location cannot be found for the organ.
+
+Implant Details:
+Function: Nanites will fabricate: [organ_display_name]
+Special Features: Organ identification protocols.
+Integrity: N/A"}
+ return dat
+
+/obj/item/weapon/implant/organ/post_implant(var/mob/M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+
+ var/obj/item/organ/NewOrgan = new organ_to_implant()
+
+ var/obj/item/organ/external/E = H.get_organ(NewOrgan.parent_organ)
+ to_chat(H, "You feel a tingling sensation in your [part].")
+ if(E && !(H.internal_organs_by_name[NewOrgan.organ_tag]))
+ spawn(rand(1 SECONDS, 30 SECONDS))
+ to_chat(H, "You feel a pressure in your [E] as the tingling fades, the lump caused by the implant now gone.")
+
+ NewOrgan.forceMove(H)
+ NewOrgan.owner = H
+ if(E.internal_organs == null)
+ E.internal_organs = list()
+ E.internal_organs |= NewOrgan
+ H.internal_organs_by_name[NewOrgan.organ_tag] = NewOrgan
+ H.internal_organs |= NewOrgan
+ NewOrgan.handle_organ_mod_special()
+
+ spawn(1)
+ if(!QDELETED(src))
+ qdel(src)
+
+ else
+ qdel(NewOrgan)
+ to_chat(H, "You feel a pinching sensation in your [part]. The implant remains.")
+
+/obj/item/weapon/implant/organ/islegal()
+ return 0
+
+/*
+ * Arm / leg mounted augments.
+ */
+
+/obj/item/weapon/implant/organ/limbaugment
+ name = "nanite implant"
+
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/taser
+ organ_display_name = "physiological augment"
+
+ var/list/possible_targets = list(O_AUG_L_FOREARM, O_AUG_R_FOREARM)
+
+/obj/item/weapon/implant/organ/limbaugment/post_implant(var/mob/M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+
+ var/obj/item/organ/NewOrgan = new organ_to_implant()
+
+ var/obj/item/organ/external/E = setup_augment_slots(H, NewOrgan)
+ to_chat(H, "You feel a tingling sensation in your [part].")
+ if(E && istype(E) && !(H.internal_organs_by_name[NewOrgan.organ_tag]))
+ spawn(rand(1 SECONDS, 30 SECONDS))
+ to_chat(H, "You feel a pressure in your [E] as the tingling fades, the lump caused by the implant now gone.")
+
+ NewOrgan.forceMove(H)
+ NewOrgan.owner = H
+ if(E.internal_organs == null)
+ E.internal_organs = list()
+ E.internal_organs |= NewOrgan
+ H.internal_organs_by_name[NewOrgan.organ_tag] = NewOrgan
+ H.internal_organs |= NewOrgan
+ NewOrgan.handle_organ_mod_special()
+
+ spawn(1)
+ if(!QDELETED(src))
+ qdel(src)
+
+ else
+ qdel(NewOrgan)
+ to_chat(H, "You feel a pinching sensation in your [part]. The implant remains.")
+
+/obj/item/weapon/implant/organ/limbaugment/proc/setup_augment_slots(var/mob/living/carbon/human/H, var/obj/item/organ/internal/augment/armmounted/I)
+ var/list/Choices = possible_targets.Copy()
+
+ for(var/targ in possible_targets)
+ if(H.internal_organs_by_name[targ])
+ Choices -= targ
+
+ var/target_choice = null
+ if(Choices && Choices.len)
+ if(Choices.len == 1)
+ target_choice = Choices[1]
+ else
+ target_choice = input("Choose augment location:") in Choices
+
+ else
+ return FALSE
+
+ if(target_choice)
+ switch(target_choice)
+ if(O_AUG_R_HAND)
+ I.organ_tag = O_AUG_R_HAND
+ I.parent_organ = BP_R_HAND
+ I.target_slot = slot_r_hand
+ if(O_AUG_L_HAND)
+ I.organ_tag = O_AUG_L_HAND
+ I.parent_organ = BP_L_HAND
+ I.target_slot = slot_l_hand
+
+ if(O_AUG_R_FOREARM)
+ I.organ_tag = O_AUG_R_FOREARM
+ I.parent_organ = BP_R_ARM
+ I.target_slot = slot_r_hand
+ if(O_AUG_L_FOREARM)
+ I.organ_tag = O_AUG_L_FOREARM
+ I.parent_organ = BP_L_ARM
+ I.target_slot = slot_l_hand
+
+ if(O_AUG_R_UPPERARM)
+ I.organ_tag = O_AUG_R_UPPERARM
+ I.parent_organ = BP_R_ARM
+ I.target_slot = slot_r_hand
+ if(O_AUG_L_UPPERARM)
+ I.organ_tag = O_AUG_L_UPPERARM
+ I.parent_organ = BP_L_ARM
+ I.target_slot = slot_l_hand
+
+ . = H.get_organ(I.parent_organ)
+
+/*
+ * Limb implant primary subtypes.
+ */
+
+/obj/item/weapon/implant/organ/limbaugment/upperarm
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/multiple
+ organ_display_name = "multi-use augment"
+
+ possible_targets = list(O_AUG_R_UPPERARM,O_AUG_L_UPPERARM)
+
+/obj/item/weapon/implant/organ/limbaugment/wrist
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand
+ organ_display_name = "wrist augment"
+
+ possible_targets = list(O_AUG_R_HAND,O_AUG_L_HAND)
+
+/*
+ * Limb implant general subtypes.
+ */
+
+// Wrist
+/obj/item/weapon/implant/organ/limbaugment/wrist/sword
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand/sword
+ organ_display_name = "weapon augment"
+
+// Fore-arm
+/obj/item/weapon/implant/organ/limbaugment/laser
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted
+ organ_display_name = "weapon augment"
+
+/obj/item/weapon/implant/organ/limbaugment/dart
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/dartbow
+ organ_display_name = "weapon augment"
+
+// Upper-arm.
+/obj/item/weapon/implant/organ/limbaugment/upperarm/medkit
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/multiple/medical
+
+/obj/item/weapon/implant/organ/limbaugment/upperarm/surge
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/surge
+
+/*
+ * Others
+ */
+
+/obj/item/weapon/implant/organ/pelvic
+ name = "nanite fabrication implant"
+
+ organ_to_implant = /obj/item/organ/internal/augment/bioaugment/sprint_enhance
+ organ_display_name = "pelvic augment"
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index ae00895361..93fef6ca92 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -179,3 +179,103 @@
src.imp = new /obj/item/weapon/implant/language/eal( src )
..()
return
+
+/obj/item/weapon/implantcase/shades
+ name = "glass case - 'Integrated Shades'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/shades/New()
+ src.imp = new /obj/item/weapon/implant/organ( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/taser
+ name = "glass case - 'Taser'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/taser/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/laser
+ name = "glass case - 'Laser'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/laser/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/laser( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/dart
+ name = "glass case - 'Dart'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/dart/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/dart( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/toolkit
+ name = "glass case - 'Toolkit'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/toolkit/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/upperarm( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/medkit
+ name = "glass case - 'Toolkit'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/medkit/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/upperarm/medkit( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/surge
+ name = "glass case - 'Muscle Overclocker'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/surge/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/upperarm/surge( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/analyzer
+ name = "glass case - 'Scanner'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/analyzer/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/sword
+ name = "glass case - 'Scanner'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/sword/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist/sword( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/sprinter
+ name = "glass case - 'Sprinter'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/sprinter/New()
+ src.imp = new /obj/item/weapon/implant/organ/pelvic( src )
+ ..()
+ return
diff --git a/code/game/objects/items/weapons/implants/implantdud.dm b/code/game/objects/items/weapons/implants/implantdud.dm
new file mode 100644
index 0000000000..896ea2358a
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implantdud.dm
@@ -0,0 +1,30 @@
+/obj/item/weapon/implant/dud
+ name = "unknown implant"
+ desc = "A small device with small connector wires."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "implant"
+ initialize_loc = BP_HEAD
+ var/roundstart = TRUE
+
+/obj/item/weapon/implant/dud/torso
+ name = "unknown implant"
+ desc = "A small device with small connector wires."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "implant"
+ initialize_loc = BP_TORSO
+
+/obj/item/weapon/implant/dud/old
+ name = "old implant"
+ desc = "A small device with small connector wires."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "implant"
+ roundstart = FALSE
+
+/obj/item/weapon/implant/dud/Initialize()
+ ..()
+ if(roundstart)
+ invisibility = 100
+ ..()
+ spawn(3)
+ if(!ishuman(loc) && !QDELETED(src))
+ qdel(src)
diff --git a/code/game/objects/items/weapons/implants/neuralbasic.dm b/code/game/objects/items/weapons/implants/neuralbasic.dm
index d744c80fde..0c5fe2b3da 100644
--- a/code/game/objects/items/weapons/implants/neuralbasic.dm
+++ b/code/game/objects/items/weapons/implants/neuralbasic.dm
@@ -1,6 +1,7 @@
/obj/item/weapon/implant/neural
name = "neural framework implant"
desc = "A small metal casing with numerous wires stemming off of it."
+ initialize_loc = BP_HEAD
var/obj/item/organ/internal/brain/my_brain = null
var/target_state = null
var/robotic_brain = FALSE
@@ -104,3 +105,10 @@ Implant Specifics:
"}
my_brain.take_damage(15)
my_brain = null
return
+
+/obj/item/weapon/implant/neural/roundstart/Initialize()
+ invisibility = 100
+ ..()
+ spawn(3)
+ if(!ishuman(loc) && !QDELETED(src))
+ qdel(src)
diff --git a/code/game/objects/items/weapons/storage/mre.dm b/code/game/objects/items/weapons/storage/mre.dm
index c3adc484e0..582af52f43 100644
--- a/code/game/objects/items/weapons/storage/mre.dm
+++ b/code/game/objects/items/weapons/storage/mre.dm
@@ -185,6 +185,20 @@ MRE Stuff
/obj/random/mre/sauce/crayon
)
+/obj/item/weapon/storage/mre/menu13
+ name = "medical MRE"
+ meal_desc = "This one is menu 13, vitamin paste & dessert. Only for emergencies."
+ icon_state = "crayonmre"
+ starts_with = list(
+ /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidprotein,
+ /obj/random/mre/drink,
+ /obj/item/weapon/storage/mrebag/dessert,
+ /obj/item/weapon/material/kitchen/utensil/spoon/plastic
+ )
+
/obj/item/weapon/storage/mre/random
meal_desc = "The menu label is faded out."
starts_with = list(
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index 4291752587..9624a85ca2 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -93,6 +93,42 @@
O.update()
. = ..()
+/obj/item/weapon/storage/box/syndie_kit/imp_aug
+ name = "boxed augment implant (with injector)"
+ var/case_type = /obj/item/weapon/implantcase/shades
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/Initialize()
+ new /obj/item/weapon/implanter(src)
+ new case_type(src)
+ . = ..()
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/taser
+ case_type = /obj/item/weapon/implantcase/taser
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/laser
+ case_type = /obj/item/weapon/implantcase/laser
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/dart
+ case_type = /obj/item/weapon/implantcase/dart
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/toolkit
+ case_type = /obj/item/weapon/implantcase/toolkit
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/medkit
+ case_type = /obj/item/weapon/implantcase/medkit
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/surge
+ case_type = /obj/item/weapon/implantcase/surge
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/analyzer
+ case_type = /obj/item/weapon/implantcase/analyzer
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/sword
+ case_type = /obj/item/weapon/implantcase/sword
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/sprinter
+ case_type = /obj/item/weapon/implantcase/sprinter
+
/obj/item/weapon/storage/box/syndie_kit/space
name = "boxed space suit and helmet"
starts_with = list(
diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm
index f011cd917b..292f047f0f 100644
--- a/code/game/objects/items/weapons/surgery_tools.dm
+++ b/code/game/objects/items/weapons/surgery_tools.dm
@@ -128,6 +128,15 @@
icon_state = "scalpel_manager_on"
force = 7.5
+/obj/item/weapon/surgical/scalpel/ripper
+ name = "organ pincers"
+ desc = "A horrifying bladed tool with a large metal spike in its center. The tool is used for rapidly removing organs from hopefully willing patients."
+ icon_state = "organ_ripper"
+ item_state = "bone_setter"
+ force = 15.0
+ toolspeed = 0.75
+ origin_tech = list(TECH_MATERIAL = 5, TECH_BIO = 3, TECH_ILLEGAL = 2)
+
/*
* Circular Saw
*/
@@ -147,6 +156,19 @@
sharp = 1
edge = 1
+/obj/item/weapon/surgical/circular_saw/manager
+ name = "energetic bone diverter"
+ desc = "For heavy duty cutting (and sealing), with science!"
+ icon_state = "adv_saw"
+ item_state = "saw3"
+ hitsound = 'sound/weapons/emitter2.ogg'
+ damtype = SEARING
+ w_class = ITEMSIZE_LARGE
+ origin_tech = list(TECH_BIO = 4, TECH_MATERIAL = 6, TECH_MAGNET = 6)
+ matter = list(DEFAULT_WALL_MATERIAL = 12500)
+ attack_verb = list("attacked", "slashed", "seared", "cut")
+ toolspeed = 0.75
+
//misc, formerly from code/defines/weapons.dm
/obj/item/weapon/surgical/bonegel
name = "bone gel"
@@ -245,4 +267,4 @@
/obj/item/weapon/surgical/bone_clamp/alien
icon = 'icons/obj/abductor.dmi'
- toolspeed = 0.75
\ No newline at end of file
+ toolspeed = 0.75
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index ba7a646cdc..f637536d14 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -139,7 +139,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else
O.robotize()
- for(var/name in list(O_HEART,O_EYES,O_LUNGS,O_LIVER,O_KIDNEYS,O_BRAIN))
+ for(var/name in list(O_HEART,O_EYES,O_VOICE,O_LUNGS,O_LIVER,O_KIDNEYS,O_SPLEEN,O_STOMACH,O_INTESTINE,O_BRAIN))
var/status = pref.organ_data[name]
if(!status)
continue
@@ -237,6 +237,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
organ_name = "heart"
if(O_EYES)
organ_name = "eyes"
+ if(O_VOICE)
+ organ_name = "larynx"
if(O_BRAIN)
organ_name = "brain"
if(O_LUNGS)
@@ -245,6 +247,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
organ_name = "liver"
if(O_KIDNEYS)
organ_name = "kidneys"
+ if(O_SPLEEN)
+ organ_name = "spleen"
+ if(O_STOMACH)
+ organ_name = "stomach"
+ if(O_INTESTINE)
+ organ_name = "intestines"
if(status == "cyborg")
++ind
@@ -701,7 +709,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["organs"])
- var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes", "Lungs", "Liver", "Kidneys", "Brain")
+ var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes","Larynx", "Lungs", "Liver", "Kidneys", "Spleen", "Intestines", "Stomach", "Brain")
if(!organ_name) return
var/organ = null
@@ -710,12 +718,20 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
organ = O_HEART
if("Eyes")
organ = O_EYES
+ if("Larynx")
+ organ = O_VOICE
if("Lungs")
organ = O_LUNGS
if("Liver")
organ = O_LIVER
if("Kidneys")
organ = O_KIDNEYS
+ if("Spleen")
+ organ = O_SPLEEN
+ if("Intestines")
+ organ = O_INTESTINE
+ if("Stomach")
+ organ = O_STOMACH
if("Brain")
if(pref.organ_data[BP_HEAD] != "cyborg")
user << "You may only select a cybernetic or synthetic brain if you have a full prosthetic body."
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm
index 65d5caf6df..c629d3ad72 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm
@@ -122,6 +122,24 @@
path = /obj/item/weapon/implant/tracking/weak
cost = 10
+/datum/gear/utility/implant/neural
+ display_name = "implant, neural assistance web"
+ description = "A complex web implanted into the subject, medically in order to compensate for neurological disease."
+ path = /obj/item/weapon/implant/neural/roundstart
+ cost = 6
+
+/datum/gear/utility/implant/dud1
+ display_name = "implant, head"
+ description = "An implant with no obvious purpose."
+ path = /obj/item/weapon/implant/dud
+ cost = 1
+
+/datum/gear/utility/implant/dud2
+ display_name = "implant, torso"
+ description = "An implant with no obvious purpose."
+ path = /obj/item/weapon/implant/dud/torso
+ cost = 1
+
/datum/gear/utility/implant/language
cost = 2
exploitable = 0
diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm
index 0e8a1edcbb..d39a5237f7 100644
--- a/code/modules/food/food/snacks.dm
+++ b/code/modules/food/food/snacks.dm
@@ -3733,6 +3733,24 @@
reagents.add_reagent("iron", 3)
bitesize = 4
+/obj/item/weapon/reagent_containers/food/snacks/liquidvitamin
+ name = "\improper VitaPaste Ration"
+ desc = "A variant of the liquidfood ration, designed for any carbon-based life. Somehow worse than regular liquidfood. Should this be crunchy?"
+ icon_state = "liquidvitamin"
+ trash = /obj/item/trash/liquidvitamin
+ filling_color = "#A8A8A8"
+ survivalfood = TRUE
+ center_of_mass = list("x"=16, "y"=15)
+
+/obj/item/weapon/reagent_containers/food/snacks/liquidvitamin/Initialize()
+ ..()
+ reagents.add_reagent("flour", 20)
+ reagents.add_reagent("tricordrazine", 5)
+ reagents.add_reagent("paracetamol", 5)
+ reagents.add_reagent("enzyme", 1)
+ reagents.add_reagent("iron", 3)
+ bitesize = 4
+
/obj/item/weapon/reagent_containers/food/snacks/meatcube
name = "cubed meat"
desc = "Fried, salted lean meat compressed into a cube. Not very appetizing."
diff --git a/code/modules/hydroponics/beekeeping/beehive.dm b/code/modules/hydroponics/beekeeping/beehive.dm
index 7af5ce286c..d215ab3dac 100644
--- a/code/modules/hydroponics/beekeeping/beehive.dm
+++ b/code/modules/hydroponics/beekeeping/beehive.dm
@@ -241,6 +241,8 @@
icon = 'icons/obj/beekeeping.dmi'
icon_state = "wax"
default_type = "wax"
+ pass_color = TRUE
+ strict_color_stacking = TRUE
/obj/item/stack/material/wax/New()
..()
@@ -252,6 +254,7 @@
icon_colour = "#fff343"
melting_point = T0C+300
weight = 1
+ pass_stack_colors = TRUE
var/global/list/datum/stack_recipe/wax_recipes = list( \
new/datum/stack_recipe("candle", /obj/item/weapon/flame/candle) \
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 0fe0f264bb..48cbf116c4 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -7,27 +7,27 @@
recipes = list()
// If is_brittle() returns true, these are only good for a single strike.
- recipes += new/datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
if(integrity>=50)
- recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
if(hardness>50)
- recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
/material/steel/generate_recipes()
..()
@@ -117,55 +117,55 @@
/material/plastic/generate_recipes()
..()
- recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1)
- recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0)
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0) // 500u
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0) // 250u
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0) // 100u
- recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20)
- recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20)
- recipes += new/datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1)
- recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE)
+ recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE) // 500u
+ recipes += new/datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE) // 250u
+ recipes += new/datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE) // 100u
+ recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE)
/material/wood/generate_recipes()
..()
- recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1)
- recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1)
- recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1)
- recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20)
- recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0)
- recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4)
- recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1)
- recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1)
- recipes += new/datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1)
- recipes += new/datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0)
- recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5)
- recipes += new/datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS)
+ recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE)
/material/wood/log/generate_recipes()
recipes = list()
- recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE)
/material/cardboard/generate_recipes()
..()
- recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box)
- recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty)
- recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box)
- recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes)
- recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs)
- recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps)
- recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3)
- recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg)
- recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox)
+ recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe_list("folders",list( \
new/datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue), \
new/datum/stack_recipe("grey folder", /obj/item/weapon/folder), \
@@ -195,7 +195,7 @@
/material/wood/sif/generate_recipes()
..()
- recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20)
+ recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE)
for(var/datum/stack_recipe/r_recipe in recipes)
if(r_recipe.title == "wood floor tile")
recipes -= r_recipe
@@ -210,17 +210,18 @@
/material/cloth/generate_recipes()
recipes = list()
- recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS)
- recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS)
- recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS)
- recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS)
- recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS)
- recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS)
- recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES)
- recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS)
- recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS)
- recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS)
- recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS)
- recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS)
- recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS)
- recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE)
+ recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 64eee7ddbe..31a3447bf2 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -316,6 +316,7 @@
name = "wooden plank"
icon_state = "sheet-wood"
default_type = MAT_WOOD
+ strict_color_stacking = TRUE
/obj/item/stack/material/wood/sif
name = "alien wooden plank"
@@ -367,12 +368,16 @@
icon_state = "sheet-cloth"
default_type = "cloth"
no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
/obj/item/stack/material/cardboard
name = "cardboard"
icon_state = "sheet-card"
default_type = "cardboard"
no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
/obj/item/stack/material/snow
name = "snow"
@@ -392,6 +397,8 @@
icon_state = "sheet-leather"
default_type = "leather"
no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
/obj/item/stack/material/glass
name = "glass"
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 624d695a0a..e76275007c 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -94,6 +94,7 @@ var/list/name_to_material
var/door_icon_base = "metal" // Door base icon tag. See header.
var/icon_reinf = "reinf_metal" // Overlay used
var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks.
+ var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects?
// Attributes
var/cut_delay = 0 // Delay in ticks when cutting through this wall.
@@ -866,6 +867,7 @@ var/list/name_to_material
stack_type = /obj/item/stack/material/log
sheet_singular_name = null
sheet_plural_name = "pile"
+ pass_stack_colors = TRUE
/material/wood/log/sif
name = MAT_SIFLOG
@@ -903,6 +905,7 @@ var/list/name_to_material
door_icon_base = "wood"
destruction_desc = "crumples"
radiation_resistance = 1
+ pass_stack_colors = TRUE
/material/snow
name = MAT_SNOW
@@ -949,6 +952,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
flags = MATERIAL_PADDING
conductive = 0
+ pass_stack_colors = TRUE
/material/cult
name = "cult"
diff --git a/code/modules/mob/_modifiers/medical.dm b/code/modules/mob/_modifiers/medical.dm
index 46a8877d1f..7e150ceb93 100644
--- a/code/modules/mob/_modifiers/medical.dm
+++ b/code/modules/mob/_modifiers/medical.dm
@@ -1,3 +1,38 @@
+
+/*
+ * Modifiers applied by Medical sources.
+ */
+
+/datum/modifier/bloodpump
+ name = "external blood pumping"
+ desc = "Your blood flows thanks to the wonderful power of science."
+
+ on_created_text = "You feel alive."
+ on_expired_text = "You feel.. less alive."
+ stacks = MODIFIER_STACK_EXTEND
+
+ pulse_set_level = PULSE_NORM
+
+/datum/modifier/bloodpump/check_if_valid()
+ ..()
+ if(holder.stat == DEAD)
+ src.expire()
+
+/datum/modifier/bloodpump_corpse
+ name = "forced blood pumping"
+ desc = "Your blood flows thanks to the wonderful power of science."
+
+ on_created_text = "You feel alive."
+ on_expired_text = "You feel.. less alive."
+ stacks = MODIFIER_STACK_EXTEND
+
+ pulse_set_level = PULSE_SLOW
+
+/datum/modifier/bloodpump/corpse/check_if_valid()
+ ..()
+ if(holder.stat != DEAD)
+ src.expire()
+
/*
* Modifiers caused by chemicals or organs specifically.
*/
diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm
index 800429de25..af6eaa952e 100644
--- a/code/modules/mob/_modifiers/modifiers_misc.dm
+++ b/code/modules/mob/_modifiers/modifiers_misc.dm
@@ -182,6 +182,31 @@ the artifact triggers the rage.
accuracy_dispersion = 3 // Ditto.
evasion = -45 // Too angry to dodge.
+// Speedy, but not hasted.
+/datum/modifier/sprinting
+ name = "sprinting"
+ desc = "You are filled with energy!"
+
+ on_created_text = "You feel a surge of energy!"
+ on_expired_text = "The energy high dies out."
+ stacks = MODIFIER_STACK_EXTEND
+
+ slowdown = -1
+ disable_duration_percent = 0.8
+
+// Speedy, but not berserked.
+/datum/modifier/melee_surge
+ name = "melee surge"
+ desc = "You are filled with energy!"
+
+ on_created_text = "You feel a surge of energy!"
+ on_expired_text = "The energy high dies out."
+ stacks = MODIFIER_STACK_ALLOWED
+
+ attack_speed_percent = 0.8
+ outgoing_melee_damage_percent = 1.1
+ disable_duration_percent = 0.8
+
// Non-cult version of deep wounds.
// Surprisingly, more dangerous.
/datum/modifier/grievous_wounds
@@ -201,7 +226,6 @@ the artifact triggers the rage.
-
// Ignition, but confined to the modifier system.
// This makes it more predictable and thus, easier to balance.
/datum/modifier/fire
@@ -305,7 +329,7 @@ the artifact triggers the rage.
bleeding_rate_percent = 0.8
- pulse_set_level = PULSE_SLOW
+ pulse_modifier = -1
// Temperature Normalizer.
/datum/modifier/homeothermic
diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm
index f558301b15..83f0b754ba 100644
--- a/code/modules/mob/language/language.dm
+++ b/code/modules/mob/language/language.dm
@@ -164,6 +164,11 @@
if(name != "Noise") // Audible Emotes
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
+ if(H.species.has_organ[O_VOICE] && !(flags & SIGNLANG) && !(flags & NONVERBAL)) // Does the species need a voicebox? Is the language even spoken?
+ var/obj/item/organ/internal/voicebox/vocal = H.internal_organs_by_name[O_VOICE]
+ if(!vocal || vocal.is_broken() || vocal.mute)
+ return FALSE
+
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
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 4e17f0cbe2..9c8e7e6a49 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -974,7 +974,7 @@
var/brainOxPercent = 0.015 //Default 1.5% of your current oxyloss is applied as brain damage, 50 oxyloss is 1 brain damage
if(CE_STABLE in chem_effects)
brainOxPercent = 0.008 //Halved in effect
- if(oxyloss >= 20 && prob(5))
+ if(oxyloss >= (getMaxHealth() * 0.3) && prob(5)) // If oxyloss exceeds 30% of your max health, you can take brain damage.
adjustBrainLoss(brainOxPercent * oxyloss)
if(halloss >= species.total_health)
@@ -1547,6 +1547,8 @@
var/temp = PULSE_NORM
+ var/brain_modifier = 1
+
var/modifier_shift = 0
var/modifier_set
@@ -1578,6 +1580,14 @@
var/obj/item/organ/internal/heart/Pump = internal_organs_by_name[O_HEART]
+ var/obj/item/organ/internal/brain/Control = internal_organs_by_name[O_BRAIN]
+
+ if(Control)
+ brain_modifier = Control.get_control_efficiency()
+
+ if(brain_modifier <= 0.7 && brain_modifier >= 0.4) // 70%-40% control, things start going weird as the brain is failing.
+ brain_modifier = rand(5, 15) / 10
+
if(Pump)
temp += Pump.standard_pulse_level - PULSE_NORM
@@ -1605,7 +1615,7 @@
if(R.id in cheartstopper) //Conditional heart-stoppage
if(R.volume >= R.overdose)
temp = PULSE_NONE
- return temp
+ return temp * brain_modifier
//handles different chems' influence on pulse
for(var/datum/reagent/R in reagents.reagent_list)
if(R.id in bradycardics)
@@ -1620,7 +1630,7 @@
if(R.volume >= R.overdose)
temp = PULSE_NONE
- return temp
+ return round(temp * brain_modifier)
/mob/living/carbon/human/proc/handle_heartbeat()
if(pulse == PULSE_NONE)
diff --git a/code/modules/mob/living/carbon/human/species/outsider/replicant.dm b/code/modules/mob/living/carbon/human/species/outsider/replicant.dm
index 91658a4851..ec13e29908 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/replicant.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/replicant.dm
@@ -60,7 +60,9 @@
O_BRAIN = /obj/item/organ/internal/brain/replicant,
O_EYES = /obj/item/organ/internal/eyes/replicant,
O_AREJECT = /obj/item/organ/internal/immunehub/replicant,
- O_VRLINK = /obj/item/organ/internal/brainmirror
+ O_VRLINK = /obj/item/organ/internal/brainmirror,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
/datum/species/shapeshifter/replicant/alpha
@@ -95,7 +97,9 @@
O_AREJECT = /obj/item/organ/internal/immunehub/replicant,
O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/replicant,
O_ACID = /obj/item/organ/internal/xenos/acidgland/replicant,
- O_VRLINK = /obj/item/organ/internal/brainmirror
+ O_VRLINK = /obj/item/organ/internal/brainmirror,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
/datum/species/shapeshifter/replicant/beta
@@ -119,5 +123,7 @@
O_VENTC = /obj/item/organ/internal/metamorphgland/replicant,
O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/replicant,
O_RESIN = /obj/item/organ/internal/xenos/resinspinner/replicant,
- O_VRLINK = /obj/item/organ/internal/brainmirror
+ O_VRLINK = /obj/item/organ/internal/brainmirror,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index b2da47c958..cdf5d9c21d 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -196,7 +196,9 @@
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
O_APPENDIX = /obj/item/organ/internal/appendix,
- O_EYES = /obj/item/organ/internal/eyes
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them.
var/dispersed_eyes // If set, the species will be affected by flashbangs regardless if they have eyes or not, as they see in large areas.
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 56b5c36035..cce1255c0b 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
@@ -48,8 +48,11 @@
O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
+ O_SPLEEN = /obj/item/organ/internal/spleen/minor,
O_BRAIN = /obj/item/organ/internal/brain,
- O_EYES = /obj/item/organ/internal/eyes
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE =/obj/item/organ/internal/intestine
)
/*
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 d6076f969a..9e35a58721 100644
--- a/code/modules/mob/living/carbon/human/species/station/seromi.dm
+++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm
@@ -110,7 +110,9 @@
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
- O_EYES = /obj/item/organ/internal/eyes
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
unarmed_types = list(
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 6a58cb2d08..7c02077f4d 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -25,6 +25,20 @@
spawn_flags = SPECIES_CAN_JOIN
appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR
+ 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,
+ O_APPENDIX = /obj/item/organ/internal/appendix,
+ O_SPLEEN = /obj/item/organ/internal/spleen,
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
+ )
+
inherent_verbs = list(
/mob/living/carbon/human/proc/tie_hair)
@@ -122,6 +136,8 @@
O_LIVER = /obj/item/organ/internal/liver/unathi,
O_BRAIN = /obj/item/organ/internal/brain/unathi,
O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach/unathi,
+ O_INTESTINE = /obj/item/organ/internal/intestine/unathi
)
@@ -228,7 +244,9 @@
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
- O_EYES = /obj/item/organ/internal/eyes
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE = /obj/item/organ/internal/intestine
)
/datum/species/tajaran/equip_survival_gear(var/mob/living/carbon/human/H)
@@ -384,7 +402,9 @@
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
- O_EYES = /obj/item/organ/internal/eyes
+ O_EYES = /obj/item/organ/internal/eyes,
+ O_STOMACH = /obj/item/organ/internal/stomach,
+ O_INTESTINE =/obj/item/organ/internal/intestine
)
descriptors = list(
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 1d2ce59307..e8b9a070ea 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
@@ -51,7 +51,9 @@
O_BRAIN = /obj/item/organ/internal/brain/xeno,
O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel,
O_HIVE = /obj/item/organ/internal/xenos/hivenode,
- O_NUTRIENT = /obj/item/organ/internal/diona/nutrients
+ O_NUTRIENT = /obj/item/organ/internal/diona/nutrients,
+ O_STOMACH = /obj/item/organ/internal/stomach/xeno,
+ O_INTESTINE = /obj/item/organ/internal/intestine/xeno
)
bump_flag = ALIEN
@@ -182,7 +184,9 @@
O_ACID = /obj/item/organ/internal/xenos/acidgland,
O_HIVE = /obj/item/organ/internal/xenos/hivenode,
O_RESIN = /obj/item/organ/internal/xenos/resinspinner,
- O_NUTRIENT = /obj/item/organ/internal/diona/nutrients
+ O_NUTRIENT = /obj/item/organ/internal/diona/nutrients,
+ O_STOMACH = /obj/item/organ/internal/stomach/xeno,
+ O_INTESTINE = /obj/item/organ/internal/intestine/xeno
)
inherent_verbs = list(
@@ -218,7 +222,9 @@
O_BRAIN = /obj/item/organ/internal/brain/xeno,
O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/hunter,
O_HIVE = /obj/item/organ/internal/xenos/hivenode,
- O_NUTRIENT = /obj/item/organ/internal/diona/nutrients
+ O_NUTRIENT = /obj/item/organ/internal/diona/nutrients,
+ O_STOMACH = /obj/item/organ/internal/stomach/xeno,
+ O_INTESTINE = /obj/item/organ/internal/intestine/xeno
)
inherent_verbs = list(
@@ -247,7 +253,9 @@
O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/sentinel,
O_ACID = /obj/item/organ/internal/xenos/acidgland,
O_HIVE = /obj/item/organ/internal/xenos/hivenode,
- O_NUTRIENT = /obj/item/organ/internal/diona/nutrients
+ O_NUTRIENT = /obj/item/organ/internal/diona/nutrients,
+ O_STOMACH = /obj/item/organ/internal/stomach/xeno,
+ O_INTESTINE = /obj/item/organ/internal/intestine/xeno
)
inherent_verbs = list(
@@ -284,7 +292,9 @@
O_ACID = /obj/item/organ/internal/xenos/acidgland,
O_HIVE = /obj/item/organ/internal/xenos/hivenode,
O_RESIN = /obj/item/organ/internal/xenos/resinspinner,
- O_NUTRIENT = /obj/item/organ/internal/diona/nutrients
+ O_NUTRIENT = /obj/item/organ/internal/diona/nutrients,
+ O_STOMACH = /obj/item/organ/internal/stomach/xeno,
+ O_INTESTINE = /obj/item/organ/internal/intestine/xeno
)
inherent_verbs = list(
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 33653e5a15..f289ad1cb6 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1002,6 +1002,14 @@ default behaviour is:
else
to_chat(src, "You feel nauseous...")
+ if(ishuman(src))
+ var/mob/living/carbon/human/Hu = src
+ if(CE_ANTACID in Hu.chem_effects)
+ if(prob(min(90, Hu.chem_effects[CE_ANTACID] * 15)))
+ spawn(rand(30 SECONDS, 2 MINUTES))
+ lastpuke = FALSE
+ return
+
spawn()
if(!skip_wait)
sleep(150) //15 seconds until second warning
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index b622f8fde5..0b6065b1a0 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -97,6 +97,29 @@
flick("portable_analyzer_load", src)
icon_state = "portable_analyzer_full"
+/obj/item/weapon/portable_scanner
+ name = "Portable Resonant Analyzer"
+ icon = 'icons/obj/items.dmi'
+ icon_state = "portable_scanner"
+ desc = "An advanced scanning device used for analyzing objects without completely annihilating them for science. Unfortunately, it has no connection to any database like its angrier cousin."
+
+/obj/item/weapon/portable_scanner/afterattack(var/atom/target, var/mob/living/user, proximity)
+ if(!target)
+ return
+ if(!proximity)
+ return
+ if(istype(target,/obj/item))
+ var/obj/item/I = target
+ if(do_after(src, 5 SECONDS * I.w_class))
+ for(var/mob/M in viewers())
+ M.show_message(text("[user] sweeps \the [src] over \the [I]."), 1)
+ flick("[initial(icon_state)]-scan", src)
+ if(I.origin_tech && I.origin_tech.len)
+ for(var/T in I.origin_tech)
+ to_chat(user, "\The [I] had level [I.origin_tech[T]] in [CallTechName(T)].")
+ else
+ to_chat(user, "\The [I] cannot be scanned by \the [src].")
+
//This is used to unlock other borg covers.
/obj/item/weapon/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers.
name = "access code transmission device"
diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm
index 8feab6dfbd..4fde42c0c7 100644
--- a/code/modules/organs/blood.dm
+++ b/code/modules/organs/blood.dm
@@ -117,7 +117,7 @@ var/const/CE_STABLE_THRESHOLD = 0.5
src << "You feel extremely [word]"
else if(blood_volume >= BLOOD_VOLUME_SURVIVE)
adjustOxyLoss(5 * dmg_coef)
- adjustToxLoss(3 * dmg_coef)
+// adjustToxLoss(3 * dmg_coef)
if(prob(15))
var/word = pick("dizzy","woosey","faint")
src << "You feel extremely [word]"
diff --git a/code/modules/organs/internal/augment.dm b/code/modules/organs/internal/augment.dm
new file mode 100644
index 0000000000..0c168d1679
--- /dev/null
+++ b/code/modules/organs/internal/augment.dm
@@ -0,0 +1,177 @@
+/*
+ * Augments. This file contains the base, and organic-targeting augments.
+ */
+
+/obj/item/organ/internal/augment
+ name = "augment"
+
+ icon_state = "cell_bay"
+
+ parent_organ = BP_TORSO
+
+ organ_verbs = list(/mob/living/carbon/human/proc/augment_menu) // Verbs added by the organ when present in the body.
+ target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
+ forgiving_class = FALSE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
+
+ var/obj/item/integrated_object // Objects held by the organ, used for re-usable, deployable things.
+ var/integrated_object_type // Object type the organ will spawn.
+ var/target_slot = null
+
+ var/silent_deploy = FALSE
+
+ var/image/my_radial_icon = null
+ var/radial_icon = null // DMI for the augment's radial icon.
+ var/radial_name = null // The augment's name in the Radial Menu.
+ var/radial_state = null // Icon state for the augment's radial icon.
+
+ var/aug_cooldown = 30 SECONDS
+ var/last_activate = null
+
+/obj/item/organ/internal/augment/Initialize()
+ ..()
+
+ setup_radial_icon()
+
+ if(integrated_object_type)
+ integrated_object = new integrated_object_type(src)
+ integrated_object.canremove = FALSE
+
+/obj/item/organ/internal/augment/proc/setup_radial_icon()
+ if(!radial_icon)
+ radial_icon = icon
+ if(!radial_name)
+ radial_name = name
+ if(!radial_state)
+ radial_state = icon_state
+ my_radial_icon = image(icon = radial_icon, icon_state = radial_state)
+
+/obj/item/organ/internal/augment/handle_organ_mod_special(var/removed = FALSE)
+ if(removed && integrated_object && integrated_object.loc != src)
+ if(isliving(integrated_object.loc))
+ var/mob/living/L = integrated_object.loc
+ L.drop_from_inventory(integrated_object)
+ integrated_object.forceMove(src)
+ ..(removed)
+
+/obj/item/organ/internal/augment/proc/augment_action()
+ if(!owner)
+ return
+
+ if(aug_cooldown)
+ if(last_activate <= world.time + aug_cooldown)
+ last_activate = world.time
+ else
+ return
+
+ var/item_to_equip = integrated_object
+ if(!item_to_equip && integrated_object_type)
+ item_to_equip = integrated_object_type
+
+ if(ispath(item_to_equip))
+ owner.equip_augment_item(target_slot, item_to_equip, silent_deploy, FALSE)
+ else if(item_to_equip)
+ owner.equip_augment_item(target_slot, item_to_equip, silent_deploy, FALSE, src)
+
+/*
+ * The delicate handling of augment-controlled items.
+ */
+
+// Attaches to the end of dropped items' code.
+
+/obj/item
+ var/destroy_on_drop = FALSE // Used by augments to determine if the item should destroy itself when dropped, or return to its master.
+ var/obj/item/organ/my_augment = null // Used to reference the object's host organ.
+
+/obj/item/dropped(mob/user)
+ . = ..()
+ if(src)
+ if(destroy_on_drop && !QDELETED(src))
+ qdel(src)
+ return
+ if(my_augment)
+ forceMove(my_augment)
+
+/*
+ * Human-specific mob procs.
+ */
+
+// The next two procs simply handle the radial menu for augment activation.
+
+/mob/living/carbon/human/proc/augment_menu()
+ set name = "Open Augment Menu"
+ set desc = "Toggle your augment menu."
+ set category = "Augments"
+
+ enable_augments(usr)
+
+/mob/living/carbon/human/proc/enable_augments(var/mob/living/user)
+ var/list/options = list()
+
+ var/list/present_augs = list()
+
+ for(var/obj/item/organ/internal/augment/Aug in internal_organs)
+ if(Aug.my_radial_icon && !Aug.is_broken() && Aug.check_verb_compatability())
+ present_augs[Aug.radial_name] = Aug
+
+ for(var/augname in present_augs)
+ var/obj/item/organ/internal/augment/iconsource = present_augs[augname]
+ options[augname] = iconsource.my_radial_icon
+
+ var/list/choice = list()
+ if(length(options) == 1)
+ for(var/key in options)
+ choice = key
+ else
+ choice = show_radial_menu(user, src, options)
+
+ if(!isnull(choice) && options[choice])
+ var/obj/item/organ/internal/augment/A = present_augs[choice]
+ A.augment_action(user)
+
+/* equip_augment_item
+ * Used to equip an organ's augment items when possible.
+ * slot is the target equip slot, if it's not a generic either-hand deployable,
+ * equipping is either the target object, or a path for the target object,
+ * destroy_on_drop is the default value for the object to be deleted if it is removed from their person, if equipping is a path, however, this will be set to TRUE,
+ * cling_to_organ is a reference to the organ object itself, so they can easily return to their organ when removed by any means.
+ */
+
+/mob/living/carbon/human/proc/equip_augment_item(var/slot, var/obj/item/equipping = null, var/make_sound = TRUE, var/destroy_on_drop = FALSE, var/obj/item/organ/cling_to_organ = null)
+ if(!ishuman(src))
+ return 0
+
+ if(!equipping)
+ return 0
+
+ var/mob/living/carbon/human/M = src
+
+ if((slot == slot_l_hand && l_hand) || (slot == slot_r_hand && r_hand))
+ to_chat(M,"Your hand is full. Drop something first.")
+ return 0
+
+ var/del_if_failure = destroy_on_drop
+
+ if(ispath(equipping))
+ del_if_failure = TRUE
+ equipping = new equipping(src)
+
+ if(!slot)
+ put_in_any_hand_if_possible(equipping, del_if_failure)
+
+ else
+ if(slot_is_accessible(slot, equipping, src))
+ equip_to_slot(equipping, slot, 1, 1)
+ else if(destroy_on_drop || del_if_failure)
+ qdel(equipping)
+ return 0
+
+ if(cling_to_organ) // Does the object automatically return to the organ?
+ equipping.my_augment = cling_to_organ
+
+ if(make_sound)
+ playsound(src, 'sound/items/change_jaws.ogg', 30, 1)
+
+ if(equipping.loc != src)
+ equipping.dropped()
+
+ return 1
diff --git a/code/modules/organs/internal/augment/armmounted.dm b/code/modules/organs/internal/augment/armmounted.dm
new file mode 100644
index 0000000000..73751be0d9
--- /dev/null
+++ b/code/modules/organs/internal/augment/armmounted.dm
@@ -0,0 +1,262 @@
+/*
+ * Arm mounted augments.
+ */
+
+/obj/item/organ/internal/augment/armmounted
+ name = "laser rifle implant"
+ desc = "A large implant that fits into a subject's arm. It deploys a laser-emitting array by some painful means."
+
+ icon_state = "augment_laser"
+
+ w_class = ITEMSIZE_LARGE
+
+ organ_tag = O_AUG_L_FOREARM
+
+ parent_organ = BP_L_ARM
+
+ target_slot = slot_l_hand
+
+ target_parent_classes = list(ORGAN_FLESH, ORGAN_ASSISTED)
+
+ integrated_object_type = /obj/item/weapon/gun/energy/laser/mounted/augment
+
+/obj/item/organ/internal/augment/armmounted/attackby(obj/item/I as obj, mob/user as mob)
+ if(I.is_screwdriver())
+ switch(organ_tag)
+ if(O_AUG_L_FOREARM)
+ organ_tag = O_AUG_R_FOREARM
+ parent_organ = BP_R_ARM
+ target_slot = slot_r_hand
+ if(O_AUG_R_FOREARM)
+ organ_tag = O_AUG_L_FOREARM
+ parent_organ = BP_L_ARM
+ target_slot = slot_l_hand
+ to_chat(user, "You swap \the [src]'s servos to install neatly into \the lower [parent_organ] mount.")
+ return
+
+ . = ..()
+
+/obj/item/organ/internal/augment/armmounted/taser
+ name = "taser implant"
+ desc = "A large implant that fits into a subject's arm. It deploys a taser-emitting array by some painful means."
+
+ icon_state = "augment_taser"
+
+ integrated_object_type = /obj/item/weapon/gun/energy/taser/mounted/augment
+
+/obj/item/organ/internal/augment/armmounted/dartbow
+ name = "crossbow implant"
+ desc = "A small implant that fits into a subject's arm. It deploys a dart launching mechanism through the flesh through unknown means."
+
+ icon_state = "augment_dart"
+
+ w_class = ITEMSIZE_SMALL
+
+ integrated_object_type = /obj/item/weapon/gun/energy/crossbow
+
+// Wrist-or-hand-mounted implant
+
+/obj/item/organ/internal/augment/armmounted/hand
+ name = "resonant analyzer implant"
+ desc = "An augment that fits neatly into the hand, useful for determining the usefulness of an object for research."
+ icon_state = "augment_box"
+
+ w_class = ITEMSIZE_SMALL
+
+ integrated_object_type = /obj/item/weapon/portable_scanner
+
+/obj/item/organ/internal/augment/armmounted/hand/attackby(obj/item/I as obj, mob/user as mob)
+ if(I.is_screwdriver())
+ switch(organ_tag)
+ if(O_AUG_L_HAND)
+ organ_tag = O_AUG_R_HAND
+ parent_organ = BP_R_HAND
+ target_slot = slot_r_hand
+ if(O_AUG_R_HAND)
+ organ_tag = O_AUG_L_HAND
+ parent_organ = BP_L_HAND
+ target_slot = slot_l_hand
+ to_chat(user, "You swap \the [src]'s servos to install neatly into \the upper [parent_organ] mount.")
+ return
+
+ . = ..()
+
+/obj/item/organ/internal/augment/armmounted/hand/sword
+ name = "energy blade implant"
+
+ integrated_object_type = /obj/item/weapon/melee/energy/sword
+
+/*
+ * Shoulder augment.
+ */
+
+/obj/item/organ/internal/augment/armmounted/shoulder
+ name = "shoulder augment"
+ desc = "A large implant that fits into a subject's arm. It looks kind of like a skeleton."
+
+ icon_state = "augment_armframe"
+
+ organ_tag = O_AUG_R_UPPERARM
+
+ w_class = ITEMSIZE_HUGE
+
+ integrated_object_type = null
+
+/obj/item/organ/internal/augment/armmounted/shoulder/attackby(obj/item/I as obj, mob/user as mob)
+ if(I.is_screwdriver())
+ switch(organ_tag)
+ if(O_AUG_L_UPPERARM)
+ organ_tag = O_AUG_R_UPPERARM
+ parent_organ = BP_R_ARM
+ target_slot = slot_r_hand
+ if(O_AUG_R_UPPERARM)
+ organ_tag = O_AUG_L_UPPERARM
+ parent_organ = BP_L_ARM
+ target_slot = slot_l_hand
+ to_chat(user, "You swap \the [src]'s servos to install neatly into \the upper [parent_organ] mount.")
+ return
+
+ . = ..()
+
+/obj/item/organ/internal/augment/armmounted/shoulder/surge
+ name = "muscle overclocker"
+
+ aug_cooldown = 1.5 MINUTES
+
+/obj/item/organ/internal/augment/armmounted/shoulder/surge/augment_action()
+ if(!owner)
+ return
+
+ if(aug_cooldown)
+ if(last_activate <= world.time + aug_cooldown)
+ last_activate = world.time
+ else
+ return
+
+ if(istype(owner, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = owner
+ H.add_modifier(/datum/modifier/melee_surge, 0.75 MINUTES)
+
+// The toolkit / multi-tool implant.
+
+/obj/item/organ/internal/augment/armmounted/shoulder/multiple
+ name = "rotary toolkit"
+ desc = "A large implant that fits into a subject's arm. It deploys an array of tools by some painful means."
+
+ icon_state = "augment_toolkit"
+
+ organ_tag = O_AUG_R_UPPERARM
+
+ w_class = ITEMSIZE_HUGE
+
+ integrated_object_type = null
+
+ toolspeed = 0.8
+
+ var/list/integrated_tools = list(
+ /obj/item/weapon/tool/screwdriver = null,
+ /obj/item/weapon/tool/wrench = null,
+ /obj/item/weapon/tool/crowbar = null,
+ /obj/item/weapon/tool/wirecutters = null,
+ /obj/item/device/multitool = null,
+ /obj/item/stack/cable_coil/gray = null,
+ /obj/item/weapon/tape_roll = null
+ )
+
+ var/list/integrated_tools_by_name
+
+ var/list/integrated_tool_images
+
+ var/list/synths
+
+ var/list/synth_types = list(
+ /datum/matter_synth/wire
+ )
+
+/obj/item/organ/internal/augment/armmounted/shoulder/multiple/Initialize()
+ ..()
+
+ if(integrated_object)
+ integrated_tools[integrated_object_type] = integrated_object
+
+ if(integrated_tools && integrated_tools.len)
+
+ integrated_tools_by_name = list()
+
+ integrated_tool_images = list()
+
+ if(synth_types)
+ synths = list()
+ for(var/datumpath in synth_types)
+ var/datum/matter_synth/MS = new datumpath
+ synths += MS
+
+ for(var/path in integrated_tools)
+ if(!integrated_tools[path])
+ integrated_tools[path] = new path(src)
+ var/obj/item/I = integrated_tools[path]
+ I.canremove = FALSE
+ I.toolspeed = toolspeed
+ I.my_augment = src
+ I.name = "integrated [I.name]"
+
+ for(var/tool in integrated_tools)
+ var/obj/item/Tool = integrated_tools[tool]
+ if(istype(Tool, /obj/item/stack))
+ var/obj/item/stack/S = Tool
+ S.synths = synths
+ S.uses_charge = synths.len
+ integrated_tools_by_name[Tool.name] = Tool
+ integrated_tool_images[Tool.name] = image(icon = Tool.icon, icon_state = Tool.icon_state)
+
+/obj/item/organ/internal/augment/armmounted/shoulder/multiple/handle_organ_proc_special()
+ ..()
+
+ if(!owner || is_bruised() || !synths)
+ return
+
+ if(prob(20))
+ for(var/datum/matter_synth/MS in synths)
+ MS.add_charge(MS.recharge_rate)
+
+/obj/item/organ/internal/augment/armmounted/shoulder/multiple/augment_action()
+ if(!owner)
+ return
+
+ var/list/options = list()
+
+ for(var/Iname in integrated_tools_by_name)
+ options[Iname] = integrated_tool_images[Iname]
+
+ var/list/choice = list()
+ if(length(options) == 1)
+ for(var/key in options)
+ choice = key
+ else
+ choice = show_radial_menu(owner, owner, options)
+
+ integrated_object = integrated_tools_by_name[choice]
+
+ ..()
+
+/obj/item/organ/internal/augment/armmounted/shoulder/multiple/medical
+ name = "rotary medical kit"
+ icon_state = "augment_medkit"
+ integrated_object_type = null
+
+ integrated_tools = list(
+ /obj/item/weapon/surgical/hemostat = null,
+ /obj/item/weapon/surgical/retractor = null,
+ /obj/item/weapon/surgical/cautery = null,
+ /obj/item/weapon/surgical/surgicaldrill = null,
+ /obj/item/weapon/surgical/scalpel = null,
+ /obj/item/weapon/surgical/circular_saw = null,
+ /obj/item/weapon/surgical/bonegel = null,
+ /obj/item/weapon/surgical/FixOVein = null,
+ /obj/item/weapon/surgical/bonesetter = null,
+ /obj/item/stack/medical/crude_pack = null
+ )
+
+ synth_types = list(
+ /datum/matter_synth/bandage
+ )
diff --git a/code/modules/organs/internal/bioaugment.dm b/code/modules/organs/internal/augment/bio.dm
similarity index 61%
rename from code/modules/organs/internal/bioaugment.dm
rename to code/modules/organs/internal/augment/bio.dm
index 52621e74c1..543394fcde 100644
--- a/code/modules/organs/internal/bioaugment.dm
+++ b/code/modules/organs/internal/augment/bio.dm
@@ -1,44 +1,18 @@
-/*
- * Augments. This file contains the base, and organic-targeting augments.
- */
-
-/obj/item/organ/internal/augment
- name = "augment"
-
- icon_state = "cell_bay"
-
- parent_organ = BP_TORSO
-
- organ_verbs = list() // Verbs added by the organ when present in the body.
- target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
- forgiving_class = FALSE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
-
- var/obj/item/integrated_object // Objects held by the organ, used for deployable things.
- var/integrated_object_type // Object type the organ will spawn.
-
-/obj/item/organ/internal/augment/Initialize()
- ..()
- if(integrated_object_type)
- integrated_object = new integrated_object_type(src)
- integrated_object.canremove = FALSE
-
-/obj/item/organ/internal/augment/handle_organ_mod_special(var/removed = FALSE)
- if(removed && integrated_object && integrated_object.loc != src)
- if(isliving(integrated_object.loc))
- var/mob/living/L = integrated_object.loc
- L.drop_from_inventory(integrated_object)
- integrated_object.forceMove(src)
- ..(removed)
-
// The base organic-targeting augment.
/obj/item/organ/internal/augment/bioaugment
name = "bioaugmenting implant"
- robotic = ORGAN_ROBOT
+ icon_state = "augment_hybrid"
+ dead_icon = "augment_hybrid_dead"
+
+ robotic = ORGAN_ASSISTED
target_parent_classes = list(ORGAN_FLESH)
-// Jensen Shades. Your vision can be augmented.
+/* Jensen Shades. Your vision can be augmented.
+ * This, technically, no longer needs its unique organ verb, however I have chosen to leave it for posterity
+ * in the event it needs to be referenced, while still remaining perfectly functional with either system.
+ */
/obj/item/organ/internal/augment/bioaugment/thermalshades
name = "integrated thermolensing implant"
@@ -48,20 +22,31 @@
w_class = ITEMSIZE_TINY
- organ_tag = O_AUG_TSHADE
+ organ_tag = O_AUG_EYES
+
+ robotic = ORGAN_ROBOT
parent_organ = BP_HEAD
- organ_verbs = list(/mob/living/carbon/human/proc/toggle_shades)
+ organ_verbs = list(
+ /mob/living/carbon/human/proc/augment_menu,
+ /mob/living/carbon/human/proc/toggle_shades)
integrated_object_type = /obj/item/clothing/glasses/hud/security/jensenshades
+/obj/item/organ/internal/augment/bioaugment/thermalshades/augment_action()
+ if(!owner)
+ return
+
+ owner.toggle_shades()
+
+// Here for posterity and example.
/mob/living/carbon/human/proc/toggle_shades()
set name = "Toggle Integrated Thermoshades"
set desc = "Toggle your flash-proof, thermal-integrated sunglasses."
set category = "Augments"
- var/obj/item/organ/internal/augment/aug = internal_organs_by_name[O_AUG_TSHADE]
+ var/obj/item/organ/internal/augment/aug = internal_organs_by_name[O_AUG_EYES]
if(glasses)
if(aug && aug.integrated_object == glasses)
@@ -90,3 +75,30 @@
var/obj/item/clothing/glasses/hud/security/jensenshades/J = new(get_turf(src))
equip_to_slot(J, slot_glasses, 1, 1)
to_chat(src, "Your [aug.integrated_object] deploy.")
+
+/obj/item/organ/internal/augment/bioaugment/sprint_enhance
+ name = "locomotive optimization implant"
+ desc = "A chunk of meat and metal that can manage an individual's leg musculature."
+
+ organ_tag = O_AUG_PELVIC
+
+ parent_organ = BP_GROIN
+
+ target_parent_classes = list(ORGAN_FLESH, ORGAN_ASSISTED)
+
+ aug_cooldown = 2 MINUTES
+
+/obj/item/organ/internal/augment/bioaugment/sprint_enhance/augment_action()
+ if(!owner)
+ return
+
+ if(aug_cooldown)
+ if(last_activate <= world.time + aug_cooldown)
+ last_activate = world.time
+ else
+ return
+
+ if(istype(owner, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = owner
+ H.add_modifier(/datum/modifier/sprinting, 1 MINUTES)
+
diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm
index 8bb09bebd2..ae53e56d42 100644
--- a/code/modules/organs/internal/brain.dm
+++ b/code/modules/organs/internal/brain.dm
@@ -130,6 +130,14 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
target.key = brainmob.key
..()
+/obj/item/organ/internal/brain/proc/get_control_efficiency()
+ . = 0
+
+ if(!is_broken())
+ . = 1 - (round(damage / max_damage * 10) / 10)
+
+ return .
+
/obj/item/organ/internal/brain/pariah_brain
name = "brain remnants"
desc = "Did someone tread on this? It looks useless for cloning or cyborgification."
diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm
index b65b3bc709..62e5fd16d2 100644
--- a/code/modules/organs/internal/heart.dm
+++ b/code/modules/organs/internal/heart.dm
@@ -9,7 +9,6 @@
var/standard_pulse_level = PULSE_NORM // We run on a normal clock. This is NOT CONNECTED to species heart-rate modifier.
-
/obj/item/organ/internal/heart/handle_germ_effects()
. = ..() //Up should return an infection level as an integer
if(!.) return
@@ -23,6 +22,10 @@
owner.custom_pain("A stabbing pain rolls through your chest!",1)
owner.apply_damage(damage = 25, damagetype = HALLOSS, def_zone = parent_organ)
+/obj/item/organ/internal/heart/robotize()
+ ..()
+ standard_pulse_level = PULSE_NONE
+
/obj/item/organ/internal/heart/grey
icon_state = "heart_grey-on"
dead_icon = "heart_grey-off"
diff --git a/code/modules/organs/internal/intestine.dm b/code/modules/organs/internal/intestine.dm
new file mode 100644
index 0000000000..ed5319fb27
--- /dev/null
+++ b/code/modules/organs/internal/intestine.dm
@@ -0,0 +1,23 @@
+/obj/item/organ/internal/intestine
+ name = "intestine"
+ icon_state = "intestine"
+ organ_tag = O_INTESTINE
+ parent_organ = BP_GROIN
+
+/obj/item/organ/internal/intestine/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Viral Gastroenteritis
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("There's a twisting pain in your abdomen!",1)
+ owner.vomit()
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("Your abdomen feels like it's tearing itself apart!",1)
+ owner.m_intent = "walk"
+ owner.hud_used.move_intent.icon_state = "walking"
+
+/obj/item/organ/internal/intestine/xeno
+ color = "#555555"
diff --git a/code/modules/organs/internal/kidneys.dm b/code/modules/organs/internal/kidneys.dm
index 571fe4f9e9..2378c0fe99 100644
--- a/code/modules/organs/internal/kidneys.dm
+++ b/code/modules/organs/internal/kidneys.dm
@@ -22,6 +22,13 @@
else if(is_broken())
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
+/obj/item/organ/internal/kidneys/handle_organ_proc_special()
+ . = ..()
+
+ if(owner && owner.getToxLoss() <= owner.getMaxHealth() * 0.1) // If you have less than 10 tox damage (for a human), your kidneys can help purge it.
+ if(prob(owner.getToxLoss()))
+ owner.adjustToxLoss(rand(-1,-3))
+
/obj/item/organ/internal/kidneys/handle_germ_effects()
. = ..() //Up should return an infection level as an integer
if(!.) return
diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm
index 9966e93aa7..e515eec971 100644
--- a/code/modules/organs/internal/lungs.dm
+++ b/code/modules/organs/internal/lungs.dm
@@ -21,6 +21,13 @@
spawn owner.emote("me", 1, "gasps for air!")
owner.AdjustLosebreath(15)
+ if(owner.internal_organs_by_name[O_BRAIN]) // As the brain starts having Trouble, the lungs start malfunctioning.
+ var/obj/item/organ/internal/brain/Brain = owner.internal_organs_by_name[O_BRAIN]
+ if(Brain.get_control_efficiency() <= 0.8)
+ if(prob(4 / Brain.get_control_efficiency()))
+ spawn owner.emote("me", 1, "gasps for air!")
+ owner.AdjustLosebreath(round(3 / Brain.get_control_efficiency()))
+
/obj/item/organ/internal/lungs/proc/rupture()
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(istype(parent))
diff --git a/code/modules/organs/internal/spleen.dm b/code/modules/organs/internal/spleen.dm
new file mode 100644
index 0000000000..352a36207f
--- /dev/null
+++ b/code/modules/organs/internal/spleen.dm
@@ -0,0 +1,87 @@
+/obj/item/organ/internal/spleen
+ name = "spleen"
+ icon_state = "spleen"
+ organ_tag = O_SPLEEN
+ parent_organ = BP_TORSO
+ w_class = ITEMSIZE_TINY
+
+ var/spleen_tick = 20 // The number of ticks between Spleen cycles.
+ var/spleen_efficiency = 1 // A multiplier for how efficient this spleen is.
+
+/obj/item/organ/internal/spleen/process()
+ ..()
+ if(!owner) return
+
+ if(owner.life_tick % spleen_tick == 0)
+
+ //High toxins levels are dangerous
+ if(owner.getToxLoss() >= 30 && !owner.reagents.has_reagent("anti_toxin"))
+ //Healthy liver suffers on its own
+ if (src.damage < min_broken_damage)
+ src.damage += 0.2 * spleen_tick
+ //Damaged one shares the fun
+ else
+ var/obj/item/organ/internal/O = pick(owner.internal_organs)
+ if(O)
+ O.damage += 0.2 * spleen_tick
+
+ else if(!src.is_broken()) // If the spleen isn't severely damaged, it can help fight infections. Key word, can.
+ var/obj/item/organ/external/OEx = pick(owner.organs)
+ OEx.adjust_germ_level(round(rand(0 * spleen_efficiency,-10 * spleen_efficiency)))
+
+ if(!src.is_bruised() && owner.internal_organs_by_name[O_BRAIN]) // If it isn't bruised, it helps with brain infections.
+ var/obj/item/organ/internal/brain/B = owner.internal_organs_by_name[O_BRAIN]
+ B.adjust_germ_level(round(rand(-3 * spleen_efficiency, -10 * spleen_efficiency)))
+
+ //Detox can heal small amounts of damage
+ if (src.damage && src.damage < src.min_bruised_damage && owner.reagents.has_reagent("anti_toxin"))
+ src.damage -= 0.2 * spleen_tick * spleen_efficiency
+
+ if(src.damage < 0)
+ src.damage = 0
+
+/obj/item/organ/internal/spleen/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ // Low levels can cause pain and haemophilia, high levels can cause brain infections.
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("There's a sharp pain in your [owner.get_organ(parent_organ)]!",1)
+ owner.add_modifier(/datum/modifier/trait/haemophilia, 2 MINUTES * spleen_efficiency)
+ if (. >= 2)
+ if(prob(1))
+ if(owner.getToxLoss() < owner.getMaxHealth() * 0.2 * spleen_efficiency)
+ owner.adjustToxLoss(2 * spleen_efficiency)
+ else if(owner.internal_organs_by_name[O_BRAIN])
+ var/obj/item/organ/internal/brain/Brain = owner.internal_organs_by_name[O_BRAIN]
+ Brain.adjust_germ_level(round(rand(5 * spleen_efficiency,20 * spleen_efficiency)))
+
+/obj/item/organ/internal/spleen/die()
+ ..()
+ if(owner)
+ owner.add_modifier(/datum/modifier/trait/haemophilia, round(15 MINUTES * spleen_efficiency))
+ var/obj/item/organ/external/Target = owner.get_organ(parent_organ)
+ var/datum/wound/W = new /datum/wound/internal_bleeding(round(20 * spleen_efficiency))
+ owner.adjustToxLoss(15 * spleen_efficiency)
+ Target.wounds += W
+
+/obj/item/organ/internal/spleen/skrell
+ name = "lymphatic hub"
+ icon_state = "spleen"
+ parent_organ = BP_HEAD
+ spleen_efficiency = 0.5
+
+/obj/item/organ/internal/spleen/skrell/Initialize()
+ ..()
+ adjust_scale(0.8,0.7)
+
+/obj/item/organ/internal/spleen/minor
+ name = "vestigial spleen"
+ parent_organ = BP_GROIN
+ spleen_efficiency = 0.3
+ spleen_tick = 15
+
+/obj/item/organ/internal/spleen/minor/Initialize()
+ ..()
+ adjust_scale(0.7)
diff --git a/code/modules/organs/internal/stomach.dm b/code/modules/organs/internal/stomach.dm
new file mode 100644
index 0000000000..02cf7cb31d
--- /dev/null
+++ b/code/modules/organs/internal/stomach.dm
@@ -0,0 +1,50 @@
+/obj/item/organ/internal/stomach
+ name = "stomach"
+ icon_state = "stomach"
+ organ_tag = O_STOMACH
+ parent_organ = BP_GROIN
+
+ unacidable = TRUE // Don't melt when holding your acid, dangit.
+
+ var/acidtype = "stomacid" // Incase you want some stomach organ with, say, polyacid instead, or sulphuric.
+ var/max_acid_volume = 30
+
+ var/deadly_hold = TRUE // Does the stomach do damage to mobs eaten by its owner? Xenos should probably have this FALSE.
+
+/obj/item/organ/internal/stomach/Initialize()
+ ..()
+
+ if(reagents)
+ reagents.maximum_volume = 30
+ else
+ create_reagents(30)
+
+/obj/item/organ/internal/stomach/handle_organ_proc_special()
+ if(owner && istype(owner, /mob/living/carbon/human))
+ if(reagents)
+ if(reagents.total_volume + 2 < max_acid_volume && prob(20))
+ reagents.add_reagent(acidtype, rand(1,2))
+
+ for(var/mob/living/L in owner.stomach_contents) // Splashes mobs inside with acid. Twice as effective as being splashed with the same acid outside the body.
+ reagents.trans_to(L, 2, 2, 0)
+
+ if(is_broken() && prob(1))
+ owner.custom_pain("There's a twisting pain in your abdomen!",1)
+ owner.vomit(FALSE, TRUE)
+
+/obj/item/organ/internal/stomach/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Bacterial Gastroenteritis
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("There's a twisting pain in your abdomen!",1)
+ owner.apply_effect(2, AGONY, 0)
+ if (. >= 2)
+ if(prob(1) && owner.getToxLoss() < owner.getMaxHealth()*0.2)
+ owner.adjustToxLoss(3)
+ owner.vomit(FALSE, TRUE)
+
+/obj/item/organ/internal/stomach/xeno
+ color = "#555555"
diff --git a/code/modules/organs/internal/voicebox.dm b/code/modules/organs/internal/voicebox.dm
index 4de69fe8f2..2cf264f780 100644
--- a/code/modules/organs/internal/voicebox.dm
+++ b/code/modules/organs/internal/voicebox.dm
@@ -1,7 +1,7 @@
/*
* 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.
+ * such as EAL. Not standard or organic, because at the moment it's undesireable to completely mute characters. - - Can now actually cause muting, if destroyed / removed.
*/
/obj/item/organ/internal/voicebox
@@ -10,6 +10,7 @@
parent_organ = BP_TORSO // We don't have a neck area
organ_tag = O_VOICE
will_assist_languages = list(LANGUAGE_GALCOM)
+ var/mute = FALSE
/obj/item/organ/internal/voicebox/New()
..()
diff --git a/code/modules/organs/subtypes/unathi.dm b/code/modules/organs/subtypes/unathi.dm
index 212330577c..03ff671b63 100644
--- a/code/modules/organs/subtypes/unathi.dm
+++ b/code/modules/organs/subtypes/unathi.dm
@@ -47,4 +47,11 @@
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
/obj/item/organ/internal/brain/unathi
- color = "#b3cbc3"
\ No newline at end of file
+ color = "#b3cbc3"
+
+/obj/item/organ/internal/stomach/unathi
+ color = "#b3cbc3"
+ max_acid_volume = 40
+
+/obj/item/organ/internal/intestine/unathi
+ color = "#b3cbc3"
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 3ac7c3fad2..50d1a8f884 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -17,6 +17,7 @@
//self-recharging
var/self_recharge = 0 //if set, the weapon will recharge itself
var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically
+ var/use_organic_power = 0 // If set, the weapon will draw from nutrition or blood.
var/recharge_time = 4
var/charge_tick = 0
var/charge_delay = 75 //delay between firing and charging
@@ -61,6 +62,27 @@
if(!external || !external.use(rechargeamt)) //Take power from the borg...
return 0
+ if(use_organic_power)
+ var/mob/living/carbon/human/H
+ if(ishuman(loc))
+ H = loc
+
+ if(istype(loc, /obj/item/organ))
+ var/obj/item/organ/O = loc
+ if(O.owner)
+ H = O.owner
+
+ if(istype(H))
+ var/start_nutrition = H.nutrition
+ var/end_nutrition = 0
+
+ H.nutrition -= rechargeamt / 10
+
+ end_nutrition = H.nutrition
+
+ if(start_nutrition - max(0, end_nutrition) < rechargeamt / 10)
+ H.remove_blood((rechargeamt / 10) - (start_nutrition - max(0, end_nutrition)))
+
power_supply.give(rechargeamt) //... to recharge 1/5th the battery
update_icon()
else
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index eeb8d779d2..f6321947b2 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -24,6 +24,11 @@
use_external_power = 1
one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
+/obj/item/weapon/gun/energy/laser/mounted/augment
+ use_external_power = FALSE
+ use_organic_power = TRUE
+ canremove = FALSE
+
/obj/item/weapon/gun/energy/laser/practice
name = "practice laser carbine"
desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice."
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index a23cf5bb4b..4240abe9e3 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -11,6 +11,12 @@
self_recharge = 1
use_external_power = 1
+/obj/item/weapon/gun/energy/taser/mounted/augment
+ self_recharge = 1
+ use_external_power = 0
+ use_organic_power = TRUE
+ canremove = FALSE
+
/obj/item/weapon/gun/energy/taser/mounted/cyborg
name = "taser gun"
charge_cost = 400
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm
index 8ad8b6486d..0b010dc4f6 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents.dm
@@ -20,6 +20,7 @@
var/max_dose = 0
var/overdose = 0 //Amount at which overdose starts
var/overdose_mod = 2 //Modifier to overdose damage
+ var/can_overdose_touch = FALSE // Can the chemical OD when processing on touch?
var/scannable = 0 // Shows up on health analyzers.
var/affects_dead = 0
var/cup_icon_state = null
@@ -60,19 +61,25 @@
var/datum/reagents/metabolism/active_metab = location
var/removed = metabolism
+ var/ingest_rem_mult = 1
+ var/ingest_abs_mult = 1
+
if(!mrate_static == TRUE)
// Modifiers
for(var/datum/modifier/mod in M.modifiers)
if(!isnull(mod.metabolism_percent))
removed *= mod.metabolism_percent
+ ingest_rem_mult *= mod.metabolism_percent
// Species
removed *= M.species.metabolic_rate
+ ingest_rem_mult *= M.species.metabolic_rate
// Metabolism
removed *= active_metab.metabolism_speed
+ ingest_rem_mult *= active_metab.metabolism_speed
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(H.species.has_organ[O_HEART])
+ if(H.species.has_organ[O_HEART] && (active_metab.metabolism_class == CHEM_BLOOD))
var/obj/item/organ/internal/heart/Pump = H.internal_organs_by_name[O_HEART]
if(!Pump)
removed *= 0.1
@@ -80,14 +87,31 @@
removed *= 0.8
else // Otherwise, chemicals process as per percentage of your current pulse, or, if you have no pulse but are alive, by a miniscule amount.
removed *= max(0.1, H.pulse / Pump.standard_pulse_level)
+
+ if(H.species.has_organ[O_STOMACH] && (active_metab.metabolism_class == CHEM_INGEST))
+ var/obj/item/organ/internal/stomach/Chamber = H.internal_organs_by_name[O_STOMACH]
+ if(Chamber)
+ ingest_rem_mult *= max(0.1, 1 - (Chamber.damage / Chamber.max_damage))
+ else
+ ingest_rem_mult = 0.1
+
+ if(H.species.has_organ[O_INTESTINE] && (active_metab.metabolism_class == CHEM_INGEST))
+ var/obj/item/organ/internal/intestine/Tube = H.internal_organs_by_name[O_INTESTINE]
+ if(Tube)
+ ingest_abs_mult *= max(0.1, 1 - (Tube.damage / Tube.max_damage))
+ else
+ ingest_abs_mult = 0.1
+
if(filtered_organs && filtered_organs.len)
for(var/organ_tag in filtered_organs)
var/obj/item/organ/internal/O = H.internal_organs_by_name[organ_tag]
if(O && !O.is_broken() && prob(max(0, O.max_damage - O.damage)))
removed *= 0.8
+ if(active_metab.metabolism_class == CHEM_INGEST)
+ ingest_rem_mult *= 0.8
if(ingest_met && (active_metab.metabolism_class == CHEM_INGEST))
- removed = ingest_met
+ removed = ingest_met * ingest_rem_mult
if(touch_met && (active_metab.metabolism_class == CHEM_TOUCH))
removed = touch_met
removed = min(removed, volume)
@@ -98,10 +122,10 @@
if(CHEM_BLOOD)
affect_blood(M, alien, removed)
if(CHEM_INGEST)
- affect_ingest(M, alien, removed)
+ affect_ingest(M, alien, removed * ingest_abs_mult)
if(CHEM_TOUCH)
affect_touch(M, alien, removed)
- if(overdose && (volume > overdose) && (active_metab.metabolism_class != CHEM_TOUCH))
+ if(overdose && (volume > overdose) && (active_metab.metabolism_class != CHEM_TOUCH && !can_overdose_touch))
overdose(M, alien, removed)
remove_self(removed)
return
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
index 2b92302196..3805ee23f2 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
@@ -7,6 +7,15 @@
reagent_state = SOLID
color = "#A8A8A8"
+/datum/reagent/calcium
+ name = "Calcium"
+ id = "calcium"
+ description = "A chemical element, the building block of bones."
+ taste_description = "metallic chalk" // Apparently, calcium tastes like calcium.
+ taste_mult = 1.3
+ reagent_state = SOLID
+ color = "#e9e6e4"
+
/datum/reagent/carbon
name = "Carbon"
id = "carbon"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
index 09a0993346..c4e22dfb2a 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
@@ -27,6 +27,7 @@
metabolism = REM * 0.5
scannable = 1
touch_met = REM * 0.75
+ can_overdose_touch = TRUE
/datum/reagent/inaprovaline/topical/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(alien != IS_DIONA)
@@ -84,6 +85,7 @@
overdose = REAGENTS_OVERDOSE * 0.75
scannable = 1
touch_met = REM * 0.75
+ can_overdose_touch = TRUE
/datum/reagent/bicaridine/topical/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
var/chem_effective = 1
@@ -100,6 +102,25 @@
if(alien != IS_DIONA)
M.heal_organ_damage(6 * removed * chem_effective, 0)
+/datum/reagent/calciumcarbonate
+ name = "calcium carbonate"
+ id = "calciumcarbonate"
+ description = "Calcium carbonate is a calcium salt commonly used as an antacid."
+ taste_description = "chalk"
+ reagent_state = SOLID
+ color = "#eae6e3"
+ overdose = REAGENTS_OVERDOSE * 0.8
+ metabolism = REM * 0.4
+ scannable = 1
+
+/datum/reagent/calciumcarbonate/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) // Why would you inject this.
+ if(alien != IS_DIONA)
+ M.adjustToxLoss(3 * removed)
+
+/datum/reagent/calciumcarbonate/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ M.add_chemical_effect(CE_ANTACID, 3)
+
/datum/reagent/kelotane
name = "Kelotane"
id = "kelotane"
@@ -147,6 +168,7 @@
overdose = REAGENTS_OVERDOSE * 0.4
scannable = 1
touch_met = REM * 0.75
+ can_overdose_touch = TRUE
/datum/reagent/dermaline/topical/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
var/chem_effective = 1
@@ -282,6 +304,42 @@
if(alien != IS_DIONA)
affect_blood(M, alien, removed * 0.4)
+/datum/reagent/tricorlidaze
+ name = "Tricorlidaze"
+ id = "tricorlidaze"
+ description = "Tricorlidaze is a topical gel produced with tricordrazine and sterilizine."
+ taste_description = "bitterness"
+ reagent_state = SOLID
+ color = "#B060FF"
+ scannable = 1
+ can_overdose_touch = TRUE
+
+/datum/reagent/tricorlidaze/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ var/chem_effective = 1
+ if(alien == IS_SLIME)
+ chem_effective = 0.5
+ M.adjustOxyLoss(-2 * removed * chem_effective)
+ M.heal_organ_damage(1 * removed, 1 * removed * chem_effective)
+ M.adjustToxLoss(-2 * removed * chem_effective)
+
+/datum/reagent/tricorlidaze/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ M.adjustToxLoss(3 * removed)
+ affect_blood(M, alien, removed * 0.4)
+
+/datum/reagent/tricorlidaze/touch_obj(var/obj/O)
+ if(istype(O, /obj/item/stack/medical/bruise_pack) && round(volume) >= 5)
+ var/obj/item/stack/medical/bruise_pack/C = O
+ var/packname = C.name
+ var/to_produce = min(C.amount, round(volume / 5))
+
+ var/obj/item/stack/medical/M = C.upgrade_stack(to_produce)
+
+ if(M && M.amount)
+ holder.my_atom.visible_message("\The [packname] bubbles.")
+ remove_self(to_produce * 5)
+
/datum/reagent/cryoxadone
name = "Cryoxadone"
id = "cryoxadone"
@@ -333,6 +391,40 @@
M.heal_organ_damage(30 * removed, 30 * removed * chem_effective)
M.adjustToxLoss(-30 * removed * chem_effective)
+/datum/reagent/necroxadone
+ name = "Necroxadone"
+ id = "necroxadone"
+ description = "A liquid compound based upon that which is used in the cloning process. Utilized primarily in severe cases of toxic shock."
+ taste_description = "meat"
+ reagent_state = LIQUID
+ color = "#94B21C"
+ metabolism = REM * 0.5
+ mrate_static = TRUE
+ scannable = 1
+
+/datum/reagent/necroxadone/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagents/metabolism/location)
+ if(M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse))
+ affects_dead = TRUE
+ else
+ affects_dead = FALSE
+
+ . = ..(M, alien, location)
+
+/datum/reagent/necroxadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(M.bodytemperature < 170 || (M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse)))
+ var/chem_effective = 1
+ if(alien == IS_SLIME)
+ if(prob(10))
+ to_chat(M, "It's so cold. Something causes your cellular mass to harden sporadically, resulting in seizure-like twitching.")
+ chem_effective = 0.5
+ M.Weaken(20)
+ M.silent = max(M.silent, 20)
+ M.make_jittery(4)
+ if(M.stat != DEAD)
+ M.adjustCloneLoss(-5 * removed * chem_effective)
+ M.adjustOxyLoss(-20 * removed * chem_effective)
+ M.adjustToxLoss(-40 * removed * chem_effective)
+
/* Painkillers */
/datum/reagent/paracetamol
@@ -636,7 +728,7 @@
if(ishuman(M))
var/mob/living/carbon/human/H = M
for(var/obj/item/organ/I in H.internal_organs)
- if(I.robotic >= ORGAN_ROBOT || !(I.organ_tag in list(O_APPENDIX, O_NUTRIENT, O_PLASMA, O_POLYP)))
+ if(I.robotic >= ORGAN_ROBOT || !(I.organ_tag in list(O_APPENDIX, O_STOMACH, O_INTESTINE, O_NUTRIENT, O_PLASMA, O_POLYP)))
continue
if(I.damage > 0)
I.damage = max(I.damage - 4 * removed * repair_strength, 0)
@@ -700,7 +792,7 @@
if(ishuman(M))
var/mob/living/carbon/human/H = M
for(var/obj/item/organ/I in H.internal_organs)
- if(I.robotic >= ORGAN_ROBOT || !(I.organ_tag in list(O_HEART, O_RESPONSE, O_ANCHOR, O_EGG)))
+ if(I.robotic >= ORGAN_ROBOT || !(I.organ_tag in list(O_HEART, O_SPLEEN, O_RESPONSE, O_ANCHOR, O_EGG)))
continue
if(I.damage > 0)
I.damage = max(I.damage - 4 * removed * repair_strength, 0)
@@ -877,11 +969,11 @@
if(M.ingested)
for(var/datum/reagent/R in M.ingested.reagent_list)
if(istype(R, /datum/reagent/ethanol))
- R.remove_self(removed * 5)
+ R.remove_self(removed * 30)
if(M.bloodstr)
for(var/datum/reagent/R in M.bloodstr.reagent_list)
if(istype(R, /datum/reagent/ethanol))
- R.remove_self(removed * 15)
+ R.remove_self(removed * 20)
/datum/reagent/hyronalin
name = "Hyronalin"
@@ -1014,6 +1106,54 @@
var/obj/item/organ/external/eo = pick(H.organs) //Misleading variable name, 'organs' is only external organs
eo.fracture()
+/datum/reagent/spacomycaze
+ name = "Spacomycaze"
+ id = "spacomycaze"
+ description = "An all-purpose painkilling antibiotic gel."
+ taste_description = "oil"
+ reagent_state = SOLID
+ color = "#C1C1C8"
+ metabolism = REM * 0.4
+ mrate_static = TRUE
+ overdose = REAGENTS_OVERDOSE
+ scannable = 1
+ data = 0
+ can_overdose_touch = TRUE
+
+/datum/reagent/spacomycaze/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ M.add_chemical_effect(CE_PAINKILLER, 10)
+ M.adjustToxLoss(3 * removed)
+
+/datum/reagent/spacomycaze/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ affect_blood(M, alien, removed * 0.8)
+
+/datum/reagent/spacomycaze/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+ if(alien == IS_SLIME)
+ if(volume <= 0.1 && data != -1)
+ data = -1
+ to_chat(M, "The itching fades...")
+ else
+ var/delay = (2 MINUTES)
+ if(world.time > data + delay)
+ data = world.time
+ to_chat(M, "Your skin itches.")
+
+ M.add_chemical_effect(CE_ANTIBIOTIC, dose >= overdose ? ANTIBIO_OD : ANTIBIO_NORM)
+ M.add_chemical_effect(CE_PAINKILLER, 20) // 5 less than paracetamol.
+
+/datum/reagent/spacomycaze/touch_obj(var/obj/O)
+ if(istype(O, /obj/item/stack/medical/crude_pack) && round(volume) >= 1)
+ var/obj/item/stack/medical/crude_pack/C = O
+ var/packname = C.name
+ var/to_produce = min(C.amount, round(volume))
+
+ var/obj/item/stack/medical/M = C.upgrade_stack(to_produce)
+
+ if(M && M.amount)
+ holder.my_atom.visible_message("\The [packname] bubbles.")
+ remove_self(to_produce)
+
/datum/reagent/sterilizine
name = "Sterilizine"
id = "sterilizine"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm
index 43635aba5b..971a54bff2 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm
@@ -191,6 +191,7 @@
taste_description = "bitterness"
reagent_state = LIQUID
strength = 5
+ filtered_organs = list(O_SPLEEN)
/datum/reagent/toxin/expired_medicine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
..()
@@ -232,6 +233,7 @@
color = "#FFFFFF"
strength = 0
overdose = REAGENTS_OVERDOSE
+ filtered_organs = list(O_SPLEEN, O_KIDNEYS)
/datum/reagent/toxin/potassium_chloride/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
..()
@@ -257,6 +259,7 @@
color = "#FFFFFF"
strength = 10
overdose = 20
+ filtered_organs = list(O_SPLEEN, O_KIDNEYS)
/datum/reagent/toxin/potassium_chlorophoride/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
..()
@@ -297,6 +300,35 @@
M.status_flags &= ~FAKEDEATH
return ..()
+/datum/reagent/toxin/lichpowder
+ name = "Lich Powder"
+ id = "lichpowder"
+ description = "A stablized nerve agent that puts the subject into a strange state of un-death."
+ reagent_state = SOLID
+ color = "#666666"
+ metabolism = REM * 0.75
+ strength = 2
+ mrate_static = TRUE
+
+/datum/reagent/toxin/lichpowder/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+ if(alien == IS_DIONA)
+ return
+ M.status_flags |= FAKEDEATH
+ M.adjustOxyLoss(1 * removed)
+ M.silent = max(M.silent, 10)
+ M.tod = stationtime2text()
+
+ if(prob(1))
+ M.visible_message("[M] wheezes.", "You wheeze sharply... it's cold.")
+ M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, T0C - 10)
+
+/datum/reagent/toxin/lichpowder/Destroy()
+ if(holder && holder.my_atom && ismob(holder.my_atom))
+ var/mob/M = holder.my_atom
+ M.status_flags &= ~FAKEDEATH
+ return ..()
+
/datum/reagent/toxin/fertilizer //Reagents used for plant fertilizers.
name = "fertilizer"
id = "fertilizer"
@@ -392,6 +424,16 @@
power = 10
meltdose = 4
+/datum/reagent/acid/digestive
+ name = "Digestive acid"
+ id = "stomacid"
+ description = "Some form of digestive slurry."
+ taste_description = "vomit"
+ reagent_state = LIQUID
+ color = "#664330"
+ power = 2
+ meltdose = 30
+
/datum/reagent/thermite/venom
name = "Pyrotoxin"
id = "thermite_v"
@@ -420,6 +462,7 @@
description = "A biological agent that acts similarly to pepperspray. This compound seems to be particularly cruel, however, capable of permeating the barriers of blood vessels."
taste_description = "fire"
color = "#B31008"
+ filtered_organs = list(O_SPLEEN)
/datum/reagent/condensedcapsaicin/venom/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(alien == IS_DIONA)
@@ -718,6 +761,7 @@
id = "serotrotium_v"
description = "A chemical compound that promotes concentrated production of the serotonin neurotransmitter in humans. This appears to be a biologically produced form, resulting in a specifically toxic nature."
taste_description = "chalky bitterness"
+ filtered_organs = list(O_SPLEEN)
/datum/reagent/serotrotium/venom/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(alien == IS_DIONA)
@@ -760,6 +804,7 @@
reagent_state = LIQUID
color = "#C8A5DC"
overdose = REAGENTS_OVERDOSE
+ filtered_organs = list(O_SPLEEN)
/datum/reagent/impedrezene/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(alien == IS_DIONA)
@@ -976,6 +1021,7 @@ datum/reagent/talum_quem/affect_blood(var/mob/living/carbon/M, var/alien, var/re
reagent_state = SOLID
color = "#555555"
metabolism = REM * 4
+ filtered_organs = list(O_SPLEEN)
/datum/reagent/neurophage_nanites/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
M.adjustBrainLoss(2 * removed) // Their job is to give you a bad time.
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 3a1f919747..d55f2d8b28 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -150,18 +150,18 @@
catalysts = list("phoron" = 1)
result_amount = 2
-/datum/chemical_reaction/tramadol
- name = "Tramadol"
- id = "tramadol"
- result = "tramadol"
- required_reagents = list("inaprovaline" = 1, "ethanol" = 1, "oxygen" = 1)
- result_amount = 3
-
/datum/chemical_reaction/paracetamol
name = "Paracetamol"
id = "paracetamol"
result = "paracetamol"
- required_reagents = list("tramadol" = 1, "sugar" = 1, "water" = 1)
+ required_reagents = list("inaprovaline" = 1, "nitrogen" = 1, "water" = 1)
+ result_amount = 2
+
+/datum/chemical_reaction/tramadol
+ name = "Tramadol"
+ id = "tramadol"
+ result = "tramadol"
+ required_reagents = list("paracetamol" = 1, "ethanol" = 1, "oxygen" = 1)
result_amount = 3
/datum/chemical_reaction/oxycodone
@@ -465,6 +465,13 @@
required_reagents = list("oxygen" = 1, "anti_toxin" = 1, "carbon" = 1)
result_amount = 3
+/datum/chemical_reaction/calciumcarbonate
+ name = "Calcium Carbonate"
+ id = "calciumcarbonate"
+ result = "calciumcarbonate"
+ required_reagents = list("oxygen" = 3, "calcium" = 1, "carbon" = 1)
+ result_amount = 2
+
/datum/chemical_reaction/soporific
name = "Soporific"
id = "stoxin"
diff --git a/code/modules/reagents/dispenser/cartridge_presets.dm b/code/modules/reagents/dispenser/cartridge_presets.dm
index 40181b81c4..9f7ddc071e 100644
--- a/code/modules/reagents/dispenser/cartridge_presets.dm
+++ b/code/modules/reagents/dispenser/cartridge_presets.dm
@@ -30,6 +30,7 @@
ethanol spawn_reagent = "ethanol"
sacid spawn_reagent = "sacid"
tungsten spawn_reagent = "tungsten"
+ calcium spawn_reagent = "calcium"
// Bar, alcoholic
beer spawn_reagent = "beer"
diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/dispenser/dispenser_presets.dm
index 08741412f1..d3aa3c0133 100644
--- a/code/modules/reagents/dispenser/dispenser_presets.dm
+++ b/code/modules/reagents/dispenser/dispenser_presets.dm
@@ -21,7 +21,8 @@
/obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/sugar,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium
)
/obj/machinery/chemical_dispenser/ert
@@ -111,7 +112,7 @@
/obj/item/weapon/reagent_containers/chem_disp_cartridge/tequila,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/vermouth,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/cognac,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/cider,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/cider,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/ale,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/mead
)
diff --git a/code/modules/reagents/dispenser/supply.dm b/code/modules/reagents/dispenser/supply.dm
index e6488d9d7e..228c5dfeef 100644
--- a/code/modules/reagents/dispenser/supply.dm
+++ b/code/modules/reagents/dispenser/supply.dm
@@ -192,6 +192,7 @@ SEC_PACK(radium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/radi
SEC_PACK(ethanol, /obj/item/weapon/reagent_containers/chem_disp_cartridge/ethanol, "Reagent refill - Ethanol", "ethanol reagent cartridge crate", 15, access_chemistry)
SEC_PACK(sacid, /obj/item/weapon/reagent_containers/chem_disp_cartridge/sacid, "Reagent refill - Sulfuric Acid", "sulfuric acid reagent cartridge crate", 15, access_chemistry)
SEC_PACK(tungsten, /obj/item/weapon/reagent_containers/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", 15, access_chemistry)
+SEC_PACK(calcium, /obj/item/weapon/reagent_containers/chem_disp_cartridge/calcium, "Reagent refill - Calcium", "calcium reagent cartridge crate", 15, access_chemistry)
// Bar-restricted (alcoholic drinks)
// Datum path Contents type Supply pack name Container name Cost Container access
diff --git a/code/modules/reagents/distilling/Distilling-Recipes.dm b/code/modules/reagents/distilling/Distilling-Recipes.dm
index f7fae18178..d610e32e9b 100644
--- a/code/modules/reagents/distilling/Distilling-Recipes.dm
+++ b/code/modules/reagents/distilling/Distilling-Recipes.dm
@@ -104,6 +104,28 @@
temp_range = list(T0C + 115, T0C + 130)
+/datum/chemical_reaction/distilling/spacomycaze
+ name = "Distilling Spacomycaze"
+ id = "distill_spacomycaze"
+ result = "spacomycaze"
+ required_reagents = list("paracetamol" = 1, "spaceacillin" = 1, "foaming_agent" = 1)
+ result_amount = 2
+
+ reaction_rate = HALF_LIFE(10)
+
+ temp_range = list(T0C + 100, T0C + 120)
+
+/datum/chemical_reaction/distilling/tricorlidaze
+ name = "Distilling Tricorlidaze"
+ id = "distill_tricorlidaze"
+ result = "tricorlidaze"
+ required_reagents = list("tricordrazine" = 1, "sterilizine" = 1, "foaming_agent" = 1)
+ result_amount = 2
+
+ reaction_rate = HALF_LIFE(10)
+
+ temp_range = list(T0C + 100, T0C + 120)
+
// Alcohol
/datum/chemical_reaction/distilling/beer
name = "Distilling Beer"
@@ -168,3 +190,27 @@
F.set_up(6, 0, T)
F.start()
return
+
+/datum/chemical_reaction/distilling/lichpowder
+ name = "Distilling Lichpowder"
+ id = "distill_lichpowder"
+ result = "lichpowder"
+ required_reagents = list("zombiepowder" = 2, "leporazine" = 1)
+ result_amount = 2
+
+ reaction_rate = HALF_LIFE(8)
+
+ temp_range = list(T0C + 100, T0C + 150)
+
+/datum/chemical_reaction/distilling/necroxadone
+ name = "Distilling Necroxadone"
+ id = "distill_necroxadone"
+ result = "necroxadone"
+ required_reagents = list("lichpowder" = 1, "cryoxadone" = 1, "carthatoline" = 1)
+ result_amount = 2
+
+ catalysts = list("phoron" = 5)
+
+ reaction_rate = HALF_LIFE(20)
+
+ temp_range = list(T0C + 90, T0C + 95)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 7087c30399..61c97a3ba7 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -132,6 +132,9 @@
update_name_label()
if(istype(W,/obj/item/weapon/storage/bag))
..()
+ if(W && W.w_class <= w_class && (flags & OPENCONTAINER))
+ to_chat(user, "You dip \the [W] into \the [src].")
+ reagents.touch_obj(W, reagents.total_volume)
/obj/item/weapon/reagent_containers/glass/proc/update_name_label()
if(label_text == "")
diff --git a/code/modules/research/designs/medical.dm b/code/modules/research/designs/medical.dm
index 9b516cf289..7fcc4ab1f6 100644
--- a/code/modules/research/designs/medical.dm
+++ b/code/modules/research/designs/medical.dm
@@ -43,6 +43,24 @@
build_path = /obj/item/weapon/surgical/scalpel/manager
sort_string = "KAAAD"
+/datum/design/item/medical/saw_manager
+ name = "Energetic Bone Diverter"
+ desc = "A strange development following the I.M.S., this heavy tool can split and open, or close and shut, intentional holes in bones."
+ id = "advanced_saw"
+ req_tech = list(TECH_BIO = 4, TECH_MATERIAL = 7, TECH_MAGNET = 6, TECH_DATA = 5)
+ materials = list (DEFAULT_WALL_MATERIAL = 12500, MAT_PLASTIC = 800, "silver" = 1500, "gold" = 1500, MAT_OSMIUM = 1000)
+ build_path = /obj/item/weapon/surgical/circular_saw/manager
+ sort_string = "KAAAE"
+
+/datum/design/item/medical/organ_ripper
+ name = "Organ Ripper"
+ desc = "A modern and horrifying take on an ancient practice, this tool is capable of rapidly removing an organ from a hopefully willing patient, without damaging it."
+ id = "organ_ripper"
+ req_tech = list(TECH_BIO = 3, TECH_MATERIAL = 5, TECH_MAGNET = 4, TECH_ILLEGAL = 3)
+ materials = list (DEFAULT_WALL_MATERIAL = 12500, MAT_PLASTIC = 8000, MAT_OSMIUM = 2500)
+ build_path = /obj/item/weapon/surgical/scalpel/ripper
+ sort_string = "KAAAF"
+
/datum/design/item/medical/bone_clamp
name = "Bone Clamp"
desc = "A miracle of modern science, this tool rapidly knits together bone, without the need for bone gel."
@@ -52,8 +70,6 @@
build_path = /obj/item/weapon/surgical/bone_clamp
sort_string = "KAABA"
-// Other medical equipment
-
/datum/design/item/medical/medical_analyzer
name = "health analyzer"
desc = "A hand-held body scanner able to distinguish vital signs of the subject."
diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm
index 199acd42fb..0fdd3df5be 100644
--- a/code/modules/research/mechfab_designs.dm
+++ b/code/modules/research/mechfab_designs.dm
@@ -570,6 +570,30 @@
materials = list(DEFAULT_WALL_MATERIAL = 8000, "gold" = 2000, "silver" = 3000, "phoron" = 5000, "glass" = 3750)
build_path = /obj/item/mecha_parts/mecha_equipment/combat_shield
+/datum/design/item/mecha/crisis_drone
+ name = "Crisis Drone"
+ desc = "Deploys a small medical drone capable of patching small wounds in order to stabilize nearby patients."
+ id = "mech_med_droid"
+ req_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_BIO = 5, TECH_DATA = 4, TECH_ARCANE = 1)
+ materials = list(DEFAULT_WALL_MATERIAL = 8000, MAT_GOLD = 2000, MAT_SILVER = 3000, MAT_VERDANTIUM = 2500, MAT_GLASS = 3000)
+ build_path = /obj/item/mecha_parts/mecha_equipment/crisis_drone
+
+/datum/design/item/mecha/rad_drone
+ name = "Hazmat Drone"
+ desc = "Deploys a small hazmat drone capable of purging minor radiation damage in order to stabilize nearby patients."
+ id = "mech_rad_droid"
+ req_tech = list(TECH_PHORON = 4, TECH_MAGNET = 5, TECH_BIO = 6, TECH_DATA = 4, TECH_ARCANE = 1)
+ materials = list(DEFAULT_WALL_MATERIAL = 8000, MAT_GOLD = 2000, MAT_URANIUM = 3000, MAT_VERDANTIUM = 2500, MAT_GLASS = 3000)
+ build_path = /obj/item/mecha_parts/mecha_equipment/crisis_drone/rad
+
+/datum/design/item/mecha/medanalyzer
+ name = "Mounted Body Scanner"
+ desc = "An advanced mech-mounted device that is not quite as powerful as a stationary body scanner, though still suitably powerful."
+ id = "mech_med_analyzer"
+ req_tech = list(TECH_PHORON = 4, TECH_MAGNET = 5, TECH_BIO = 5, TECH_DATA = 4)
+ materials = list(MAT_PLASTEEL = 4500, MAT_GOLD = 2000, MAT_URANIUM = 3000, MAT_GLASS = 3000)
+ build_path = /obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer
+
/datum/design/item/mecha/jetpack
name = "Ion Jetpack"
desc = "Using directed ion bursts and cunning solar wind reflection technique, this device enables controlled space flight."
diff --git a/code/modules/research/prosfab_designs.dm b/code/modules/research/prosfab_designs.dm
index 43399ce322..be5aa3760b 100644
--- a/code/modules/research/prosfab_designs.dm
+++ b/code/modules/research/prosfab_designs.dm
@@ -191,6 +191,21 @@
materials = list(DEFAULT_WALL_MATERIAL = 5625, "glass" = 1000)
// req_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
+/datum/design/item/prosfab/pros/internal/spleen
+ name = "Prosthetic Spleen"
+ id = "pros_spleen"
+ build_path = /obj/item/organ/internal/spleen
+ time = 15
+ materials = list(DEFAULT_WALL_MATERIAL = 3000, MAT_GLASS = 750)
+// req_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
+
+/datum/design/item/prosfab/pros/internal/larynx
+ name = "Prosthetic Larynx"
+ id = "pros_larynx"
+ build_path = /obj/item/organ/internal/voicebox
+ time = 15
+ materials = list(DEFAULT_WALL_MATERIAL = 2000, MAT_GLASS = 750, MAT_PLASTIC = 500)
+
//////////////////// Cyborg Parts ////////////////////
/datum/design/item/prosfab/cyborg
category = "Cyborg Parts"
diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm
index 3513691706..4e03024a01 100644
--- a/code/modules/surgery/encased.dm
+++ b/code/modules/surgery/encased.dm
@@ -134,7 +134,7 @@
if (!hasorgans(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
- return ..() && affected && affected.open == 3
+ return (..() && affected && affected.open == 3)
/datum/surgery_step/open_encased/close/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if (!hasorgans(target))
@@ -214,4 +214,94 @@
var/self_msg = "You applied \the [tool] to [target]'s [affected.encased]."
user.visible_message(msg, self_msg)
- affected.open = 2
\ No newline at end of file
+ affected.open = 2
+
+///////////////////////////////////////////////////////////////
+// Saw/Retractor/Gel Combi-open and close.
+///////////////////////////////////////////////////////////////
+/datum/surgery_step/open_encased/advancedsaw_open
+ allowed_tools = list(
+ /obj/item/weapon/surgical/circular_saw/manager = 100
+ )
+
+ priority = 3
+
+ min_duration = 60
+ max_duration = 90
+
+/datum/surgery_step/open_encased/advancedsaw_open/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ return ..() && affected && affected.open >= 2 && affected.open < 3
+
+/datum/surgery_step/open_encased/advancedsaw_open/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+
+ user.visible_message("[user] begins to open [target]'s [affected.encased] with \the [tool].", \
+ "You begin to open [target]'s [affected.encased] with \the [tool].")
+ target.custom_pain("Something hurts horribly in your [affected.name]!", 60)
+ ..()
+
+/datum/surgery_step/open_encased/advancedsaw_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+
+ user.visible_message("[user] has cut [target]'s [affected.encased] wide open with \the [tool].", \
+ "You have cut [target]'s [affected.encased] wide open with \the [tool].")
+ affected.open = 3
+
+/datum/surgery_step/open_encased/advancedsaw_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+
+ user.visible_message("[user]'s hand slips, searing [target]'s [affected.encased] with \the [tool]!" , \
+ "Your hand slips, searing [target]'s [affected.encased] with \the [tool]!" )
+
+ affected.createwound(CUT, 20)
+ affected.createwound(BURN, 15)
+ if(prob(affected.damage))
+ affected.fracture()
+
+
+/datum/surgery_step/open_encased/advancedsaw_mend
+ allowed_tools = list(
+ /obj/item/weapon/surgical/circular_saw/manager = 100
+ )
+
+ priority = 3
+
+ min_duration = 30
+ max_duration = 60
+
+/datum/surgery_step/open_encased/advancedsaw_mend/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ return (..() && affected && affected.open == 3)
+
+/datum/surgery_step/open_encased/advancedsaw_mend/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+
+ var/msg = "[user] starts sealing \the [target]'s [affected.encased] with \the [tool]."
+ var/self_msg = "You start sealing \the [target]'s [affected.encased] with \the [tool]."
+ user.visible_message(msg, self_msg)
+ target.custom_pain("Something hurts horribly in your [affected.name]!", 100)
+ ..()
+
+/datum/surgery_step/open_encased/advancedsaw_mend/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!hasorgans(target))
+ return
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+
+ var/msg = "[user] sealed \the [target]'s [affected.encased] with \the [tool]."
+ var/self_msg = "You sealed \the [target]'s [affected.encased] with \the [tool]."
+ user.visible_message(msg, self_msg)
+
+ affected.open = 2
diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm
index 2f2e1cb44a..8d261f7535 100644
--- a/code/modules/surgery/organs_internal.dm
+++ b/code/modules/surgery/organs_internal.dm
@@ -394,6 +394,65 @@
"Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!")
affected.createwound(BRUISE, 20)
+///////////////////////////////////////////////////////////////
+// Organ Ripping Surgery
+///////////////////////////////////////////////////////////////
+
+/datum/surgery_step/internal/rip_organ
+
+ allowed_tools = list(
+ /obj/item/weapon/surgical/scalpel/ripper = 100
+ )
+
+ priority = 3
+
+ blood_level = 3
+
+ min_duration = 60
+ max_duration = 80
+
+/datum/surgery_step/internal/rip_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ if (!..())
+ return 0
+
+ target.op_stage.current_organ = null
+
+ var/list/removable_organs = list()
+ for(var/organ in target.internal_organs_by_name)
+ var/obj/item/organ/internal/I = target.internal_organs_by_name[organ]
+ if(istype(I) && I.parent_organ == target_zone)
+ removable_organs |= organ
+
+ var/organ_to_remove = input(user, "Which organ do you want to remove?") as null|anything in removable_organs
+ if(!organ_to_remove)
+ return 0
+
+ target.op_stage.current_organ = organ_to_remove
+ return ..()
+
+/datum/surgery_step/internal/rip_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ user.visible_message("[user] starts ripping [target]'s [target.op_stage.current_organ] out with \the [tool].", \
+ "You start ripping [target]'s [target.op_stage.current_organ] out with \the [tool].")
+ target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!", 100)
+ ..()
+
+/datum/surgery_step/internal/rip_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
+ user.visible_message("[user] has ripped [target]'s [target.op_stage.current_organ] out with \the [tool].", \
+ "You have ripped [target]'s [target.op_stage.current_organ] out with \the [tool].")
+
+ // Extract the organ!
+ if(target.op_stage.current_organ)
+ var/obj/item/organ/O = target.internal_organs_by_name[target.op_stage.current_organ]
+ if(O && istype(O))
+ O.removed(user)
+ target.op_stage.current_organ = null
+
+/datum/surgery_step/internal/rip_organ/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, damaging [target]'s [affected.name] with \the [tool]!", \
+ "Your hand slips, damaging [target]'s [affected.name] with \the [tool]!")
+ affected.createwound(BRUISE, 20)
+
//////////////////////////////////////////////////////////////////
// HEART SURGERY //
//////////////////////////////////////////////////////////////////
diff --git a/html/changelogs/Mechoid - Medical Expansion.yml b/html/changelogs/Mechoid - Medical Expansion.yml
new file mode 100644
index 0000000000..5d9b3b6aed
--- /dev/null
+++ b/html/changelogs/Mechoid - Medical Expansion.yml
@@ -0,0 +1,59 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# 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: Mechoid
+
+# 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:
+ - rscadd: "Multiple new organs added. Humans and Skrell received spleens, all species expected to have a stomach and intestine organ have them."
+ - tweak: "Augment 'slots' organized."
+ - rscadd: "Multiple augments added, currently only available in the Traitor / Mercenary uplinks as easy-to-install implants."
+ - rscadd: "Anesthetic / Oxygen pumps added. A mobile stabilizer has been added. All three are available in Cargo."
+ - rscadd: "Medical MRE rations added to Cargo."
+ - tweak: "Roundstart implants now become invisible until being handled."
+ - rscadd: "Neural implant added to loadout, makes the brain of the user count as an assisted organ. Does not affect MMIs or their subtypes."
+ - rscadd: "Bioprinters now unlock more organs upon being upgraded, once they pass the anomalous tier, they unlock quite probably illegal organs."
+ - rscadd: "Three medical exosuit components have been added. Crisis and Hazmat response drones, and a mounted advanced medical analyzer."
+ - tweak: "Medical analyzers now detect on-skin reagents."
+ - rscadd: "Multiple new chemicals added, two used for upgrading bandage kits."
+ - rscadd: "Brute-based medical stacks can be upgraded."
+ - rscadd: "Crude brute kits can be made with cloth."
+ - tweak: "Stacks can now pass their colors onto objects produced by them. (Colored cloth, painted wood, etcetera.)"
+ - rscadd: "Two combined surgical tools added, for opening / closing ribcages and skulls, and removing organs respectively."
+ - rscadd: "Two dud implants added to the loadout. They do literally nothing but hurt you if you're EMP'd."
+ - experiment: "The larynx now controls the ability to speak. Damage to it will stop you from being able to speak anything but non-verbal languages."
+ - tweak: "Damage to the brain can now affect the pulse."
+ - tweak: "Only the critical blood level causes toxin damage, meaning individuals who die of standard oxygen loss from bloodloss can possibly be saved, but exsanguinated persons are unlikely."
+ - tweak: "Bioaugment.dm is now just augment.dm"
+ - tweak: "Robotic hearts do not have a pulse."
+ - tweak: "Brain damage can now cause loss of breath."
+ - tweak: "Paracetamol is now the precursor to tramadol."
+ - rscadd: "Calcium is now in the chemical vendor."
diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi
index 2f15024c6a..cba863ea47 100644
Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ
diff --git a/icons/obj/atmos.dmi b/icons/obj/atmos.dmi
index 4ea2e6a2ea..13f177d300 100644
Binary files a/icons/obj/atmos.dmi and b/icons/obj/atmos.dmi differ
diff --git a/icons/obj/food.dmi b/icons/obj/food.dmi
index de2f69b813..aef2ea318f 100644
Binary files a/icons/obj/food.dmi and b/icons/obj/food.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index e3de287a99..62df172136 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 5d28658eed..6f318cff60 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/icons/obj/trash.dmi b/icons/obj/trash.dmi
index 2fe1a91c98..e55d92293d 100644
Binary files a/icons/obj/trash.dmi and b/icons/obj/trash.dmi differ
diff --git a/polaris.dme b/polaris.dme
index c0abfb7133..1e3f6afd2b 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1008,9 +1008,11 @@
#include "code\game\objects\items\weapons\id cards\station_ids.dm"
#include "code\game\objects\items\weapons\id cards\syndicate_ids.dm"
#include "code\game\objects\items\weapons\implants\implant.dm"
+#include "code\game\objects\items\weapons\implants\implantaugment.dm"
#include "code\game\objects\items\weapons\implants\implantcase.dm"
#include "code\game\objects\items\weapons\implants\implantchair.dm"
#include "code\game\objects\items\weapons\implants\implantcircuits.dm"
+#include "code\game\objects\items\weapons\implants\implantdud.dm"
#include "code\game\objects\items\weapons\implants\implanter.dm"
#include "code\game\objects\items\weapons\implants\implantfreedom.dm"
#include "code\game\objects\items\weapons\implants\implantlanguage.dm"
@@ -2262,15 +2264,20 @@
#include "code\modules\organs\robolimbs.dm"
#include "code\modules\organs\wound.dm"
#include "code\modules\organs\internal\appendix.dm"
-#include "code\modules\organs\internal\bioaugment.dm"
+#include "code\modules\organs\internal\augment.dm"
#include "code\modules\organs\internal\brain.dm"
#include "code\modules\organs\internal\eyes.dm"
#include "code\modules\organs\internal\heart.dm"
+#include "code\modules\organs\internal\intestine.dm"
#include "code\modules\organs\internal\kidneys.dm"
#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\spleen.dm"
+#include "code\modules\organs\internal\stomach.dm"
#include "code\modules\organs\internal\voicebox.dm"
+#include "code\modules\organs\internal\augment\armmounted.dm"
+#include "code\modules\organs\internal\augment\bio.dm"
#include "code\modules\organs\subtypes\diona.dm"
#include "code\modules\organs\subtypes\indestructible.dm"
#include "code\modules\organs\subtypes\machine.dm"