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"