From cfada9bfe6bcb31b582ae0f1a6eb0a21e50378a4 Mon Sep 17 00:00:00 2001 From: Triff Date: Sun, 13 Oct 2024 17:34:18 +0400 Subject: [PATCH 01/32] transferorgans --- code/modules/{ => surgery}/organs/blood.dm | 0 code/modules/{ => surgery}/organs/external/flesh.dm | 0 code/modules/{ => surgery}/organs/external/ipc.dm | 0 code/modules/{ => surgery}/organs/external/nymph.dm | 0 code/modules/{ => surgery}/organs/external/plant.dm | 0 code/modules/{ => surgery}/organs/external/robotic.dm | 0 code/modules/{ => surgery}/organs/external/skeleton.dm | 0 code/modules/{ => surgery}/organs/external/stump.dm | 0 code/modules/{ => surgery}/organs/organ.dm | 0 code/modules/{ => surgery}/organs/organ_external.dm | 0 code/modules/{ => surgery}/organs/organ_internal.dm | 0 code/modules/{ => surgery}/organs/pain.dm | 0 code/modules/{ => surgery}/organs/wound.dm | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename code/modules/{ => surgery}/organs/blood.dm (100%) rename code/modules/{ => surgery}/organs/external/flesh.dm (100%) rename code/modules/{ => surgery}/organs/external/ipc.dm (100%) rename code/modules/{ => surgery}/organs/external/nymph.dm (100%) rename code/modules/{ => surgery}/organs/external/plant.dm (100%) rename code/modules/{ => surgery}/organs/external/robotic.dm (100%) rename code/modules/{ => surgery}/organs/external/skeleton.dm (100%) rename code/modules/{ => surgery}/organs/external/stump.dm (100%) rename code/modules/{ => surgery}/organs/organ.dm (100%) rename code/modules/{ => surgery}/organs/organ_external.dm (100%) rename code/modules/{ => surgery}/organs/organ_internal.dm (100%) rename code/modules/{ => surgery}/organs/pain.dm (100%) rename code/modules/{ => surgery}/organs/wound.dm (100%) diff --git a/code/modules/organs/blood.dm b/code/modules/surgery/organs/blood.dm similarity index 100% rename from code/modules/organs/blood.dm rename to code/modules/surgery/organs/blood.dm diff --git a/code/modules/organs/external/flesh.dm b/code/modules/surgery/organs/external/flesh.dm similarity index 100% rename from code/modules/organs/external/flesh.dm rename to code/modules/surgery/organs/external/flesh.dm diff --git a/code/modules/organs/external/ipc.dm b/code/modules/surgery/organs/external/ipc.dm similarity index 100% rename from code/modules/organs/external/ipc.dm rename to code/modules/surgery/organs/external/ipc.dm diff --git a/code/modules/organs/external/nymph.dm b/code/modules/surgery/organs/external/nymph.dm similarity index 100% rename from code/modules/organs/external/nymph.dm rename to code/modules/surgery/organs/external/nymph.dm diff --git a/code/modules/organs/external/plant.dm b/code/modules/surgery/organs/external/plant.dm similarity index 100% rename from code/modules/organs/external/plant.dm rename to code/modules/surgery/organs/external/plant.dm diff --git a/code/modules/organs/external/robotic.dm b/code/modules/surgery/organs/external/robotic.dm similarity index 100% rename from code/modules/organs/external/robotic.dm rename to code/modules/surgery/organs/external/robotic.dm diff --git a/code/modules/organs/external/skeleton.dm b/code/modules/surgery/organs/external/skeleton.dm similarity index 100% rename from code/modules/organs/external/skeleton.dm rename to code/modules/surgery/organs/external/skeleton.dm diff --git a/code/modules/organs/external/stump.dm b/code/modules/surgery/organs/external/stump.dm similarity index 100% rename from code/modules/organs/external/stump.dm rename to code/modules/surgery/organs/external/stump.dm diff --git a/code/modules/organs/organ.dm b/code/modules/surgery/organs/organ.dm similarity index 100% rename from code/modules/organs/organ.dm rename to code/modules/surgery/organs/organ.dm diff --git a/code/modules/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm similarity index 100% rename from code/modules/organs/organ_external.dm rename to code/modules/surgery/organs/organ_external.dm diff --git a/code/modules/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm similarity index 100% rename from code/modules/organs/organ_internal.dm rename to code/modules/surgery/organs/organ_internal.dm diff --git a/code/modules/organs/pain.dm b/code/modules/surgery/organs/pain.dm similarity index 100% rename from code/modules/organs/pain.dm rename to code/modules/surgery/organs/pain.dm diff --git a/code/modules/organs/wound.dm b/code/modules/surgery/organs/wound.dm similarity index 100% rename from code/modules/organs/wound.dm rename to code/modules/surgery/organs/wound.dm From 65506ff9eeacefc55c58239fdcd7dd09940e0fe1 Mon Sep 17 00:00:00 2001 From: Triff Date: Sun, 13 Oct 2024 21:07:21 +0400 Subject: [PATCH 02/32] organs and operations --- code/__DEFINES/mob.dm | 7 +- code/datums/spells/inflict_handler.dm | 2 +- code/defines/obj/weapon.dm | 2 +- code/game/dna/dna_modifier.dm | 2 +- .../abduction/machinery/experiment.dm | 2 +- .../modes_gameplays/cult/cult_items.dm | 3 +- code/game/machinery/adv_med.dm | 11 +- code/game/machinery/flasher.dm | 7 +- code/game/mecha/mech_fabricator.dm | 1 + code/game/objects/items.dm | 29 +- code/game/objects/items/stacks/nanopaste.dm | 2 +- .../items/weapons/grenades/flashbang.dm | 15 +- code/game/objects/items/weapons/tools.dm | 4 +- code/modules/client/character_menu/general.dm | 27 +- code/modules/client/preferences.dm | 4 +- .../clothing/spacesuits/rig/modules/ai.dm | 2 +- .../spacesuits/rig/modules/utility.dm | 2 +- code/modules/food/recipes_microwave.dm | 2 +- code/modules/food/recipes_oven.dm | 2 +- code/modules/mob/living/carbon/brain/MMI.dm | 6 +- .../mob/living/carbon/brain/brain_item.dm | 8 +- code/modules/mob/living/carbon/brain/death.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/living/carbon/human/death.dm | 4 + .../mob/living/carbon/human/examine.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 10 +- .../living/carbon/human/human_attackhand.dm | 2 +- .../mob/living/carbon/human/human_damage.dm | 14 +- .../mob/living/carbon/human/human_defense.dm | 4 +- .../mob/living/carbon/human/human_defines.dm | 3 + code/modules/mob/living/carbon/human/life.dm | 18 +- code/modules/mob/living/carbon/species.dm | 38 +- .../living/silicon/robot/drone/drone_items.dm | 4 +- code/modules/mob/mob_grab.dm | 9 +- code/modules/mob/mob_helpers.dm | 4 +- code/modules/power/cable.dm | 2 +- .../reagent_types/Chemistry-Drinks.dm | 8 + .../reagent_types/Chemistry-Medicine.dm | 12 +- code/modules/religion/aspect.dm | 2 +- .../designs/mechfabricator_designs.dm | 52 ++ code/modules/scrap/scrap.dm | 6 +- code/modules/surgery/appendix.dm | 4 +- code/modules/surgery/braincore.dm | 8 +- code/modules/surgery/eye.dm | 192 +++++++- code/modules/surgery/organs/blood.dm | 2 +- code/modules/surgery/organs/external/flesh.dm | 4 +- code/modules/surgery/organs/external/stump.dm | 2 +- code/modules/surgery/organs/organ.dm | 127 ++++- code/modules/surgery/organs/organ_external.dm | 25 +- code/modules/surgery/organs/organ_helpers.dm | 14 + code/modules/surgery/organs/organ_internal.dm | 452 +++++++++++++++--- code/modules/surgery/organs/pain.dm | 2 +- code/modules/surgery/organs_internal.dm | 132 +++++ code/modules/surgery/other.dm | 12 +- code/modules/surgery/ribcage.dm | 12 +- .../unarmed_combat/combos/disarming.dm | 3 +- code/modules/virus2/effect.dm | 2 +- icons/obj/special_organs/skrell.dmi | Bin 0 -> 1844 bytes icons/obj/special_organs/tajaran.dmi | Bin 0 -> 2162 bytes icons/obj/special_organs/unathi.dmi | Bin 0 -> 2119 bytes icons/obj/special_organs/vox.dmi | Bin 0 -> 1993 bytes icons/obj/surgery.dmi | Bin 11556 -> 21361 bytes maps/RandomZLevels/Academy.dmm | 2 +- maps/RandomZLevels/assistantChamber.dmm | 2 +- maps/RandomZLevels/blackmarketpackers.dmm | 2 +- maps/centcom/centcom.dmm | 2 +- taucetistation.dme | 29 +- 67 files changed, 1136 insertions(+), 232 deletions(-) create mode 100644 code/modules/surgery/organs/organ_helpers.dm create mode 100644 code/modules/surgery/organs_internal.dm create mode 100644 icons/obj/special_organs/skrell.dmi create mode 100644 icons/obj/special_organs/tajaran.dmi create mode 100644 icons/obj/special_organs/unathi.dmi create mode 100644 icons/obj/special_organs/vox.dmi diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 8b502f6c90a5..339523cd1f80 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -4,9 +4,10 @@ #define ORGAN_BLEEDING 4 #define ORGAN_BROKEN 8 #define ORGAN_SPLINTED 16 -#define ORGAN_DEAD 32 -#define ORGAN_MUTATED 64 -#define ORGAN_ARTERY_CUT 128 +#define ORGAN_ROBOT 32 +#define ORGAN_DEAD 64 +#define ORGAN_MUTATED 128 +#define ORGAN_ARTERY_CUT 256 #define DROPLIMB_EDGE 0 #define DROPLIMB_BLUNT 1 diff --git a/code/datums/spells/inflict_handler.dm b/code/datums/spells/inflict_handler.dm index 723954fd7b7d..bbb6fbb18768 100644 --- a/code/datums/spells/inflict_handler.dm +++ b/code/datums/spells/inflict_handler.dm @@ -27,7 +27,7 @@ if(ishuman(target) || ismonkey(target)) var/mob/living/carbon/C = target if(C.has_brain()) // Their brain is already taken out - var/obj/item/brain/B = new(C.loc) + var/obj/item/organ/internal/brain/B = new(C.loc) B.transfer_identity(C) target.gib() if("disintegrate") diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index ee190f3cfdb5..d03c0c1f8227 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -201,7 +201,7 @@ if(!H.shoes) var/obj/item/organ/external/BP = H.bodyparts_by_name[pick(BP_L_LEG , BP_R_LEG)] - if(BP.is_robotic()) + if(BP.is_robotic_part()) return BP.take_damage(5, 0) if(!H.species.flags[NO_PAIN]) diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 27f7e26e5482..0dd04fc02395 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -128,7 +128,7 @@ occupant = occupant_body = C break if(isbrain(M)) - var/obj/item/brain/B = M + var/obj/item/organ/internal/brain/B = M occupant = B.brainmob occupant_body = B break diff --git a/code/game/gamemodes/modes_gameplays/abduction/machinery/experiment.dm b/code/game/gamemodes/modes_gameplays/abduction/machinery/experiment.dm index 978035a12e18..f4620342d65e 100644 --- a/code/game/gamemodes/modes_gameplays/abduction/machinery/experiment.dm +++ b/code/game/gamemodes/modes_gameplays/abduction/machinery/experiment.dm @@ -58,7 +58,7 @@ if((BP.status & ORGAN_CUT_AWAY) || (BP.is_stump)) continue temp = new /icon(icobase, "[BP.body_zone]") - if(BP.is_robotic()) + if(BP.is_robotic_part()) temp.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0)) preview_icon.Blend(temp, ICON_OVERLAY) diff --git a/code/game/gamemodes/modes_gameplays/cult/cult_items.dm b/code/game/gamemodes/modes_gameplays/cult/cult_items.dm index 2d22a89ca7b3..58cf069262e1 100644 --- a/code/game/gamemodes/modes_gameplays/cult/cult_items.dm +++ b/code/game/gamemodes/modes_gameplays/cult/cult_items.dm @@ -87,7 +87,8 @@ if(ishuman(L)) var/mob/living/carbon/human/H = L var/obj/item/organ/internal/eyes/E = H.organs_by_name[O_EYES] - E.damage += rand(4, 8) + if(E) + E.damage += rand(4, 8) L.flash_eyes() L.drop_item() return FALSE diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 1f12571918a5..b1368b92b64e 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -239,7 +239,7 @@ var/list/organStatus = list() if(E.status & ORGAN_BROKEN) organStatus["broken"] = capitalize(E.broken_description) - if(E.is_robotic()) + if(E.is_robotic_part()) organStatus["robotic"] = TRUE if(E.status & ORGAN_SPLINTED) organStatus["splinted"] = TRUE @@ -279,8 +279,7 @@ organData["maxHealth"] = I.min_broken_damage organData["bruised"] = I.is_bruised() organData["broken"] = I.is_broken() - organData["assisted"] = I.robotic == 1 - organData["robotic"] = I.robotic == 2 + organData["cybernetic"] = I.is_robotic() organData["dead"] = (I.status & ORGAN_DEAD) intOrganData.Add(list(organData)) @@ -398,7 +397,7 @@ bled = "Кровотечение:" if(BP.status & ORGAN_BROKEN) AN = "[capitalize(BP.broken_description)]:" - if(BP.is_robotic()) + if(BP.is_robotic_part()) robot = "Протез:" if(BP.open) open = "Вскрытое:" @@ -434,9 +433,7 @@ var/mech = "Органическое:" var/organ_status = "" var/infection = "" - if(IO.robotic == 1) - mech = "Со вспомогательными средствами:" // sounds weird - if(IO.robotic == 2) + if(IO.is_robotic()) mech = "Механическое:" if(istype(IO, /obj/item/organ/internal/heart)) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 84126669a25c..42d50519cb93 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -93,9 +93,10 @@ if (ishuman(O)) var/mob/living/carbon/human/H = O var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] - if (IO.damage > IO.min_bruised_damage && prob(IO.damage + 50)) - H.flash_eyes() - IO.damage += rand(1, 5) + if(IO) + if (IO.damage > IO.min_bruised_damage && prob(IO.damage + 50)) + H.flash_eyes() + IO.damage += rand(1, 5) else if(!O.blinded && isliving(O)) var/mob/living/L = O diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 83bf90346fb9..c6a822de4bfb 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -48,6 +48,7 @@ "Cyborg Components", "Misc", "Stock Parts", + "Organs", ) required_skills = list(/datum/skill/research = SKILL_LEVEL_PRO) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index fc6b2b15f007..412eecd1060b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -860,21 +860,22 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] - IO.damage += rand(force * 0.5, force) - if(IO.damage >= IO.min_bruised_damage) - if(H.stat != DEAD) - if(IO.robotic <= 1) //robot eyes bleeding might be a bit silly - to_chat(H, "Your eyes start to bleed profusely!") - if(prob(10 * force)) + if(IO) + IO.damage += rand(force * 0.5, force) + if(IO.damage >= IO.min_bruised_damage) if(H.stat != DEAD) - to_chat(H, "You drop what you're holding and clutch at your eyes!") - H.drop_item() - H.adjustBlurriness(10) - H.Paralyse(1) - H.Weaken(4) - if (IO.damage >= IO.min_broken_damage) - if(H.stat != DEAD) - to_chat(H, "You go blind!") + if(!IO.is_robotic()) //robot eyes bleeding might be a bit silly + to_chat(H, "Your eyes start to bleed profusely!") + if(prob(10 * force)) + if(H.stat != DEAD) + to_chat(H, "You drop what you're holding and clutch at your eyes!") + H.drop_item() + H.adjustBlurriness(10) + H.Paralyse(1) + H.Weaken(4) + if (IO.damage >= IO.min_broken_damage) + if(H.stat != DEAD) + to_chat(H, "You go blind!") var/obj/item/organ/external/BP = H.bodyparts_by_name[BP_HEAD] BP.take_damage(force) else diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index c51a242c4f8c..b869cb91147c 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -31,7 +31,7 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/external/BP = H.get_bodypart(def_zone) - if(BP && BP.is_robotic()) + if(BP && BP.is_robotic_part()) if(can_operate(H)) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) if(IO.is_bruised()) diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 7e067e5e31d8..13669f4dd0db 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -108,13 +108,14 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] - if(IO.damage >= IO.min_bruised_damage) - to_chat(M, "Ваши глаза сильно щиплит!") - if(!banglet && !(istype(src , /obj/item/weapon/grenade/clusterbuster))) - if(IO.damage >= IO.min_broken_damage) - to_chat(M, "Вы ничего не видите!") - if(H.species.name == SHADOWLING) // BBQ from shadowling ~Zve - H.adjustFireLoss(rand(15, 25)) + if(IO) + if(IO.damage >= IO.min_bruised_damage) + to_chat(M, "Ваши глаза сильно щиплит!") + if(!banglet && !(istype(src , /obj/item/weapon/grenade/clusterbuster))) + if(IO.damage >= IO.min_broken_damage) + to_chat(M, "Вы ничего не видите!") + if(H.species.name == SHADOWLING) // BBQ from shadowling ~Zve + H.adjustFireLoss(rand(15, 25)) if(M.ear_damage >= 15) to_chat(M, "Вы чувствуете сильный звон в ушах!") if(!banglet && !(istype(src , /obj/item/weapon/grenade/clusterbuster))) diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 06b1442c69d9..62fd0c274915 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -438,6 +438,8 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] + if(!IO) + return if(H.species.flags[IS_SYNTHETIC]) return switch(safety) @@ -566,7 +568,7 @@ var/obj/item/organ/external/BP = H.get_bodypart(def_zone) if(!BP) return - if(!(BP.is_robotic()) || user.a_intent != INTENT_HELP) + if(!(BP.is_robotic_part()) || user.a_intent != INTENT_HELP) return ..() if(H.species.flags[IS_SYNTHETIC]) diff --git a/code/modules/client/character_menu/general.dm b/code/modules/client/character_menu/general.dm index fe457852f4e4..f757bffec3a7 100644 --- a/code/modules/client/character_menu/general.dm +++ b/code/modules/client/character_menu/general.dm @@ -82,15 +82,6 @@ else if(status == "mechanical") ++ind . += "
  • Mechanical [organ_name]
  • " - else if(status == "assisted") - ++ind - switch(organ_name) - if("heart") - . += "
  • Pacemaker-assisted [organ_name]
  • " - if("eyes") - . += "
  • Retinal overlayed [organ_name]
  • " - else - . += "
  • Mechanically assisted [organ_name]
  • " if(species == IPC) . += "
    Head: [ipc_head]" @@ -573,7 +564,7 @@ organ_data[limb] = "cyborg" if("Organs") - var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes", "lungs", "liver", "kidneys") if(!organ_name) return var/organ = null @@ -582,17 +573,21 @@ organ = O_HEART if("Eyes") organ = O_EYES - - var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") + if("lungs") + organ = O_LUNGS + if("liver") + organ = O_LIVER + if("kidneys") + organ = O_KIDNEYS + + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Cybernetic") if(!new_state) return switch(new_state) if("Normal") organ_data[organ] = null - if("Assisted") - organ_data[organ] = "assisted" - if("Mechanical") - organ_data[organ] = "mechanical" + if("Cybernetic") + organ_data[organ] = "Cybernetic" // Choosing a head for an IPC if("ipc_head") var/list/ipc_heads = list("Default", "Alien", "Double", "Pillar", "Human") diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index da3ada93aecb..07de4f3aeb24 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -497,9 +497,7 @@ var/global/list/datum/preferences/preferences_datums = list() var/obj/item/organ/external/new_BP = new type(null) new_BP.insert_organ(character) - else if(status == "assisted" && IO) - IO.mechassist() - else if(status == "mechanical" && IO) + else if(status == "Cybernetic" && IO) IO.mechanize() else diff --git a/code/modules/clothing/spacesuits/rig/modules/ai.dm b/code/modules/clothing/spacesuits/rig/modules/ai.dm index 7625147604dd..669422cc3e06 100644 --- a/code/modules/clothing/spacesuits/rig/modules/ai.dm +++ b/code/modules/clothing/spacesuits/rig/modules/ai.dm @@ -348,7 +348,7 @@ if(repairModule) for(var/obj/item/organ/external/BP in H.bodyparts) - if(BP.is_robotic() && (BP.brute_dam || BP.burn_dam)) + if(BP.is_robotic_part() && (BP.brute_dam || BP.burn_dam)) repairModule.activate() break diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index f4b98a02d771..ffa30a45c68f 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -506,7 +506,7 @@ var/obj/item/organ/external/DBP for(var/obj/item/organ/external/BP in H.bodyparts) - if(BP.is_robotic()) + if(BP.is_robotic_part()) if(BP.brute_dam) DBP = BP else if(BP.burn_dam) diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index bb9a2b98f361..2701cfedbcde 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -126,7 +126,7 @@ /datum/recipe/microwave/brainburger items = list( /obj/item/weapon/reagent_containers/food/snacks/bun, - /obj/item/brain + /obj/item/organ/internal/brain ) result = /obj/item/weapon/reagent_containers/food/snacks/brainburger diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm index b275d4424607..74a5967b43f3 100644 --- a/code/modules/food/recipes_oven.dm +++ b/code/modules/food/recipes_oven.dm @@ -385,7 +385,7 @@ /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/brain + /obj/item/organ/internal/brain ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cake/brain diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index af767d4c0da1..ebfec30b806d 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -15,8 +15,8 @@ var/mob/living/carbon/brain/brainmob = null//The current occupant. /obj/item/device/mmi/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/brain) && !brainmob) //Time to stick a brain in it --NEO - var/obj/item/brain/B = I + if(istype(I, /obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO + var/obj/item/organ/internal/brain/B = I if(!B.brainmob) to_chat(user, "You aren't sure where this brain came from, but you're pretty sure it's a useless brain.") return @@ -83,7 +83,7 @@ QDEL_NULL(brainmob) return - var/obj/item/brain/brain + var/obj/item/organ/internal/brain/brain if(user) to_chat(user, "You upend the MMI, spilling the brain onto the floor.") brain = new(get_turf(user)) diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm index 650faf91769c..f8e293b3bf99 100644 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ b/code/modules/mob/living/carbon/brain/brain_item.dm @@ -1,4 +1,4 @@ -/obj/item/brain +/obj/item/organ/internal/brain name = "brain" desc = "A piece of juicy meat found in a persons head." icon = 'icons/obj/surgery.dmi' @@ -13,14 +13,14 @@ var/mob/living/carbon/brain/brainmob = null -/obj/item/brain/atom_init() +/obj/item/organ/internal/brain/atom_init() . = ..() //Shifting the brain "mob" over to the brain object so it's easier to keep track of. --NEO //WASSSSSUUUPPPP /N spawn(5) brainmob?.client?.screen.len = null //clear the hud -/obj/item/brain/proc/transfer_identity(mob/living/carbon/H) +/obj/item/organ/internal/brain/proc/transfer_identity(mob/living/carbon/H) name = "[H]'s brain" brainmob = new(src) brainmob.name = H.real_name @@ -31,7 +31,7 @@ H.mind.transfer_to(brainmob) to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a brain.") -/obj/item/brain/examine(mob/user) // -- TLE +/obj/item/organ/internal/brain/examine(mob/user) // -- TLE ..() if(brainmob && brainmob.client)//if thar be a brain inside... the brain. to_chat(user, "You can feel the small spark of life still left in this one.") diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm index d2302a1b3614..be2a7dc6da51 100644 --- a/code/modules/mob/living/carbon/brain/death.dm +++ b/code/modules/mob/living/carbon/brain/death.dm @@ -17,5 +17,5 @@ ..() if(container && isMMI(container)) qdel(container)//Gets rid of the MMI if there is one - if(istype(old_loc, /obj/item/brain)) + if(istype(old_loc, /obj/item/organ/internal/brain)) qdel(old_loc)//Gets rid of the brain item diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 03a6c0b1b88a..a4841714807e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -635,7 +635,7 @@ if(HAS_TRAIT(M, TRAIT_WET_HANDS) && ishuman(src)) var/mob/living/carbon/human/H = src var/obj/item/organ/external/BP = H.get_bodypart(M.get_targetzone()) - if(BP && BP.is_robotic()) + if(BP && BP.is_robotic_part()) var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() sparks.set_up(3, 0, get_turf(H)) sparks.start() diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 952f8f3dc025..a741cb091b2f 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -8,6 +8,10 @@ flick(icon('icons/mob/mob.dmi', "gibbed-h"), animation) QDEL_IN(animation, 2 SECOND) + for(var/obj/item/organ/internal/IO in organs) + IO.remove(src) + IO.forceMove(get_turf(src)) + for(var/obj/item/organ/external/BP in bodyparts) // Only make the limb drop if it's not too damaged if(prob(100 - BP.get_damage())) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 70757149f710..8e0b2e3d55b6 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -320,7 +320,7 @@ applying_pressure = "[t_He] is applying pressure to [t_his] [BP.name].
    " else applying_pressure = "[BP.applied_pressure] is applying pressure to [t_his] [BP.name].
    " - if(BP.is_robotic()) + if(BP.is_robotic_part()) if(!(BP.brute_dam + BP.burn_dam)) if(!species.flags[IS_SYNTHETIC]) wound_flavor_text[BP_Name] = "[t_He] has a robot [BP.name]!\n" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0e8eb2d68c2f..c495bc17da5b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1241,11 +1241,17 @@ /mob/living/carbon/human/proc/is_lung_ruptured() var/obj/item/organ/internal/lungs/IO = organs_by_name[O_LUNGS] + if(!IO) + return + return IO.is_bruised() /mob/living/carbon/human/proc/rupture_lung() var/obj/item/organ/internal/lungs/IO = organs_by_name[O_LUNGS] + if(!IO) + return + if(!IO.is_bruised()) custom_pain("You feel a stabbing pain in your chest!", 1) IO.damage = IO.min_bruised_damage @@ -1332,7 +1338,7 @@ to_chat(src, msg) BP.take_damage(rand(1,3), 0, 0) - if(!BP.is_robotic()) //There is no blood in protheses. + if(!BP.is_robotic_part()) //There is no blood in protheses. if(!reagents.has_reagent("metatrombine")) // metatrombine just prevents bleeding, not toxication BP.status |= ORGAN_BLEEDING adjustToxLoss(rand(1,3)) @@ -1805,7 +1811,7 @@ else if(organ_check in list(O_LIVER, O_KIDNEYS)) BP = bodyparts_by_name[BP_GROIN] - if(BP && BP.is_robotic()) + if(BP && BP.is_robotic_part()) return FALSE return species.has_organ[organ_check] diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 9987e3703cc3..5981aea70cda 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -68,7 +68,7 @@ */ /mob/living/carbon/human/proc/apply_pressure(mob/living/user, target_zone) var/obj/item/organ/external/BP = get_bodypart(target_zone) - if(!BP || !(BP.status & ORGAN_BLEEDING) || BP.is_robotic()) + if(!BP || !(BP.status & ORGAN_BLEEDING) || BP.is_robotic_part()) return FALSE if(user.is_busy()) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index c5a9fb7d0854..e5b88d9cbb7e 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -8,7 +8,7 @@ var/total_burn = 0 var/total_brute = 0 for(var/obj/item/organ/external/BP in bodyparts) // hardcoded to streamline things a bit - if(BP.is_robotic() && !BP.vital) + if(BP.is_robotic_part() && !BP.vital) continue // *non-vital* robot limbs don't count towards shock and crit total_brute += BP.brute_dam total_burn += BP.burn_dam @@ -22,6 +22,14 @@ ChangeToHusk() return +/mob/living/carbon/human/proc/get_organ(zone) + if(!zone) + zone = BP_CHEST + if(zone in list(O_EYES, O_MOUTH)) + zone = BP_HEAD + + return bodyparts[zone] + // ============================================= /mob/living/carbon/human/getBrainLoss() @@ -64,7 +72,7 @@ /mob/living/carbon/human/getBruteLoss() var/amount = 0 for(var/obj/item/organ/external/BP in bodyparts) - if(BP.is_robotic() && !BP.vital) + if(BP.is_robotic_part() && !BP.vital) continue // robot limbs don't count towards shock and crit amount += BP.brute_dam return round(amount, 0.01) @@ -80,7 +88,7 @@ /mob/living/carbon/human/getFireLoss() var/amount = 0 for(var/obj/item/organ/external/BP in bodyparts) - if(BP.is_robotic() && !BP.vital) + if(BP.is_robotic_part() && !BP.vital) continue // robot limbs don't count towards shock and crit amount += BP.burn_dam return round(amount, 0.01) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 95d51e6135b2..2d16187ef8df 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -273,7 +273,7 @@ continue BP.emplode(severity) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.robotic == 0) + if(!IO.is_robotic()) continue IO.emplode(severity) ..() @@ -290,7 +290,7 @@ var/hit_area = BP.name if(istype(I,/obj/item/weapon/card/emag)) - if(!BP.is_robotic()) + if(!BP.is_robotic_part()) to_chat(user, "That limb isn't robotic.") return if(BP.sabotaged) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 8ffca43ee5d0..a44d4e9fc1a7 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -126,3 +126,6 @@ // Reagent allergies. var/list/allergies var/next_allergy_message = 0 + + //Same as above, but stores "slot ID" - "organ" pairs for easy access. + var/list/internal_organs_slot = list() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index cc31588d6b68..22533548d5a5 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -347,6 +347,18 @@ var/global/list/tourette_bad_words= list( failed_last_breath = inhale_alert + var/lungs = get_int_organ_by_name(O_LUNGS) + if(!lungs) + adjustOxyLoss(10) + if(prob(80)) + emote("gasp") + + //CRIT + if(!breath || (breath.total_moles == 0) || !lungs) + adjustOxyLoss(5) + inhale_alert = TRUE + return FALSE + if(breath) //spread some viruses while we are at it if (virus2.len > 0) @@ -1066,7 +1078,11 @@ var/global/list/tourette_bad_words= list( set_EyesVision(sightglassesmod) return FALSE - see_in_dark = species.darksight + var/obj/item/organ/internal/eyes/eyes = organs_by_name[O_EYES] + if(eyes) + see_in_dark = eyes.darksight + else + see_in_dark = species.darksight var/obj/item/clothing/glasses/G = glasses if(istype(G)) diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index c22432fb4678..f0664c55833c 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -406,6 +406,16 @@ ,IS_SOCIAL = TRUE ) + has_organ = list( + O_HEART = /obj/item/organ/internal/heart/unathi, + O_BRAIN = /obj/item/organ/internal/brain/unathi, + O_EYES = /obj/item/organ/internal/eyes/unathi, + O_LUNGS = /obj/item/organ/internal/lungs/unathi, + O_LIVER = /obj/item/organ/internal/liver/unathi, + O_KIDNEYS = /obj/item/organ/internal/kidneys/unathi + ) + + flesh_color = "#34af10" base_color = "#066000" @@ -481,6 +491,16 @@ ,FUR = TRUE ) + has_organ = list( + O_HEART = /obj/item/organ/internal/heart/tajaran, + O_BRAIN = /obj/item/organ/internal/brain/tajaran, + O_EYES = /obj/item/organ/internal/eyes/tajaran, + O_LUNGS = /obj/item/organ/internal/lungs/tajaran, + O_LIVER = /obj/item/organ/internal/liver/tajaran, + O_KIDNEYS = /obj/item/organ/internal/kidneys/tajaran + ) + + flesh_color = "#afa59e" base_color = "#333333" @@ -531,12 +551,12 @@ ) has_organ = list( - O_HEART = /obj/item/organ/internal/heart, - O_BRAIN = /obj/item/organ/internal/brain, - O_EYES = /obj/item/organ/internal/eyes, + O_HEART = /obj/item/organ/internal/heart/skrell, + O_BRAIN = /obj/item/organ/internal/brain/skrell, + O_EYES = /obj/item/organ/internal/eyes/skrell, O_LUNGS = /obj/item/organ/internal/lungs/skrell, - O_LIVER = /obj/item/organ/internal/liver, - O_KIDNEYS = /obj/item/organ/internal/kidneys + O_LIVER = /obj/item/organ/internal/liver/skrell, + O_KIDNEYS = /obj/item/organ/internal/kidneys/skrell ) eyes = "skrell_eyes" @@ -601,8 +621,8 @@ ) has_organ = list( O_HEART = /obj/item/organ/internal/heart/vox, - O_BRAIN = /obj/item/organ/internal/brain, - O_EYES = /obj/item/organ/internal/eyes, + O_BRAIN = /obj/item/organ/internal/brain/vox, + O_EYES = /obj/item/organ/internal/eyes/vox, O_LUNGS = /obj/item/organ/internal/lungs/vox, O_LIVER = /obj/item/organ/internal/liver/vox, O_KIDNEYS = /obj/item/organ/internal/kidneys/vox @@ -1931,7 +1951,7 @@ if(!isbodypart(I)) return var/obj/item/organ/external/BP = I - if(BP.is_robotic()) + if(BP.is_robotic_part()) return source.nutrition += max(0, NUTRITION_LEVEL_FULL - source.nutrition) qdel(I) @@ -1997,7 +2017,7 @@ if(!L || (L.is_stump)) return FALSE - if(L.is_robotic()) + if(L.is_robotic_part()) L.take_damage(rand(30,40), 0, 0) assailant.visible_message("You hear [H]'s [L.name] being pulled beyond its load limits!", \ "[H]'s [L.name] begins to tear apart!") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index b822a1882f0a..e0a0d8485504 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -181,7 +181,7 @@ /obj/item/stack/sheet/plasteel, /obj/item/weapon/circuitboard, /obj/item/device/mmi, - /obj/item/brain, + /obj/item/organ/internal/brain, /obj/item/device/mmi/posibrain, /obj/item/robot_parts, /obj/item/weapon/stock_parts, @@ -201,7 +201,7 @@ /obj/item/weapon/storage/pill_bottle, /obj/item/organ/internal, /obj/item/organ/external, - /obj/item/brain, + /obj/item/organ/internal/brain, /obj/item/robot_parts/l_arm, /obj/item/robot_parts/r_arm, /obj/item/robot_parts/l_leg, diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index f1c066eab2ee..b85f2c23220e 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -494,10 +494,11 @@ affecting.log_combat(assailant, "finger-pressed into the eyes") var/obj/item/organ/internal/eyes/IO = affecting:organs_by_name[O_EYES] - IO.damage += rand(3,4) - if (IO.damage >= IO.min_broken_damage) - if(affecting.stat != DEAD) - to_chat(affecting, "You go blind!") + if(IO) + IO.damage += rand(3,4) + if (IO.damage >= IO.min_broken_damage) + if(affecting.stat != DEAD) + to_chat(affecting, "You go blind!") else if(state >= GRAB_AGGRESSIVE && hit_zone == BP_CHEST) var/chance_to_force_vomit = 30 diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e8b6a2c0d522..03c9b8185d63 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -8,14 +8,14 @@ if(isnull(full_prosthetic)) robolimb_count = 0 for(var/obj/item/organ/external/BP in bodyparts) - if(BP.is_robotic()) + if(BP.is_robotic_part()) robolimb_count++ full_prosthetic = (robolimb_count == bodyparts.len) if(!full_prosthetic && target_zone) var/obj/item/organ/external/BP = get_bodypart(target_zone) if(BP) - return BP.is_robotic() + return BP.is_robotic_part() return full_prosthetic diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 1022ff9644e6..ecb7441244d8 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -463,7 +463,7 @@ By design, d1 is the smallest direction and d2 is the highest var/mob/living/carbon/human/H = M var/obj/item/organ/external/BP = H.get_bodypart(def_zone) - if(!BP.is_robotic() || user.a_intent != INTENT_HELP) + if(!BP.is_robotic_part() || user.a_intent != INTENT_HELP) return ..() if(H.species.flags[IS_SYNTHETIC]) diff --git a/code/modules/reagents/reagent_types/Chemistry-Drinks.dm b/code/modules/reagents/reagent_types/Chemistry-Drinks.dm index 67fb4737ac5e..0d081215951b 100644 --- a/code/modules/reagents/reagent_types/Chemistry-Drinks.dm +++ b/code/modules/reagents/reagent_types/Chemistry-Drinks.dm @@ -746,6 +746,14 @@ if(HAS_TRAIT(M, TRAIT_LIGHT_DRINKER)) drunkpwr *= 2 + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/liver/L = H.organs_by_name[O_LIVER] + if(!L) + drunkpwr *= 5 + else + drunkpwr *= L.alcohol_intensity + M.AdjustDrunkenness(drunkpwr) M.dizziness += dizzy_adj diff --git a/code/modules/reagents/reagent_types/Chemistry-Medicine.dm b/code/modules/reagents/reagent_types/Chemistry-Medicine.dm index e912208a51ad..a8ee94fd002a 100644 --- a/code/modules/reagents/reagent_types/Chemistry-Medicine.dm +++ b/code/modules/reagents/reagent_types/Chemistry-Medicine.dm @@ -265,7 +265,7 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/internal/lungs/IO = H.organs_by_name[O_LUNGS] if(istype(IO)) - if(IO.damage > 0 && IO.robotic < 2) + if(IO.damage > 0 && !IO.is_robotic()) IO.damage = max(IO.damage - 0.7, 0) switch(data["ticks"]) if(50 to 100) @@ -497,7 +497,7 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] if(istype(IO)) - if(IO.damage > 0 && IO.robotic < 2) + if(IO.damage > 0 && !IO.is_robotic()) IO.damage = max(IO.damage - 1, 0) /datum/reagent/aurisine @@ -533,13 +533,13 @@ var/damaged_organs = 0 //Peridaxon is hard enough to get, it's probably fair to make this all organs for(var/obj/item/organ/internal/IO in H.organs) - if(IO.damage > 0 && IO.robotic < 2) + if(IO.damage > 0 && !IO.is_robotic()) damaged_organs++ if(!damaged_organs) return for(var/obj/item/organ/internal/IO in H.organs) - if(IO.damage > 0 && IO.robotic < 2) + if(IO.damage > 0 && !IO.is_robotic()) IO.damage = max(IO.damage - (3 * custom_metabolism / damaged_organs), 0) /datum/reagent/kyphotorin @@ -847,9 +847,9 @@ for(var/obj/item/organ/external/E in M.bodyparts) if(E.is_artery_cut()) E.status &= ~ORGAN_ARTERY_CUT - if(IO.robotic == 1) + if(!IO.is_robotic()) if(prob(75)) data["ticks"]-- if(200 to INFINITY) - if(IO.robotic != 2) + if(!IO.is_robotic()) IO.heart_stop() diff --git a/code/modules/religion/aspect.dm b/code/modules/religion/aspect.dm index 731231e60452..ece5f75f105f 100644 --- a/code/modules/religion/aspect.dm +++ b/code/modules/religion/aspect.dm @@ -69,7 +69,7 @@ else if(isbodypart(I)) return 50 - else if(istype(I, /obj/item/brain)) + else if(istype(I, /obj/item/organ/internal/brain)) return 100 else if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/meat)) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index efe2a4cb5d10..58a1e55cc566 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -972,3 +972,55 @@ construction_time = 50 starts_unlocked = TRUE category = list("Misc") + +//Organ + +/datum/design/cybernetic_heart + name = "Cybernetic heart" + id = "cybernetic_heart" + build_type = MECHFAB + build_path = /obj/item/organ/internal/heart/cybernetic + materials = list(MAT_METAL=2000, MAT_GLASS=500) + construction_time = 50 + starts_unlocked = TRUE + category = list("Organs") + +/datum/design/cybernetic_lungs + name = "Cybernetic lungs" + id = "cybernetic_lungs" + build_type = MECHFAB + build_path = /obj/item/organ/internal/lungs/cybernetic + materials = list(MAT_METAL=2000, MAT_GLASS=500) + construction_time = 50 + starts_unlocked = TRUE + category = list("Organs") + +/datum/design/cybernetic_liver + name = "Cybernetic liver" + id = "cybernetic_liver" + build_type = MECHFAB + build_path = /obj/item/organ/internal/liver/cybernetic + materials = list(MAT_METAL=2000, MAT_GLASS=500) + construction_time = 50 + starts_unlocked = TRUE + category = list("Organs") + +/datum/design/cybernetic_kidneys + name = "Cybernetic kidneys" + id = "cybernetic_kidneys" + build_type = MECHFAB + build_path = /obj/item/organ/internal/kidneys/cybernetic + materials = list(MAT_METAL=2000, MAT_GLASS=500) + construction_time = 50 + starts_unlocked = TRUE + category = list("Organs") + +/datum/design/cybernetic_eyes + name = "Cybernetic eyes" + id = "cybernetic_eyes" + build_type = MECHFAB + build_path = /obj/item/organ/internal/eyes/cybernetic + materials = list(MAT_METAL=2000, MAT_GLASS=500) + construction_time = 50 + starts_unlocked = TRUE + category = list("Organs") diff --git a/code/modules/scrap/scrap.dm b/code/modules/scrap/scrap.dm index a83b0dee5f7c..2879a61a39a0 100644 --- a/code/modules/scrap/scrap.dm +++ b/code/modules/scrap/scrap.dm @@ -150,7 +150,7 @@ var/global/list/scrap_base_cache = list() return if((!H.shoes && !H.species.flags[NO_MINORCUTS]) && (!H.wear_suit || !(H.wear_suit.body_parts_covered & LEGS))) var/obj/item/organ/external/BP = H.bodyparts_by_name[pick(BP_L_LEG , BP_R_LEG)] - if(BP.is_robotic()) + if(BP.is_robotic_part()) return to_chat(M, "You step on the sharp debris!") H.Stun(1) @@ -214,7 +214,7 @@ var/global/list/scrap_base_cache = list() var/mob/living/carbon/human/victim = user var/obj/item/organ/external/BP = victim.bodyparts_by_name[pick(BP_L_ARM , BP_R_ARM)] var/obj/item/clothing/gloves/G = victim.gloves - if(!BP || BP.is_robotic() || victim.species.flags[NO_MINORCUTS]\ + if(!BP || BP.is_robotic_part() || victim.species.flags[NO_MINORCUTS]\ || victim.species.flags[IS_SYNTHETIC] || (victim.gloves && G.protect_fingers)) return FALSE else if(prob(50)) @@ -411,7 +411,7 @@ var/global/list/scrap_base_cache = list() /obj/random/syndie/fullhouse, /obj/item/weapon/reagent_containers/food/snacks/meat, /obj/item/weapon/reagent_containers/food/snacks/meat/corgi, - /obj/item/brain, + /obj/item/organ/internal/brain, /obj/item/weapon/tank/phoron ) diff --git a/code/modules/surgery/appendix.dm b/code/modules/surgery/appendix.dm index a51470271557..92c9ecd43688 100644 --- a/code/modules/surgery/appendix.dm +++ b/code/modules/surgery/appendix.dm @@ -2,7 +2,7 @@ ////////////////////////////////////////////////////////////////// // APPENDECTOMY // ////////////////////////////////////////////////////////////////// - +/* /datum/surgery_step/appendectomy priority = 2 can_infect = 1 @@ -49,3 +49,5 @@ user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!", \ "Your hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!") BP.take_damage(50, 0, DAM_SHARP|DAM_EDGE, tool) + +*/ diff --git a/code/modules/surgery/braincore.dm b/code/modules/surgery/braincore.dm index b6fbd4a41497..aa6faf3b1e68 100644 --- a/code/modules/surgery/braincore.dm +++ b/code/modules/surgery/braincore.dm @@ -105,7 +105,7 @@ target.log_combat(user, "debrained with [tool.name] (INTENT: [uppertext(user.a_intent)])") - var/obj/item/brain/B + var/obj/item/organ/internal/brain/B B = new(target.loc) B.transfer_identity(target) @@ -125,7 +125,7 @@ /datum/surgery_step/brain/insert_brain allowed_tools = list( - /obj/item/brain = 100 + /obj/item/organ/internal/brain = 100 ) allowed_species = list("exclude", IPC, DIONA) @@ -146,13 +146,13 @@ user.visible_message("[user] inserts [tool] into [target]'s [BP.name].", "You inserts [tool] into [target]'s [BP.name].") - if(!istype(tool, /obj/item/brain)) + if(!istype(tool, /obj/item/organ/internal/brain)) return //this might actually be outdated since barring badminnery, a debrain'd body will have any client sucked out to the brain's internal mob. Leaving it anyway to be safe. --NEO if(target.key)//Revised. /N target.ghostize() - var/obj/item/brain/B = tool + var/obj/item/organ/internal/brain/B = tool if(B.brainmob) if(B.brainmob.mind) B.brainmob.mind.transfer_to(target) diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index 992a38166566..091de04b90e0 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -28,6 +28,9 @@ min_duration = 90 max_duration = 110 +/datum/surgery_step/eye/cut_open/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target.op_stage.eyes == 0 + /datum/surgery_step/eye/cut_open/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] starts to separate the corneas on [target]'s eyes with \the [tool].", \ "You start to separate the corneas on [target]'s eyes with \the [tool].") @@ -99,9 +102,13 @@ ..() /datum/surgery_step/eye/mend_eyes/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/internal/eyes/eyes = target.organs_by_name[O_EYES] user.visible_message("[user] mends the nerves and lenses in [target]'s with \the [tool]." , \ "You mend the nerves and lenses in [target]'s with \the [tool].") - target.op_stage.eyes = 3 + + target.cure_nearsighted(list(EYE_DAMAGE_TRAIT, EYE_DAMAGE_TEMPORARY_TRAIT)) + target.sdisabilities &= ~BLIND + eyes.damage = 0 /datum/surgery_step/eye/mend_eyes/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/internal/eyes/IO = target.organs_by_name[O_EYES] @@ -127,13 +134,9 @@ "You are beginning to cauterize the incision around [target]'s eyes with \the [tool].") /datum/surgery_step/eye/cauterize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/internal/eyes/eyes = target.organs_by_name[O_EYES] user.visible_message("[user] cauterizes the incision around [target]'s eyes with \the [tool].", \ "You cauterize the incision around [target]'s eyes with \the [tool].") - if (target.op_stage.eyes == 3) - target.cure_nearsighted(list(EYE_DAMAGE_TRAIT, EYE_DAMAGE_TEMPORARY_TRAIT)) - target.sdisabilities &= ~BLIND - eyes.damage = 0 + target.op_stage.eyes = 0 /datum/surgery_step/eye/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -144,6 +147,183 @@ BP.take_damage(0, 5, used_weapon = tool) IO.take_damage(5, 0) +////////////////////////////////////////////////////////////////// +// EYE SURGERY manipulation // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/eye/manipulation + priority = 1 + allowed_species = null + var/obj/item/organ/internal/I = null + +/datum/surgery_step/eye/manipulation/place + allowed_tools = list(/obj/item/organ/internal = 100) + + min_duration = 110 + max_duration = 150 + + +/datum/surgery_step/eye/manipulation/place/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!ishuman(target)) + return FALSE + + + + var/obj/item/organ/internal/I = tool + if(I.requires_robotic_bodypart) + user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") + return FALSE + + if(target_zone != I.parent_bodypart || target.get_organ_slot(I.slot)) + user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") + return FALSE + + if(I.damage > (I.max_damage * 0.75)) + user.visible_message ( " \The [I] is in no state to be transplanted.") + return FALSE + + if(target.get_int_organ(I)) + user.visible_message ( " \The [target] already has [I].") + return FALSE + + return TRUE + + + +/datum/surgery_step/eye/manipulation/place/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts transplanting \the [tool] into [target]'s [parse_zone(target_zone)].", \ + "You start transplanting \the [tool] into [target]'s [parse_zone(target_zone)].") + ..() + +/datum/surgery_step/eye/manipulation/place/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] mends the nerves and lenses in [target]'s with \the [tool]." , \ + "You mend the nerves and lenses in [target]'s with \the [tool].") + + I = tool + user.drop_from_inventory(tool) + I.insert_organ(target) + user.visible_message(" [user] has transplanted \the [tool] into [target].", \ + " You have transplanted \the [tool] into [target].") + I.status &= ~ORGAN_CUT_AWAY + +/datum/surgery_step/eye/manipulation/place/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/internal/eyes/IO = target.organs_by_name[O_EYES] + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + user.visible_message("[user]'s hand slips, stabbing \the [tool] into [target]'s eye!", \ + "Your hand slips, stabbing \the [tool] into [target]'s eye!") + BP.take_damage(10, 0, DAM_SHARP|DAM_EDGE, tool) + if(IO) + IO.take_damage(5, 0) + +////////////////////////////////////////////////////////////////// +// EYE SURGERY manipulation for eyes // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/organ_manipulation/place_eye + priority = 2 + allowed_tools = list(/obj/item/organ/internal/eyes = 100) + + min_duration = 110 + max_duration = 150 + +/datum/surgery_step/organ_manipulation/place_eye/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!ishuman(target)) + return FALSE + + if(target_zone != O_EYES) + return FALSE + + + var/obj/item/organ/internal/I = tool + if(I.requires_robotic_bodypart) + user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") + return FALSE + + if(target.get_organ_slot(I.slot)) + user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") + return FALSE + + if(I.damage > (I.max_damage * 0.75)) + user.visible_message ( " \The [I] is in no state to be transplanted.") + return FALSE + + if(target.get_int_organ(I)) + user.visible_message ( " \The [target] already has [I].") + return FALSE + + return TRUE + + +/datum/surgery_step/organ_manipulation/place_eye/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts transplanting \the [tool] into [target]'s [parse_zone(target_zone)].", \ + "You start transplanting \the [tool] into [target]'s [parse_zone(target_zone)].") + + ..() + +/datum/surgery_step/organ_manipulation/place_eye/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + I = tool + user.drop_from_inventory(tool) + I.insert_organ(target) + user.visible_message(" [user] has transplanted \the [tool] into [target].", \ + " You have transplanted \the [tool] into [target].") + I.status &= ~ORGAN_CUT_AWAY + +/datum/surgery_step/organ_manipulation/place_eye/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/BP = target.get_bodypart(target_zone) + user.visible_message("[user]'s hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!", \ + "Your hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!") + BP.take_damage(20, 0, DAM_SHARP|DAM_EDGE, tool) + +/datum/surgery_step/eye/manipulation/remove + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/kitchenknife = 75, \ + /obj/item/weapon/shard = 50, \ + ) + + min_duration = 110 + max_duration = 150 + +/datum/surgery_step/eye/manipulation/remove/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + return ..() && target.op_stage.eyes == 2 + +/datum/surgery_step/eye/manipulation/remove/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + user.visible_message("[user] starts disconnect eyes inside the incision on [target]'s [BP.name] with \the [tool].", \ + "You start disconnect eyes inside the incision on [target]'s [BP.name] with \the [tool]" ) + target.custom_pain("The pain in your chest is living hell!",1) + ..() + +/datum/surgery_step/eye/manipulation/remove/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + if (BP.bodypart_organs.len) + var/list/embed_organs = list() + for(var/embed_organ in BP.bodypart_organs) + embed_organs += embed_organ + for(var/atom/embed_organ as anything in embed_organs) + embed_organs[embed_organ] = image(icon = embed_organ.icon, icon_state = embed_organ.icon_state) + var/choosen_organ = show_radial_menu(user, target, embed_organs, radius = 50, require_near = TRUE, tooltips = TRUE) + if(!choosen_organ) + user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ + "You could not find anything inside [target]'s [BP.name].") + return + var/obj/item/organ/internal/I = choosen_organ + I.status |= ORGAN_CUT_AWAY + I.remove(target) + I.loc = get_turf(target) + BP.bodypart_organs -= I + playsound(target, 'sound/effects/squelch1.ogg', VOL_EFFECTS_MASTER) + +/datum/surgery_step/eye/manipulation/remove/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/internal/eyes/IO = target.organs_by_name[O_EYES] + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + user.visible_message("[user]'s hand slips, stabbing \the [tool] into [target]'s eye!", \ + "Your hand slips, stabbing \the [tool] into [target]'s eye!") + BP.take_damage(10, 0, DAM_SHARP|DAM_EDGE, tool) + if(IO) + IO.take_damage(5, 0) + ////////////////////////////////////////////////////////////////// // ROBO EYE SURGERY // ////////////////////////////////////////////////////////////////// diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index d2461749e06a..c173b1da0112 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -179,7 +179,7 @@ var/global/const/BLOOD_VOLUME_SURVIVE = 122 var/blood_max = 0 var/list/do_spray = list() for(var/obj/item/organ/external/BP in bodyparts) - if(BP.is_robotic()) + if(BP.is_robotic_part()) continue var/open_wound diff --git a/code/modules/surgery/organs/external/flesh.dm b/code/modules/surgery/organs/external/flesh.dm index 222af999b0a3..351fea684b3b 100644 --- a/code/modules/surgery/organs/external/flesh.dm +++ b/code/modules/surgery/organs/external/flesh.dm @@ -481,12 +481,12 @@ Note that amputating the affected organ does in fact remove the infection from t //spread the infection to child and parent bodyparts if (BP.children) for (var/obj/item/organ/external/ChildBP in BP.children) - if (ChildBP.germ_level < BP.germ_level && !ChildBP.is_robotic()) + if (ChildBP.germ_level < BP.germ_level && !ChildBP.is_robotic_part()) if (ChildBP.germ_level < INFECTION_LEVEL_ONE * 2 || prob(30)) ChildBP.germ_level++ if (BP.parent) - if (BP.parent.germ_level < BP.germ_level && !BP.parent.is_robotic()) + if (BP.parent.germ_level < BP.germ_level && !BP.parent.is_robotic_part()) if (BP.parent.germ_level < INFECTION_LEVEL_ONE * 2 || prob(30)) BP.parent.germ_level++ diff --git a/code/modules/surgery/organs/external/stump.dm b/code/modules/surgery/organs/external/stump.dm index ec4d835b1887..7107e1b14b4b 100644 --- a/code/modules/surgery/organs/external/stump.dm +++ b/code/modules/surgery/organs/external/stump.dm @@ -9,7 +9,7 @@ return 0 /obj/item/organ/external/stump/proc/copy_original_limb(obj/item/organ/external/limb) - name = "[limb.is_robotic() ? "mechanical " : ""]stump of \a [limb.name]" + name = "[limb.is_robotic_part() ? "mechanical " : ""]stump of \a [limb.name]" cases = list( "культя [CASE(limb, GENITIVE_CASE)]", "культи [CASE(limb, GENITIVE_CASE)]", "культе [CASE(limb, GENITIVE_CASE)]", "культю [CASE(limb, GENITIVE_CASE)]", diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 3287ab2b39e6..50fcdad457ed 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -6,8 +6,11 @@ /obj/item/organ name = "organ" + icon = 'icons/obj/surgery.dmi' + item_state_world germ_level = 0 + var/organ_tag = O_HEART appearance_flags = TILE_BOUND | PIXEL_SCALE | KEEP_APART | APPEARANCE_UI_IGNORE_ALPHA // Strings. @@ -24,16 +27,89 @@ var/obj/item/organ/external/parent // Master-limb. // Damage vars. - var/min_broken_damage = 30 // Damage before becoming broken + var/damage = 0 // amount of damage to the organ + var/min_bruised_damage = 10 + var/min_broken_damage = 30 + var/max_damage + + var/dead_icon + + var/sterile = 0 //can the organ be infected by germs? + var/requires_robotic_bodypart = FALSE + var/slot = "heart" + // DO NOT add slots with matching names to different zones - it will break internal_organs_slot list! /obj/item/organ/Destroy() owner = null return ..() +/obj/item/organ/proc/remove(mob/living/user,special = 0) + if(!istype(owner)) + return + + owner.organs -= src + + loc = get_turf(owner) + STOP_PROCESSING(SSobj, src) + + if(owner && vital) // I'd do another check for species or whatever so that you couldn't "kill" an IPC by removing a human head from them, but it doesn't matter since they'll come right back from the dead + owner.death() + owner = null + /obj/item/organ/proc/set_owner(mob/living/carbon/human/H, datum/species/S) loc = null owner = H +/obj/item/organ/proc/die() + if(is_robotic()) + return + damage = max_damage + status |= ORGAN_DEAD + STOP_PROCESSING(SSobj, src) + if(owner && vital) + owner.death() + +/obj/item/organ/process() + + //dead already, no need for more processing + if(status & ORGAN_DEAD) + return + + if(is_preserved()) + return + + //Process infections + if ((is_robotic()) || (sterile) ||(owner && owner.species && (owner.species.flags & IS_PLANT))) + germ_level = 0 + return + + if(!owner) + if(reagents) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in reagents.reagent_list + if(B && prob(40)) + reagents.remove_reagent("blood",0.1) + blood_splatter(src,B,1) + // Maybe scale it down a bit, have it REALLY kick in once past the basic infection threshold + // Another mercy for surgeons preparing transplant organs + germ_level++ + if(germ_level >= INFECTION_LEVEL_ONE) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_TWO) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_THREE) + die() + + if(damage >= max_damage) + die() + + else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs + //** Handle antibiotics and curing infections + handle_antibiotics() + + //check if we've hit max_damage + if(damage >= max_damage) + die() + /obj/item/organ/proc/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) set_owner(H, S) @@ -42,8 +118,19 @@ if(parent_bodypart) parent = owner.bodyparts_by_name[parent_bodypart] -/obj/item/organ/process() - return 0 +/obj/item/organ/proc/replaced(mob/living/carbon/human/target, obj/item/organ/external/parent_bodypart) + + if(!istype(target)) return + + owner = target + STOP_PROCESSING(SSobj, src) + parent_bodypart.bodypart_organs |= src + if (!target.get_int_organ(src)) + target.organs_by_name += src + target.organs += src + src.loc = target + if(is_robotic()) + status |= ORGAN_ROBOT /obj/item/organ/proc/receive_chem(chemical) return 0 @@ -72,6 +159,20 @@ else return (istype(loc,/obj/structure/closet/secure_closet/freezer) || istype(loc,/obj/structure/closet/crate/freezer)) +/obj/item/organ/take_damage(amount, silent=0) + if(!isnum(silent)) + return // prevent basic take_damage usage (TODO remove workaround) + if(is_robotic()) + src.damage += (amount * 0.8) + else + src.damage += amount + + //only show this if the organ is not robotic + if(owner && parent_bodypart && amount > 0) + var/obj/item/organ/external/parent = owner.get_organ(parent_bodypart) + if(parent && !silent) + owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) + /obj/item/organ/examine(mob/user) . = ..(user) show_decay_status(user) @@ -131,6 +232,7 @@ //processing organs is pretty cheap, do that first. for(var/obj/item/organ/internal/IO in organs) IO.process() + IO.on_life() handle_stance() @@ -161,6 +263,18 @@ if (W.infection_check()) W.germ_level += 1 + +/obj/item/organ/proc/is_robotic() + if(status & ORGAN_ROBOT) + return TRUE + return FALSE + +/obj/item/organ/proc/mechanize() //Being used to make robutt hearts, etc + status &= ~ORGAN_BROKEN + status &= ~ORGAN_SPLINTED + status += ORGAN_ROBOT + + /mob/living/carbon/human/proc/handle_stance() // Don't need to process any of this if they aren't standing anyways // unless their stance is damaged, and we want to check if they should stay down @@ -226,3 +340,10 @@ break if(!has_arm) //need atleast one hand to crawl Stun(5) + +/obj/item/organ/proc/is_primary_organ(mob/living/carbon/human/O = null) + if (isnull(O)) + O = owner + if (!istype(owner)) // You're not the primary organ of ANYTHING, bucko + return 0 + return src == O.get_int_organ(organ_tag) diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index cdcd4d081cc4..f408bd0b15e2 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -16,7 +16,6 @@ var/brute_dam = 0 // Actual current brute damage. var/burn_dam = 0 // Actual current burn damage. var/last_dam = -1 // used in healing/processing calculations. - var/max_damage = 0 // Damage cap var/controller_type = /datum/bodypart_controller var/datum/bodypart_controller/controller @@ -74,6 +73,10 @@ if(parent) parent.children -= src parent = null + if(bodypart_organs) + for(var/obj/item/organ/internal/O in bodypart_organs) + bodypart_organs -= O + O.remove(owner,special = 1) QDEL_NULL(controller) if(owner) owner.bodyparts -= src @@ -318,20 +321,20 @@ Note that amputating the affected organ does in fact remove the infection from t switch(disintegrate) if(DROPLIMB_EDGE) if(!clean) - var/gore_sound = "[is_robotic() ? "tortured metal" : "ripping tendons and flesh"]" + var/gore_sound = "[is_robotic_part() ? "tortured metal" : "ripping tendons and flesh"]" owner.visible_message( "\The [owner]'s [name] flies off in an arc!", "Your [name] goes flying off!", "You hear a terrible sound of [gore_sound].") if(DROPLIMB_BURN) - var/gore = "[is_robotic() ? "": " of burning flesh"]" + var/gore = "[is_robotic_part() ? "": " of burning flesh"]" owner.visible_message( "\The [owner]'s [name] flashes away into ashes!", "Your [name] flashes away into ashes!", "You hear a crackling sound[gore].") if(DROPLIMB_BLUNT) - var/gore = "[is_robotic() ? "": " in shower of gore"]" - var/gore_sound = "[is_robotic() ? "rending sound of tortured metal" : "sickening splatter of gore"]" + var/gore = "[is_robotic_part() ? "": " in shower of gore"]" + var/gore_sound = "[is_robotic_part() ? "rending sound of tortured metal" : "sickening splatter of gore"]" owner.visible_message( "\The [owner]'s [name] explodes[gore]!", "Your [name] explodes[gore]!", @@ -362,7 +365,7 @@ Note that amputating the affected organ does in fact remove the infection from t if(bodypart) //Robotic limbs explode if sabotaged. - if(is_robotic() && !no_explode && sabotaged) + if(is_robotic_part() && !no_explode && sabotaged) explosion(get_turf(owner), 0, 0, 2, 3) var/datum/effect/effect/system/spark_spread/spark_system = new spark_system.set_up(5, 0, owner) @@ -388,7 +391,7 @@ Note that amputating the affected organ does in fact remove the infection from t should_delete = TRUE if(DROPLIMB_BLUNT) var/obj/effect/decal/cleanable/blood/gibs/gore - if(is_robotic()) + if(is_robotic_part()) gore = new /obj/effect/decal/cleanable/blood/gibs/robot(get_turf(owner)) else gore = new /obj/effect/decal/cleanable/blood/gibs(get_turf(owner)) @@ -620,7 +623,7 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/is_flesh() return controller.bodypart_type == BODYPART_ORGANIC -/obj/item/organ/external/proc/is_robotic() +/obj/item/organ/external/proc/is_robotic_part() return controller.bodypart_type == BODYPART_ROBOTIC /obj/item/organ/external/proc/is_usable() @@ -633,7 +636,7 @@ Note that amputating the affected organ does in fact remove the infection from t return (status & ORGAN_ARTERY_CUT) /obj/item/organ/external/proc/is_malfunctioning() - return (is_robotic() && prob(brute_dam + burn_dam)) + return (is_robotic_part() && prob(brute_dam + burn_dam)) //for arms and hands /obj/item/organ/external/proc/process_grasp(obj/item/c_hand, hand_name) @@ -908,7 +911,7 @@ Note that amputating the affected organ does in fact remove the infection from t var/obj/item/device/mmi/posibrain/B = new(loc) B.transfer_identity(brainmob) else - var/obj/item/brain/B = new(loc) + var/obj/item/organ/internal/brain/B = new(loc) B.transfer_identity(brainmob) brain_op_stage = 4.0 @@ -1113,7 +1116,7 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/get_wounds_desc() - if(is_robotic()) + if(is_robotic_part()) var/list/descriptors = list() if(brute_dam) switch(brute_dam) diff --git a/code/modules/surgery/organs/organ_helpers.dm b/code/modules/surgery/organs/organ_helpers.dm new file mode 100644 index 000000000000..f0ed01f31720 --- /dev/null +++ b/code/modules/surgery/organs/organ_helpers.dm @@ -0,0 +1,14 @@ +/mob/proc/get_int_organ(typepath) //int stands for internal + return + +/mob/proc/get_organ_slot(slot) //is it a brain, is it a brain_tumor? + return + +/mob/living/carbon/human/get_int_organ(typepath) + return (locate(typepath) in organs_by_name) + +/mob/living/carbon/human/get_organ_slot(slot) + return internal_organs_slot[slot] + +/mob/living/carbon/human/proc/get_int_organ_by_name(tag_to_check) + return organs_by_name[tag_to_check] diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 59a31a387079..d6516005e0a1 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -4,19 +4,15 @@ /obj/item/organ/internal parent_bodypart = BP_CHEST - // Strings. - var/organ_tag = null // Unique identifier. - - // Damage vars. - var/min_bruised_damage = 10 // Damage before considered bruised - var/damage = 0 // Amount of damage to the organ - // Will be moved, removed or refactored. var/process_accuracy = 0 // Damage multiplier for organs, that have damage values. - // 0 - normal - // 1 - assisted - // 2 - mechanical - var/robotic = 0 // For being a robot + + + +/obj/item/organ/internal/New(mob/living/carbon/holder) + if(istype(holder)) + insert_organ(holder) + ..() /obj/item/organ/internal/Destroy() if(parent) @@ -28,15 +24,47 @@ owner.organs_by_name -= organ_tag return ..() +/obj/item/organ/internal/remove(mob/living/carbon/human/M, special = 0) + owner = null + STOP_PROCESSING(SSobj, src) + if(M) + M.organs -= src + if(M.organs_by_name[organ_tag] == src) + M.organs_by_name -= organ_tag + if(M.internal_organs_slot[slot] == src) + M.internal_organs_slot.Remove(slot) + + if(vital && !special) + if(M.stat != DEAD)//safety check! + M.death() + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/parent = H.get_organ(check_zone(parent_bodypart)) + if(!istype(parent)) + return + else + parent.bodypart_organs -= src + + /obj/item/organ/internal/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) ..() + var/obj/item/organ/internal/replaced = H.get_organ_slot(slot) + if(replaced) + replaced.remove(H, special = 1) + + owner.organs += src owner.organs_by_name[organ_tag] = src + H.internal_organs_slot[slot] = src if(parent) parent.bodypart_organs += src +/obj/item/organ/internal/replaced(mob/living/carbon/human/target, obj/item/organ/external/affected) + insert_organ(target) + ..() /obj/item/organ/internal/proc/rejuvenate() damage = 0 @@ -47,11 +75,13 @@ /obj/item/organ/internal/proc/is_broken() return damage >= min_broken_damage +/obj/item/organ/internal/proc/on_life() + return /obj/item/organ/internal/process() //Process infections - if (robotic >= 2 || (owner.species && owner.species.flags[IS_PLANT])) //TODO make robotic organs and bodyparts separate types instead of a flag + if (is_robotic() || (owner.species && owner.species.flags[IS_PLANT])) //TODO make robotic organs and bodyparts separate types instead of a flag germ_level = 0 return @@ -79,51 +109,33 @@ if (prob(3)) //about once every 30 seconds take_damage(1,silent=prob(30)) -/obj/item/organ/internal/take_damage(amount, silent=0) - if(!isnum(silent)) - return // prevent basic take_damage usage (TODO remove workaround) - if(src.robotic == 2) - src.damage += (amount * 0.8) - else - src.damage += amount - - if (!silent) - owner.custom_pain("What a pain! My [name]!", 1) /obj/item/organ/internal/emp_act(severity) - switch(robotic) - if(0) - return + if(!is_robotic()) + return + + switch(severity) if(1) - switch (severity) - if (1.0) - take_damage(20,0) - return - if (2.0) - take_damage(7,0) - return - if(3.0) - take_damage(3,0) - return + take_damage(20, 1) if(2) - switch (severity) - if (1.0) - take_damage(40,0) - return - if (2.0) - take_damage(15,0) - return - if(3.0) - take_damage(10,0) - return - -/obj/item/organ/internal/proc/mechanize() //Being used to make robutt hearts, etc - robotic = 2 - -/obj/item/organ/internal/proc/mechassist() //Used to add things like pacemakers, etc - robotic = 1 - min_bruised_damage = 15 - min_broken_damage = 35 + take_damage(7, 1) + +/obj/item/organ/internal/mechanize() //Being used to make robutt hearts, etc + if(!is_robotic()) + var/list/states = icon_states('icons/obj/surgery.dmi') //Insensitive to specially-defined icon files for species like the Drask or whomever else. Everyone gets the same robotic heart. + if(slot == "heart" && ("[slot]-prosthetic-on" in states) && ("[slot]-prosthetic-off" in states)) //Give the robotic heart its robotic heart icons if they exist. + var/obj/item/organ/internal/heart/H = src + H.icon = icon('icons/obj/surgery.dmi') + H.icon_state = "[slot]-prosthetic" + H.dead_icon = "[slot]-prosthetic-off" + H.item_state_world = "[slot]-prosthetic_world" + H.update_icon() + else if("[slot]-prosthetic" in states) //Give the robotic organ its robotic organ icons if they exist. + icon = icon('icons/obj/surgery.dmi') + icon_state = "[slot]-prosthetic" + item_state_world = "[slot]-prosthetic_world" + name = "cybernetic [slot]" + ..() //Go apply all the organ flags/robotic statuses. /**************************************************** ORGANS DEFINES @@ -131,17 +143,33 @@ /obj/item/organ/internal/heart name = "heart" + icon = 'icons/obj/surgery.dmi' + icon_state = "heart-on" + item_state_world = "heart-on_world" cases = list("сердце", "сердца", "сердцу", "сердце", "сердцем", "сердце") organ_tag = O_HEART + vital = TRUE parent_bodypart = BP_CHEST var/heart_status = HEART_NORMAL var/fibrillation_timer_id = null var/failing_interval = 1 MINUTE + var/beating = 0 + +/obj/item/organ/internal/heart/update_icon() + if(beating) + icon_state = "heart-on" + item_state_world = "heart-on_world" + else + icon_state = "heart-off" + item_state_world = "heart-off_world" -/obj/item/organ/internal/heart/insert_organ() +/obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M, special = 0) ..() + beating = 1 + update_icon() owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) + /obj/item/organ/internal/heart/proc/heart_stop() if(!owner.reagents.has_reagent("inaprovaline") || owner.stat == DEAD) heart_status = HEART_FAILURE @@ -152,6 +180,12 @@ take_damage(1, 0) fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE) +/obj/item/organ/internal/heart/remove(mob/living/carbon/M, special = 0) + ..() + VARSET_IN(src, beating, 0, 100 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2 MINUTES) + + /obj/item/organ/internal/heart/proc/heart_fibrillate() heart_status = HEART_FIBR if(HAS_TRAIT(owner, TRAIT_FAT)) @@ -165,12 +199,41 @@ fibrillation_timer_id = null owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) +/obj/item/organ/internal/heart/cybernetic + name = "cybernetic heart" + desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." + icon_state = "heart-prosthetic" + item_state_world = "heart-prosthetic_world" + dead_icon = "heart-prosthetic-off" + status = ORGAN_ROBOT + +/obj/item/organ/internal/heart/cybernetic/update_icon() + if(beating) + icon_state = "heart-prosthetic" + item_state_world = "heart-prosthetic" + else + icon_state = "heart-prosthetic" + item_state_world = "heart-prosthetic" + /obj/item/organ/internal/heart/ipc name = "cooling pump" cases = list("помпа системы охлаждения", "помпы системы охлаждения", "помпе системы охлаждения", "помпу системы охлаждения", "помпой системы охлаждения", "помпой системы охлаждения") var/pumping_rate = 5 var/bruised_loss = 3 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/device.dmi' + icon_state = "miniaturesuitcooler0" + + +/obj/item/organ/internal/heart/ipc/update_icon() + if(beating) + icon_state = "miniaturesuitcooler0" + item_state_world = "miniaturesuitcooler0" + else + icon_state = "miniaturesuitcooler0" + item_state_world = "miniaturesuitcooler0" /obj/item/organ/internal/heart/ipc/process() if(owner.nutrition < 1) @@ -190,30 +253,76 @@ lungs.add_refrigerant(pumping_volume) /obj/item/organ/internal/heart/vox + name = "vox heart" + icon = 'icons/obj/special_organs/vox.dmi' parent_bodypart = BP_GROIN +/obj/item/organ/internal/heart/tajaran + name = "tajaran heart" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/heart/unathi + name = "unathi heart" + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A large looking heart." + +/obj/item/organ/internal/heart/skrell + name = "skrell heart" + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "A stream lined heart." + +/obj/item/organ/internal/heart/diona + name = "circulatory siphonostele" + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + /obj/item/organ/internal/lungs name = "lungs" cases = list("лёгкие", "лёгких", "лёгким", "лёгкие", "лёгкими", "лёгких") + icon_state = "lungs" + item_state_world = "lungs_world" organ_tag = O_LUNGS parent_bodypart = BP_CHEST - + slot = "lungs" var/has_gills = FALSE /obj/item/organ/internal/lungs/vox name = "air capillary sack" cases = list("воздушно-капиллярный мешок", "воздушно-капиллярного мешка", "воздушно-капиллярному мешку", "воздушно-капиллярный мешок", "воздушно-капиллярным мешком", "воздушно-капиллярном мешке") + desc = "They're filled with dust....wow." parent_bodypart = BP_GROIN + icon = 'icons/obj/special_organs/vox.dmi' + +/obj/item/organ/internal/lungs/tajaran + name = "tajaran lungs" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/lungs/unathi + name = "unathi lungs" + icon = 'icons/obj/special_organs/unathi.dmi' /obj/item/organ/internal/lungs/skrell name = "respiration sac" cases = list("дыхательная сумка", "дыхательной сумки", "дыхательной сумке", "дыхательную сумку", "дыхательной сумкой", "дыхательной сумке") has_gills = TRUE + icon = 'icons/obj/special_organs/skrell.dmi' /obj/item/organ/internal/lungs/diona name = "virga inopinatus" cases = list("полая ветка", "полой ветки", "полой ветки", "полую ветку", "полой веткой", "полой ветке") process_accuracy = 10 + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + +/obj/item/organ/internal/lungs/cybernetic + name = "cybernetic lungs" + desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement." + icon_state = "lungs-prosthetic" + item_state_world = "lungs-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT /obj/item/organ/internal/lungs/ipc name = "cooling element" @@ -223,6 +332,11 @@ var/refrigerant = 50 var/refrigerant_rate = 5 var/bruised_loss = 3 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/robot_component.dmi' + icon_state = "working" + item_state_world = "working" /obj/item/organ/internal/lungs/process() ..() @@ -273,22 +387,61 @@ /obj/item/organ/internal/liver name = "liver" cases = list("печень", "печени", "печени", "печень", "печенью", "печени") + icon_state = "liver" + item_state_world = "liver_world" organ_tag = O_LIVER - parent_bodypart = BP_CHEST + parent_bodypart = BP_GROIN + var/alcohol_intensity = 1 + slot = "liver" process_accuracy = 10 /obj/item/organ/internal/liver/diona name = "chlorophyll sac" cases = list("хлорофилловый мешок", "хлорофиллового мешка", "хлорофилловому мешку", "хлорофилловый мешок", "хлорофилловым мешком", "хлорофилловом мешке") + icon = 'icons/obj/objects.dmi' + icon_state = "podkid" + item_state_world = "podkid" + alcohol_intensity = 0.5 /obj/item/organ/internal/liver/vox name = "waste tract" cases = list("канал отходов", "канала отходов", "каналу отходов", "канал отходов", "каналом отходов", "канале отходов") + icon = 'icons/obj/special_organs/vox.dmi' + alcohol_intensity = 1.6 + +/obj/item/organ/internal/liver/tajaran + name = "tajaran liver" + icon = 'icons/obj/special_organs/tajaran.dmi' + alcohol_intensity = 1.4 + +/obj/item/organ/internal/liver/unathi + name = "unathi liver" + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A large looking liver." + alcohol_intensity = 0.8 + +/obj/item/organ/internal/liver/skrell + name = "skrell liver" + icon = 'icons/obj/special_organs/skrell.dmi' + alcohol_intensity = 0 + +/obj/item/organ/internal/liver/cybernetic + name = "cybernetic liver" + icon_state = "liver-prosthetic" + desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce." + item_state_world = "liver-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT /obj/item/organ/internal/liver/ipc name = "accumulator" cases = list("аккумулятор", "аккумулятора", "аккумулятору", "аккумулятор", "аккумулятором", "аккумуляторе") var/accumulator_warning = 0 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/power.dmi' + icon_state = "hpcell" + item_state_world = "hpcell" /obj/item/organ/internal/liver/ipc/set_owner(mob/living/carbon/human/H, datum/species/S) ..() @@ -392,24 +545,75 @@ /obj/item/organ/internal/kidneys name = "kidneys" cases = list("почки", "почек", "почкам", "почки", "почками", "почках") + icon_state = "kidneys" + item_state_world = "kidneys_world" organ_tag = O_KIDNEYS - parent_bodypart = BP_CHEST + parent_bodypart = BP_GROIN + slot = "kidneys" /obj/item/organ/internal/kidneys/vox name = "filtration bladder" cases = list("фильтрующий пузырь", "фильтрующего пузыря", "фильтрующему пузырю", "фильтрующий пузырь", "фильтрующим пузырём", "фильтрующем пузыре") + icon = 'icons/obj/special_organs/vox.dmi' + +/obj/item/organ/internal/kidneys/tajaran + name = "tajaran kidneys" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/kidneys/unathi + name = "unathi kidneys" + icon = 'icons/obj/special_organs/unathi.dmi' + +/obj/item/organ/internal/kidneys/skrell + name = "skrell kidneys" + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "The smallest kidneys you have ever seen, it probably doesn't even work." /obj/item/organ/internal/kidneys/diona name = "vacuole" cases = list("вакуоль", "вакуоли", "вакуолям", "вакуоль", "вакуолью", "вакуоли") parent_bodypart = BP_GROIN + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + +/obj/item/organ/internal/kidneys/cybernetic + name = "cybernetic kidneys" + icon_state = "kidneys-prosthetic" + desc = "An electronic device designed to mimic the functions of human kidneys. It has no benefits over a pair of organic kidneys, but is easy to produce." + item_state_world = "kidneys-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT /obj/item/organ/internal/kidneys/ipc name = "self-diagnosis unit" cases = list("устройство самодиагностики", "устройства самодиагностики", "устройству самодиагностики", "устройство самодиагностики", "устройством самодиагностики", "устройстве самодиагностики") parent_bodypart = BP_GROIN - + status = ORGAN_ROBOT var/next_warning = 0 + requires_robotic_bodypart = TRUE + + icon = 'icons/obj/robot_component.dmi' + icon_state = "analyser" + item_state_world = "analyser" + +/obj/item/organ/internal/kidneys/process() + + ..() + + if(!owner) + return + + // Coffee is really bad for you with busted kidneys. + // This should probably be expanded in some way, but fucked if I know + // what else kidneys can process in our reagent list. + var/datum/reagent/coffee = locate(/datum/reagent/consumable/drink/coffee) in owner.reagents.reagent_list + if(coffee) + if(is_bruised()) + owner.adjustToxLoss(0.1 * process_accuracy) + else if(is_broken()) + owner.adjustToxLoss(0.3 * process_accuracy) + /obj/item/organ/internal/kidneys/ipc/process() if(owner.nutrition < 1) @@ -435,17 +639,79 @@ name = "brain" cases = list("мозг", "мозга", "мозгу", "мозг", "мозгом", "мозге") organ_tag = O_BRAIN - parent_bodypart = BP_HEAD + vital = TRUE + parent_bodypart = O_BRAIN + slot = "brain" + icon_state = "brain2" + item_state_world = "brain2_world" /obj/item/organ/internal/brain/diona name = "main node nymph" cases = list("главная нимфа", "главной нимфы", "главной нимфе", "главную нимфу", "главной нимфой", "главной нимфе") parent_bodypart = BP_CHEST + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + +/obj/item/organ/internal/brain/tajaran + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/brain/unathi + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A smallish looking brain." + +/obj/item/organ/internal/brain/vox + name = "cortical-stack" + desc = "A peculiarly advanced bio-electronic device that seems to hold the memories and identity of a Vox." + icon = 'icons/obj/special_organs/vox.dmi' + icon_state = "cortical-stack" + item_state_world = "cortical-stack_world" + +/obj/item/organ/internal/brain/skrell + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "A brain with a odd division in the middle." + +/obj/item/organ/internal/brain/remove(mob/living/user,special = 0) + + if(!owner) return ..() // Probably a redundant removal; just bail + var/obj/item/organ/internal/brain/B = src + if(!special) + var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() + + if(borer) + borer.detatch() //Should remove borer if the brain is removed - RR + + B.transfer_identity(user) + + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + H.update_hair(1) + ..() /obj/item/organ/internal/brain/ipc name = "positronic brain" cases = list("позитронный мозг", "позитронного мозга", "позитронному мозгу", "позитронный мозг", "позитронным мозгом", "позитронном мозге") parent_bodypart = BP_CHEST + requires_robotic_bodypart = TRUE + icon = 'icons/obj/assemblies.dmi' + icon_state = "posibrain-occupied" + item_state_world = "posibrain-occupied" + var/obj/item/device/mmi/posibrain/stored_mmi + + +/obj/item/organ/internal/brain/ipc/remove(mob/living/carbon/human/M, special = 0) + if(!special) + var/brain_type = /obj/item/device/mmi/posibrain + + var/obj/item/organ/external/BP = owner.get_bodypart(parent_bodypart) + if(istype(BP, /obj/item/organ/external/chest/robot/ipc)) + var/obj/item/organ/external/chest/robot/ipc/I = BP + brain_type = I.posibrain_type + + + var/obj/item/device/mmi/P = new brain_type(owner.loc) + P.transfer_identity(owner) + /obj/item/organ/internal/brain/abomination name = "deformed brain" @@ -454,14 +720,80 @@ /obj/item/organ/internal/eyes name = "eyes" + icon_state = "eyes" + item_state_world = "eyes_world" cases = list("глаза", "глаз", "глазам", "глаза", "глазами", "глазах") organ_tag = O_EYES parent_bodypart = BP_HEAD + slot = "eyes" + var/list/eye_colour = list(0,0,0) + var/darksight = 2 + +/obj/item/organ/internal/eyes/proc/update_colour() + if(!owner) + return + eye_colour = list( + owner.r_eyes ? owner.r_eyes : 0, + owner.g_eyes ? owner.g_eyes : 0, + owner.b_eyes ? owner.b_eyes : 0 + ) + +/obj/item/organ/internal/eyes/insert_organ(mob/living/carbon/human/M, special = 0) +// Apply our eye colour to the target. + if(istype(M) && eye_colour) + var/mob/living/carbon/human/eyes = M + eyes.r_eyes = eye_colour[1] + eyes.g_eyes = eye_colour[2] + eyes.b_eyes = eye_colour[3] + eyes.update_eyes() + ..() + +/mob/living/carbon/human/proc/update_eyes() + var/obj/item/organ/internal/eyes/eyes = get_int_organ(/obj/item/organ/internal/eyes) + if(eyes) + eyes.update_colour() + regenerate_icons() + +/obj/item/organ/internal/eyes/tajaran + name = "tajaran eyeballs" + icon = 'icons/obj/special_organs/tajaran.dmi' + darksight = 8 + +/obj/item/organ/internal/eyes/unathi + name = "unathi eyeballs" + icon = 'icons/obj/special_organs/unathi.dmi' + darksight = 3 + +/obj/item/organ/internal/eyes/vox + name = "vox eyeballs" + icon = 'icons/obj/special_organs/vox.dmi' + +/obj/item/organ/internal/eyes/skrell + name = "skrell eyeballs" + icon = 'icons/obj/special_organs/skrell.dmi' + +/obj/item/organ/internal/eyes/diona + name = "nutrient sac" + icon = 'icons/obj/objects.dmi' + icon_state = "podkid" + item_state_world = "podkid" + +/obj/item/organ/internal/eyes/cybernetic + name = "cybernetic eyes" + icon_state = "eyes-prosthetic" + desc = "An electronic device designed to mimic the functions of a pair of human eyes. It has no benefits over organic eyes, but is easy to produce." + item_state_world = "eyes-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT /obj/item/organ/internal/eyes/ipc name = "cameras" cases = list("камеры", "камер", "камерам", "камеры", "камерами", "камерах") - robotic = 2 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/robot_component.dmi' + icon_state = "camera" + item_state_world = "camera" /obj/item/organ/internal/eyes/process() //Eye damage replaces the old eye_stat var. ..() diff --git a/code/modules/surgery/organs/pain.dm b/code/modules/surgery/organs/pain.dm index bac59de50bd0..76b51a375bb5 100644 --- a/code/modules/surgery/organs/pain.dm +++ b/code/modules/surgery/organs/pain.dm @@ -71,7 +71,7 @@ var/maxdam = 0 var/obj/item/organ/external/damaged_organ = null for(var/obj/item/organ/external/BP in bodyparts) - if(BP.status & ORGAN_DEAD || BP.is_robotic()) + if(BP.status & ORGAN_DEAD || BP.is_robotic_part()) continue var/dam = BP.get_damage() // make the choice of the organ depend on damage, diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm new file mode 100644 index 000000000000..f84e3ee744b6 --- /dev/null +++ b/code/modules/surgery/organs_internal.dm @@ -0,0 +1,132 @@ + + +////////////////////////////////////////////////////////////////// +// ORGANS SURGERY // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/organ_manipulation + priority = 1 + allowed_species = null + var/obj/item/organ/internal/I = null + +/datum/surgery_step/organ_manipulation/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!ishuman(target)) + return 0 + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + + if(target_zone in list(O_EYES , O_MOUTH, BP_HEAD)) + return 0 + + return BP && BP.open >= 2 && !(BP.status & ORGAN_BLEEDING) && (target_zone != BP_CHEST || target.op_stage.ribcage == 2) + +/datum/surgery_step/organ_manipulation/place + priority = 0 + allowed_tools = list(/obj/item/organ/internal = 100) + + min_duration = 50 + max_duration = 50 + +/datum/surgery_step/organ_manipulation/place/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(!ishuman(target)) + return FALSE + + if(target_zone in list(O_EYES , O_MOUTH, BP_HEAD)) + return FALSE + + + + var/obj/item/organ/internal/I = tool + if(I.requires_robotic_bodypart) + user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") + return FALSE + + if(target_zone != I.parent_bodypart || target.get_organ_slot(I.slot)) + user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") + return FALSE + + if(I.damage > (I.max_damage * 0.75)) + user.visible_message ( " \The [I] is in no state to be transplanted.") + return FALSE + + if(target.get_int_organ(I)) + user.visible_message ( " \The [target] already has [I].") + return FALSE + + return TRUE + + +/datum/surgery_step/organ_manipulation/place/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts transplanting \the [tool] into [target]'s [parse_zone(target_zone)].", \ + "You start transplanting \the [tool] into [target]'s [parse_zone(target_zone)].") + + ..() + +/datum/surgery_step/organ_manipulation/place/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + I = tool + user.drop_from_inventory(tool) + I.insert_organ(target) + user.visible_message(" [user] has transplanted \the [tool] into [target].", \ + " You have transplanted \the [tool] into [target].") + I.status &= ~ORGAN_CUT_AWAY + +/datum/surgery_step/organ_manipulation/place/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/BP = target.get_bodypart(target_zone) + user.visible_message("[user]'s hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!", \ + "Your hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!") + BP.take_damage(20, 0, DAM_SHARP|DAM_EDGE, tool) + + +/datum/surgery_step/organ_manipulation/remove + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/kitchenknife = 75, \ + /obj/item/weapon/shard = 50, \ + ) + + min_duration = 110 + max_duration = 150 + +/datum/surgery_step/organ_manipulation/remove/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + if(BP.stage == 3) + return FALSE + + return BP && ((BP.open == 3 && BP.body_zone == BP_CHEST) || (BP.open == 2)) + +/datum/surgery_step/organ_manipulation/remove/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + user.visible_message("[user] starts poking around inside the incision on [target]'s [BP.name] with \the [tool].", \ + "You start poking around inside the incision on [target]'s [BP.name] with \the [tool]" ) + target.custom_pain("The pain in your chest is living hell!",1) + ..() + +/datum/surgery_step/organ_manipulation/remove/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/BP = target.get_bodypart(target_zone) + if (BP.bodypart_organs.len) + var/list/embed_organs = list() + for(var/embed_organ in BP.bodypart_organs) + embed_organs += embed_organ + for(var/atom/embed_organ as anything in embed_organs) + embed_organs[embed_organ] = image(icon = embed_organ.icon, icon_state = embed_organ.icon_state) + var/choosen_organ = show_radial_menu(user, target, embed_organs, radius = 50, require_near = TRUE, tooltips = TRUE) + if(!choosen_organ) + user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ + "You could not find anything inside [target]'s [BP.name].") + return + var/obj/item/organ/internal/I = choosen_organ + I.status |= ORGAN_CUT_AWAY + I.remove(target) + I.loc = get_turf(target) + BP.bodypart_organs -= I + playsound(target, 'sound/effects/squelch1.ogg', VOL_EFFECTS_MASTER) + + else + user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ + "You could not find anything inside [target]'s [BP.name]." ) + +/datum/surgery_step/organ_manipulation/remove/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/BP = target.get_bodypart(target_zone) + user.visible_message("[user]'s hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!", \ + "Your hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!") + BP.take_damage(20, 0, DAM_SHARP|DAM_EDGE, tool) diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index 93b013c982fa..f3a57b7beef3 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -102,7 +102,7 @@ var/obj/item/organ/external/groin/BP = target.get_bodypart(BP_GROIN) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) if(IO && IO.damage > 0) - if(IO.robotic < 2) + if(!IO.is_robotic()) user.visible_message("[user] starts treating damage to [target]'s [IO.name] with [tool_name].", "You start treating damage to [target]'s [IO.name] with [tool_name]." ) else @@ -127,7 +127,7 @@ var/obj/item/organ/external/groin/BP = target.get_bodypart(BP_GROIN) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) if(IO && IO.damage > 0) - if(IO.robotic < 2) + if(!IO.is_robotic()) user.visible_message("[user] treats damage to [target]'s [IO.name] with [tool_name].", "You treat damage to [target]'s [IO.name] with [tool_name]." ) IO.damage = 0 @@ -175,7 +175,7 @@ var/is_groin_organ_damaged = FALSE var/obj/item/organ/external/groin/BP = target.get_bodypart(BP_GROIN) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) is_groin_organ_damaged = TRUE break return is_groin_organ_damaged @@ -183,7 +183,7 @@ /datum/surgery_step/groin_organs/fixing_robot/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/groin/BP = target.get_bodypart(BP_GROIN) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) user.visible_message("[user] starts mending the mechanisms on [target]'s [IO] with \the [tool].", "You start mending the mechanisms on [target]'s [IO] with \the [tool]." ) continue @@ -196,7 +196,7 @@ /datum/surgery_step/groin_organs/fixing_robot/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/groin/BP = target.get_bodypart(BP_GROIN) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) user.visible_message("[user] repairs [target]'s [IO] with \the [tool].", "You repair [target]'s [IO] with \the [tool]." ) IO.damage = 0 @@ -214,5 +214,5 @@ var/dam_amt = 2 for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) IO.take_damage(dam_amt,0) diff --git a/code/modules/surgery/ribcage.dm b/code/modules/surgery/ribcage.dm index b5deada4671a..c30e6a77f251 100644 --- a/code/modules/surgery/ribcage.dm +++ b/code/modules/surgery/ribcage.dm @@ -227,7 +227,7 @@ var/obj/item/organ/external/chest/BP = target.get_bodypart(BP_CHEST) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) if(IO && IO.damage > 0) - if(IO.robotic < 2) + if(!IO.is_robotic()) user.visible_message("[user] starts treating damage to [target]'s [IO.name] with [tool_name].", \ "You start treating damage to [target]'s [IO.name] with [tool_name]." ) else @@ -249,7 +249,7 @@ var/obj/item/organ/external/chest/BP = target.get_bodypart(BP_CHEST) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) if(IO && IO.damage > 0) - if(IO.robotic < 2) + if(!IO.is_robotic()) user.visible_message("[user] treats damage to [target]'s [IO.name] with [tool_name].", \ "You treat damage to [target]'s [IO.name] with [tool_name]." ) IO.damage = 0 @@ -296,14 +296,14 @@ return FALSE var/obj/item/organ/external/chest/BP = target.get_bodypart(BP_CHEST) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) return TRUE return FALSE /datum/surgery_step/ribcage/fix_chest_internal_robot/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/chest/BP = target.get_bodypart(BP_CHEST) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) user.visible_message("[user] starts mending the mechanisms on [target]'s [IO] with \the [tool].", "You start mending the mechanisms on [target]'s [IO] with \the [tool]." ) continue @@ -316,7 +316,7 @@ /datum/surgery_step/ribcage/fix_chest_internal_robot/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/chest/BP = target.get_bodypart(BP_CHEST) for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) user.visible_message("[user] repairs [target]'s [IO] with \the [tool].", "You repair [target]'s [IO] with \the [tool]." ) IO.damage = 0 @@ -335,7 +335,7 @@ var/dam_amt = 2 for(var/obj/item/organ/internal/IO in BP.bodypart_organs) - if(IO.damage > 0 && IO.robotic == 2) + if(IO.damage > 0 && IO.is_robotic()) IO.take_damage(dam_amt,0) ////////////////////////////////////////////////////////////////// diff --git a/code/modules/unarmed_combat/combos/disarming.dm b/code/modules/unarmed_combat/combos/disarming.dm index 0276b9c0b567..6b9a7e77932d 100644 --- a/code/modules/unarmed_combat/combos/disarming.dm +++ b/code/modules/unarmed_combat/combos/disarming.dm @@ -541,6 +541,7 @@ if(ishuman(victim)) var/mob/living/carbon/human/H = victim var/obj/item/organ/internal/eyes/IO = H.organs_by_name[O_EYES] - IO.damage += 20 + if(IO) + IO.damage += 20 victim.flash_eyes() victim.visible_message("[attacker] pokes [victim] in the eye!") diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm index 19b5a1bb09b7..0ce7444ed04f 100644 --- a/code/modules/virus2/effect.dm +++ b/code/modules/virus2/effect.dm @@ -973,7 +973,7 @@ var/mob/living/carbon/human/H = mob var/list/parts = list() for(var/obj/item/organ/external/BP in H.bodyparts) - if(BP.is_robotic()) + if(BP.is_robotic_part()) if(BP.get_damage()) parts += BP if(!parts.len) diff --git a/icons/obj/special_organs/skrell.dmi b/icons/obj/special_organs/skrell.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f9250826a5e9cd277845ed490d9cbf8631e8b807 GIT binary patch literal 1844 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 literal 0 HcmV?d00001 diff --git a/icons/obj/special_organs/vox.dmi b/icons/obj/special_organs/vox.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a6a914fb4938158aac28df3244fbbef107a5fe11 GIT binary patch literal 1993 zcmV;)2R8VLP)004jl0{{R3eocQU0000gP)t-sz`(#p zR90k%j7dR)ip0Yd5*;WkJVL+dbMNT!^8ZD0fFDZ*Bkpc$}4!(F%ev6o#+2rxH z4%Y_TN__iPh7^QbcmMhMwsAgKNDle2C`ooI@Ew$9Qjk5_t~VGBtTvq;(gdRpSlgLt z(1seYF}NtoL=s?BGo@`2W7H^mg(=S%zll~msh-sWMmGl|xSedLE?WwVzf`_AS?wek%4vXVL%hVhMLh_k8JF z{qmuZ)<86=P)93&I25w12K~!jg?V3+d8%G$%hits5EGh*AsNw_;I8v2E zl&RO&ra3?fhc*XV$6F~U!{QH-z zm1g?cz_bZ2B*-|2(3cO}Ttca<2IOKT8sWjCgW!7k5A$c#Ta;bX?|)hE0FC6%=fUDuFNLQ&1tm0odCJD zChC;dEvD%Iq_H1cT)MlF0lj^X>|h>XJXocHxwRpH-MAzdT1_!Z+G7(vi0D_60+(l& z@7_;=RYq{fV^u#qApJvZuS>sPL|b&ghZbC)5bID*nptlGyOZqT{cH0JOKES7P}X6) zoE#F|Z>&DT9L+nQ3@$%$(V)pCV2Wk71_y{s0)PUiPJ&pxKf69TodT=kY;a6)NLU|e zgaILyjcI>ylA?>I(VQ?{9s`R(unhsX8fm$AmuF`uoteb8y?p|4h$-{>OBTDucyE2e zr~NgGi>9&$rY0N?2f*;C%UoOHfvI`w`7_h$c5sZj_oHoNg5r}z2zAX=d+}M=@d@FLhjE2%YPB|2u7U!x`&VMoCj$8G z<6rr93iQNog>)^k*S~Yyn00zCTpKJoz)S!cr7;jW>q`JMYW)kR*xj?~UU>8yVQEPr z_DR=HfwR{vi&Y7NgMBt|5LLKEh#dh75V>n+S?tu7AD!poF0$bd;ZcwQK^yygHw6N8 zYlb4b*ND%X05WljxS01V1ddw)U4ku_g%!#odzu3)jh_bR;muokLpA7NrW%u_;O$j4q^mS*N%v+u7j4Y(qYBaI3Tm zF0tk2F$bYmW~(@8X3m62o?W_&27`UlX@W-enbKN-mUN7Xklg9Q3iz-LPNUIk-NNe= z%d_c&RjIS*%9ZP1qw>{@`5~R1oygqHz8mdD$hQ^XacNcl1*PS? zksd&dJ^86&yuA5VE>O#NBYhMFx>bpI^2KLoO|dbF*Ye#+Uk!Y`%W;}*#>>a2_uhi# z6sYC9kzPbbzRP(MV8OBb`HRi7lTr%Q@?GRZ&3h#C1}1{Wd6MVG@4dQh-~MHzw3>|2 z^WFNa-DQfe$=(n=T*Wv6o|Iod=P$XH0Y$#UQoa+9Bq8RKkNSy}{{#;rgtk-Q^V8R- zFJvHN9uDDJ=DV6#`c2L(!9zbMz}1)Z6+Jy(DQ5?Wd?)1u0q`-Cz0z;;PQ-KX#Qw&; zH_yL%v9U6roi>s0h?MWls_M1;XI4dlE`0ZU>`N!*GkUf%Kal}NzGGAh9uc4;0~scg z|0BY^OM548l-_Pcyk^=Y@*R=$U0X~5rSu~n6qwZiF}#!EqNo3plFAb$aygDg06Fi8 z36=Z@($&T#F6g`{jww+qnxLZj52vBA(uBr~5~C8ww7fUuHBAojfT_hXJ@2{joGd58 zqRtzVp7#pp@p9$Ll`GdjsLOhTLEkql)#{wqU=#T*Hn?(2&Co^KRtIQWT4<^bMUuY% z?8|%lP&uAam!AW?wCO%kTSDq9OA2~5WdyfSU9RCHN{Z41mzHhy%|F03E{(Zt z0Jd66g(i{TqKj`?PqAVPw>r{G9#HI5Ix^7U6^AJ$8_7HAcmhTh56lPhOP;7g`Kdu{ zv1Quo7xlK{Ks|d89~0FtaE` z-6%gwdcGUwhcsSRte)>i`C+~JX;rp*zI%_?60wJshVd_{0vyVBu1A})Z)^Qmy6S6~ z@s))cWq_XVOvV-OGWCBkiV!LB>C)MfGJZJUY2K`>K*Q4F+q_!faK0-zn%Dnm2y*4h b^`F+CIp}4HzP!L100000NkvXXu0mjfcp}Oy literal 0 HcmV?d00001 diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 77fbec3f00e1df12cb44ae02a9f6636e1c6f09e3..e79965ccf92ec9624c59dedf4efa6f233a4710c7 100644 GIT binary patch literal 21361 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 Date: Sun, 13 Oct 2024 21:16:30 +0400 Subject: [PATCH 03/32] operation_fix --- code/modules/surgery/gender_reassignment.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/modules/surgery/gender_reassignment.dm b/code/modules/surgery/gender_reassignment.dm index 30c9cf6d9128..37687cfc2524 100644 --- a/code/modules/surgery/gender_reassignment.dm +++ b/code/modules/surgery/gender_reassignment.dm @@ -16,15 +16,15 @@ var/obj/item/organ/external/groin = target.get_bodypart(BP_GROIN) if (!groin) return 0 - if (groin.open < 1) + if (groin.open < 2) return 0 return 1 /datum/surgery_step/gender_reassignment/reshape_genitals allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ + /obj/item/weapon/retractor = 100, \ + /obj/item/weapon/kitchen/utensil/fork = 75, \ + /obj/item/weapon/screwdriver = 50 ) min_duration = 110 From f523a1d3f186bd9a7ade9f54715c7e8c8e9e4d94 Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Sun, 13 Oct 2024 23:32:29 +0400 Subject: [PATCH 04/32] dme fix --- taucetistation.dme | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/taucetistation.dme b/taucetistation.dme index d04a884b141c..8d2a6247efcf 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -2105,22 +2105,6 @@ #include "code\modules\nano\nanoui.dm" #include "code\modules\nano\modules\crew_monitor.dm" #include "code\modules\orbit\orbit.dm" -#include "code\modules\surgery\eye.dm" -#include "code\modules\surgery\organs_internal.dm" -#include "code\modules\surgery\organs\blood.dm" -#include "code\modules\surgery\organs\organ.dm" -#include "code\modules\surgery\organs\organ_external.dm" -#include "code\modules\surgery\organs\organ_helpers.dm" -#include "code\modules\surgery\organs\organ_internal.dm" -#include "code\modules\surgery\organs\pain.dm" -#include "code\modules\surgery\organs\wound.dm" -#include "code\modules\surgery\organs\external\flesh.dm" -#include "code\modules\surgery\organs\external\ipc.dm" -#include "code\modules\surgery\organs\external\nymph.dm" -#include "code\modules\surgery\organs\external\plant.dm" -#include "code\modules\surgery\organs\external\robotic.dm" -#include "code\modules\surgery\organs\external\skeleton.dm" -#include "code\modules\surgery\organs\external\stump.dm" #include "code\modules\paperwork\carbonpaper.dm" #include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\filingcabinet.dm" @@ -2480,6 +2464,21 @@ #include "code\modules\surgery\ribcage.dm" #include "code\modules\surgery\surgery.dm" #include "code\modules\surgery\tissue.dm" +#include "code\modules\surgery\organs_internal.dm" +#include "code\modules\surgery\organs\blood.dm" +#include "code\modules\surgery\organs\organ.dm" +#include "code\modules\surgery\organs\organ_external.dm" +#include "code\modules\surgery\organs\organ_helpers.dm" +#include "code\modules\surgery\organs\organ_internal.dm" +#include "code\modules\surgery\organs\pain.dm" +#include "code\modules\surgery\organs\wound.dm" +#include "code\modules\surgery\organs\external\flesh.dm" +#include "code\modules\surgery\organs\external\ipc.dm" +#include "code\modules\surgery\organs\external\nymph.dm" +#include "code\modules\surgery\organs\external\plant.dm" +#include "code\modules\surgery\organs\external\robotic.dm" +#include "code\modules\surgery\organs\external\skeleton.dm" +#include "code\modules\surgery\organs\external\stump.dm" #include "code\modules\telesci\bscrystal.dm" #include "code\modules\telesci\gps.dm" #include "code\modules\telesci\telepad.dm" From 6b08b096e0d9a6e4787c7592aa6026625d4127ff Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:19:16 +0400 Subject: [PATCH 05/32] Update code/modules/surgery/organs/organ.dm Co-authored-by: NinjaPikachuska <89906909+NinjaPikachuska@users.noreply.github.com> --- code/modules/surgery/organs/organ.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 50fcdad457ed..5c1b95dd4e1d 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -7,7 +7,6 @@ /obj/item/organ name = "organ" icon = 'icons/obj/surgery.dmi' - item_state_world germ_level = 0 var/organ_tag = O_HEART From 459fac3d83148b05ec36f98290c30e182af2fd74 Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 26 Oct 2024 15:48:50 +0400 Subject: [PATCH 06/32] eyes, roles and organs damage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Вернула переменные органов по местам, сделала зрение зависящее от глаз, все роли и расы работают корректно и не умирают при спавне. --- code/modules/mob/living/carbon/carbon.dm | 4 -- code/modules/mob/living/carbon/human/life.dm | 21 ++------ .../modules/mob/living/carbon/human/zombie.dm | 3 ++ code/modules/mob/living/carbon/species.dm | 35 +++++++------ code/modules/surgery/organs/organ.dm | 45 +--------------- code/modules/surgery/organs/organ_internal.dm | 52 ++++++++++++++++++- 6 files changed, 78 insertions(+), 82 deletions(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index a4841714807e..05f6828cfefd 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1191,10 +1191,6 @@ sight = initial(sight) var/new_lighting_alpha = initial(lighting_alpha) - var/datum/species/S = all_species[get_species()] - if(S) - see_in_dark = S.darksight - see_invisible = see_in_dark > 2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING if(changeling_aug) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 22533548d5a5..abeb61553848 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -332,7 +332,8 @@ var/global/list/tourette_bad_words= list( BP.add_autopsy_data("Radiation Poisoning", damage) /mob/living/carbon/human/is_cant_breathe() - return (handle_drowning() || health < config.health_threshold_crit) && !(reagents.has_reagent("inaprovaline") || HAS_TRAIT(src, TRAIT_AV)) + var/lungs = get_int_organ_by_name(O_LUNGS) + return ((handle_drowning() || health < config.health_threshold_crit) || !lungs) && !(reagents.has_reagent("inaprovaline") || HAS_TRAIT(src, TRAIT_AV)) /mob/living/carbon/human/handle_external_pre_breathing(datum/gas_mixture/breath) ..() @@ -347,18 +348,6 @@ var/global/list/tourette_bad_words= list( failed_last_breath = inhale_alert - var/lungs = get_int_organ_by_name(O_LUNGS) - if(!lungs) - adjustOxyLoss(10) - if(prob(80)) - emote("gasp") - - //CRIT - if(!breath || (breath.total_moles == 0) || !lungs) - adjustOxyLoss(5) - inhale_alert = TRUE - return FALSE - if(breath) //spread some viruses while we are at it if (virus2.len > 0) @@ -1079,10 +1068,10 @@ var/global/list/tourette_bad_words= list( return FALSE var/obj/item/organ/internal/eyes/eyes = organs_by_name[O_EYES] + var/night = null if(eyes) see_in_dark = eyes.darksight - else - see_in_dark = species.darksight + night = eyes.nighteyes var/obj/item/clothing/glasses/G = glasses if(istype(G)) @@ -1098,7 +1087,7 @@ var/global/list/tourette_bad_words= list( else sightglassesmod = null - if(species.nighteyes) + if(night) var/light_amount = 0 var/turf/T = get_turf(src) light_amount = round(T.get_lumcount()*10) diff --git a/code/modules/mob/living/carbon/human/zombie.dm b/code/modules/mob/living/carbon/human/zombie.dm index 6cf8ace264a7..33cf70294049 100644 --- a/code/modules/mob/living/carbon/human/zombie.dm +++ b/code/modules/mob/living/carbon/human/zombie.dm @@ -301,6 +301,9 @@ var/global/list/zombie_list = list() var/datum/faction/zombie/Z = create_uniq_faction(/datum/faction/zombie) add_faction_member(Z, H, FALSE) + var/obj/item/organ/internal/eyes/zombie_vision/EYE = new(null) + EYE.insert_organ(H) + /proc/remove_zombie(mob/living/carbon/human/H) var/obj/effect/proc_holder/spell/targeted/zombie_findbrains/spell = locate() in H.spell_list H.RemoveSpell(spell) diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index f0664c55833c..8e1cccbce74b 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -74,8 +74,6 @@ var/taste_sensitivity = TASTE_SENSITIVITY_NORMAL //the most widely used factor; humans use a different one var/dietflags = 0 // Make sure you set this, otherwise it won't be able to digest a lot of foods - var/darksight = 2 - var/nighteyes = FALSE var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. @@ -380,7 +378,6 @@ race_verbs = list(/mob/living/carbon/human/proc/air_sample) dietflags = DIET_MEAT | DIET_DAIRY primitive = /mob/living/carbon/monkey/unathi - darksight = 3 cold_level_1 = BODYTEMP_COLD_DAMAGE_LIMIT + 20 cold_level_2 = BODYTEMP_COLD_DAMAGE_LIMIT + 15 @@ -457,8 +454,6 @@ race_traits = list(TRAIT_NATURAL_AGILITY) dietflags = DIET_OMNI taste_sensitivity = TASTE_SENSITIVITY_SHARP - darksight = 8 - nighteyes = TRUE breath_cold_level_1 = BODYTEMP_COLD_DAMAGE_LIMIT - 40 breath_cold_level_2 = BODYTEMP_COLD_DAMAGE_LIMIT - 50 @@ -1166,7 +1161,6 @@ /datum/species/abductor name = ABDUCTOR - darksight = 3 dietflags = DIET_OMNI icobase = 'icons/mob/human_races/r_abductor.dmi' @@ -1381,7 +1375,6 @@ heat_level_3 = 4000 blood_datum_path = /datum/dirt_cover/black_blood - darksight = 8 butcher_drops = list() // They are just shadows. Why should they drop anything? bodypart_butcher_results = list() @@ -1404,6 +1397,11 @@ ,NO_GENDERS = TRUE ) + has_organ = list( + O_BRAIN = /obj/item/organ/internal/brain + ,O_EYES = /obj/item/organ/internal/eyes/night_vision + ) + burn_mod = 2 brain_mod = 0 @@ -1538,8 +1536,6 @@ /datum/species/zombie name = ZOMBIE - darksight = 8 - nighteyes = TRUE dietflags = DIET_OMNI icobase = 'icons/mob/human_races/r_zombie.dmi' @@ -1692,8 +1688,6 @@ cold_level_2 = BODYTEMP_COLD_DAMAGE_LIMIT - 10 cold_level_3 = BODYTEMP_COLD_DAMAGE_LIMIT - 50 - darksight = 3 - flags = list( NO_BREATHE = TRUE ,NO_SCAN = TRUE @@ -1738,8 +1732,6 @@ heat_level_2 = BODYTEMP_HEAT_DAMAGE_LIMIT + 10 heat_level_3 = BODYTEMP_HEAT_DAMAGE_LIMIT + 20 - darksight = 8 - restricted_inventory_slots = list(SLOT_BELT, SLOT_WEAR_ID, SLOT_L_EAR, SLOT_R_EAR, SLOT_BACK, SLOT_L_STORE, SLOT_R_STORE, SLOT_WEAR_SUIT, SLOT_W_UNIFORM, SLOT_SHOES, SLOT_GLOVES, SLOT_HEAD, SLOT_WEAR_MASK, SLOT_GLASSES) flags = list( @@ -1767,6 +1759,7 @@ has_organ = list( O_BRAIN = /obj/item/organ/internal/brain/abomination + ,O_EYES = /obj/item/organ/internal/eyes/night_vision ) burn_mod = 0.2 brute_mod = 0.2 @@ -1911,7 +1904,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart ,O_BRAIN = /obj/item/organ/internal/brain - ,O_EYES = /obj/item/organ/internal/eyes + ,O_EYES = /obj/item/organ/internal/eyes/night_vision ,O_LUNGS = /obj/item/organ/internal/lungs ,O_LIVER = /obj/item/organ/internal/liver/serpentid ,O_KIDNEYS = /obj/item/organ/internal/kidneys @@ -1922,7 +1915,6 @@ heat_level_3 = BODYTEMP_HEAT_DAMAGE_LIMIT + 440 unarmed_type = /datum/unarmed_attack/claws/serpentid blood_trail_type = /obj/effect/decal/cleanable/blood/tracks/snake - darksight = 8 offset_features = list( OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), @@ -2072,6 +2064,17 @@ NO_GENDERS = TRUE, NO_FAT = TRUE, ) + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart + ,O_BRAIN = /obj/item/organ/internal/brain + ,O_EYES = /obj/item/organ/internal/eyes/tajaran + ,O_LUNGS = /obj/item/organ/internal/lungs + ,O_LIVER = /obj/item/organ/internal/liver + ,O_KIDNEYS = /obj/item/organ/internal/kidneys + ) + + restricted_inventory_slots = list(SLOT_WEAR_ID, SLOT_BELT, SLOT_L_EAR, SLOT_R_EAR) unarmed_type = /datum/unarmed_attack/claws dietflags = DIET_OMNI @@ -2080,8 +2083,6 @@ damage_mask = FALSE min_age = 1 max_age = 5 - darksight = 8 - nighteyes = 1 /datum/species/moth/on_gain(mob/living/carbon/human/H) H.real_name = "[pick(global.moth_first)] [pick(global.moth_second)]" diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 50fcdad457ed..6912ee93c2c1 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -10,7 +10,6 @@ item_state_world germ_level = 0 - var/organ_tag = O_HEART appearance_flags = TILE_BOUND | PIXEL_SCALE | KEEP_APART | APPEARANCE_UI_IGNORE_ALPHA // Strings. @@ -27,12 +26,8 @@ var/obj/item/organ/external/parent // Master-limb. // Damage vars. - var/damage = 0 // amount of damage to the organ - var/min_bruised_damage = 10 - var/min_broken_damage = 30 - var/max_damage - - var/dead_icon + var/min_broken_damage = 30 // Damage before becoming broken + var/max_damage = 0 // Damage cap var/sterile = 0 //can the organ be infected by germs? var/requires_robotic_bodypart = FALSE @@ -60,15 +55,6 @@ loc = null owner = H -/obj/item/organ/proc/die() - if(is_robotic()) - return - damage = max_damage - status |= ORGAN_DEAD - STOP_PROCESSING(SSobj, src) - if(owner && vital) - owner.death() - /obj/item/organ/process() //dead already, no need for more processing @@ -96,19 +82,11 @@ germ_level += rand(2,6) if(germ_level >= INFECTION_LEVEL_TWO) germ_level += rand(2,6) - if(germ_level >= INFECTION_LEVEL_THREE) - die() - - if(damage >= max_damage) - die() else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Handle antibiotics and curing infections handle_antibiotics() - //check if we've hit max_damage - if(damage >= max_damage) - die() /obj/item/organ/proc/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) set_owner(H, S) @@ -159,19 +137,6 @@ else return (istype(loc,/obj/structure/closet/secure_closet/freezer) || istype(loc,/obj/structure/closet/crate/freezer)) -/obj/item/organ/take_damage(amount, silent=0) - if(!isnum(silent)) - return // prevent basic take_damage usage (TODO remove workaround) - if(is_robotic()) - src.damage += (amount * 0.8) - else - src.damage += amount - - //only show this if the organ is not robotic - if(owner && parent_bodypart && amount > 0) - var/obj/item/organ/external/parent = owner.get_organ(parent_bodypart) - if(parent && !silent) - owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) /obj/item/organ/examine(mob/user) . = ..(user) @@ -341,9 +306,3 @@ if(!has_arm) //need atleast one hand to crawl Stun(5) -/obj/item/organ/proc/is_primary_organ(mob/living/carbon/human/O = null) - if (isnull(O)) - O = owner - if (!istype(owner)) // You're not the primary organ of ANYTHING, bucko - return 0 - return src == O.get_int_organ(organ_tag) diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index d6516005e0a1..7e27a6fd86ea 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -3,10 +3,15 @@ ****************************************************/ /obj/item/organ/internal parent_bodypart = BP_CHEST - + var/organ_tag = O_HEART // Will be moved, removed or refactored. var/process_accuracy = 0 // Damage multiplier for organs, that have damage values. + var/damage = 0 // amount of damage to the organ + var/min_bruised_damage = 10 + + var/dead_icon + /obj/item/organ/internal/New(mob/living/carbon/holder) @@ -24,6 +29,15 @@ owner.organs_by_name -= organ_tag return ..() +/obj/item/organ/internal/proc/die() + if(is_robotic()) + return + damage = max_damage + status |= ORGAN_DEAD + STOP_PROCESSING(SSobj, src) + if(owner && vital) + owner.death() + /obj/item/organ/internal/remove(mob/living/carbon/human/M, special = 0) owner = null STOP_PROCESSING(SSobj, src) @@ -66,6 +80,22 @@ insert_organ(target) ..() +/obj/item/organ/internal/take_damage(amount, silent=0) + if(!isnum(silent)) + return // prevent basic take_damage usage (TODO remove workaround) + if(is_robotic()) + src.damage += (amount * 0.8) + else + src.damage += amount + + //only show this if the organ is not robotic + if(owner && parent_bodypart && amount > 0) + var/obj/item/organ/external/parent = owner.get_organ(parent_bodypart) + if(parent && !silent) + owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) + if(damage >= max_damage) + die() + /obj/item/organ/internal/proc/rejuvenate() damage = 0 @@ -81,6 +111,10 @@ /obj/item/organ/internal/process() //Process infections + //dead already, no need for more processing + if(status & ORGAN_DEAD) + return + if (is_robotic() || (owner.species && owner.species.flags[IS_PLANT])) //TODO make robotic organs and bodyparts separate types instead of a flag germ_level = 0 return @@ -108,7 +142,8 @@ if (prob(3)) //about once every 30 seconds take_damage(1,silent=prob(30)) - + if(germ_level >= INFECTION_LEVEL_THREE) + die() /obj/item/organ/internal/emp_act(severity) if(!is_robotic()) @@ -728,6 +763,7 @@ slot = "eyes" var/list/eye_colour = list(0,0,0) var/darksight = 2 + var/nighteyes = FALSE /obj/item/organ/internal/eyes/proc/update_colour() if(!owner) @@ -758,6 +794,7 @@ name = "tajaran eyeballs" icon = 'icons/obj/special_organs/tajaran.dmi' darksight = 8 + nighteyes = TRUE /obj/item/organ/internal/eyes/unathi name = "unathi eyeballs" @@ -778,6 +815,17 @@ icon_state = "podkid" item_state_world = "podkid" +/obj/item/organ/internal/eyes/zombie_vision + name = "zombie eyes" + desc = "A dead set of eyes that don't blink" + darksight = 8 + nighteyes = TRUE + +/obj/item/organ/internal/eyes/night_vision + name = "shadow eyes" + desc = "A spooky set of eyes that can see in the dark." + darksight = 8 + /obj/item/organ/internal/eyes/cybernetic name = "cybernetic eyes" icon_state = "eyes-prosthetic" From c46e1e58331979dca8d0e06e6911a1ff2ed6e556 Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 26 Oct 2024 16:14:02 +0400 Subject: [PATCH 07/32] abomination neck --- code/modules/mob/living/carbon/species.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index cb1037ac6870..17aa763bdca2 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -1816,7 +1816,7 @@ heat_level_2 = BODYTEMP_HEAT_DAMAGE_LIMIT + 10 heat_level_3 = BODYTEMP_HEAT_DAMAGE_LIMIT + 20 - restricted_inventory_slots = list(SLOT_BELT, SLOT_WEAR_ID, SLOT_L_EAR, SLOT_R_EAR, SLOT_BACK, SLOT_L_STORE, SLOT_R_STORE, SLOT_WEAR_SUIT, SLOT_W_UNIFORM, SLOT_SHOES, SLOT_GLOVES, SLOT_HEAD, SLOT_WEAR_MASK, SLOT_GLASSES) + restricted_inventory_slots = list(SLOT_BELT, SLOT_NECK, SLOT_WEAR_ID, SLOT_L_EAR, SLOT_R_EAR, SLOT_BACK, SLOT_L_STORE, SLOT_R_STORE, SLOT_WEAR_SUIT, SLOT_W_UNIFORM, SLOT_SHOES, SLOT_GLOVES, SLOT_HEAD, SLOT_WEAR_MASK, SLOT_GLASSES) flags = list( NO_BREATHE = TRUE From 61b3ff79d80ea1a0a08837a8162cce6b803bdebb Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 7 Dec 2024 02:17:17 +0400 Subject: [PATCH 08/32] mechanize_remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Убрала в нулльспейс прок mechanize и теперь органы просто меняются на кибернетику --- code/datums/qualities/quirkieish.dm | 22 +++++++++++++++++-- code/modules/client/preferences.dm | 20 +++++++++++++++-- code/modules/mob/living/carbon/species.dm | 4 ---- code/modules/surgery/organs/organ.dm | 6 ----- code/modules/surgery/organs/organ_internal.dm | 16 -------------- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/code/datums/qualities/quirkieish.dm b/code/datums/qualities/quirkieish.dm index 913667efb708..3e0a56e22143 100644 --- a/code/datums/qualities/quirkieish.dm +++ b/code/datums/qualities/quirkieish.dm @@ -27,8 +27,26 @@ var/obj/item/organ/external/r_leg/robot/RL = new(null) RL.insert_organ(H) - for(var/obj/item/organ/internal/IO in H.organs) - IO.mechanize() + qdel(H.organs_by_name[O_HEART]) + qdel(H.organs_by_name[O_KIDNEYS]) + qdel(H.organs_by_name[O_LIVER]) + qdel(H.organs_by_name[O_LUNGS]) + qdel(H.organs_by_name[O_EYES]) + + var/obj/item/organ/internal/heart/cybernetic/CH = new(null) + CH.insert_organ(H) + + var/obj/item/organ/internal/kidneys/cybernetic/CK = new(null) + CK.insert_organ(H) + + var/obj/item/organ/internal/liver/cybernetic/CL = new(null) + CL.insert_organ(H) + + var/obj/item/organ/internal/lungs/cybernetic/CU = new(null) + CU.insert_organ(H) + + var/obj/item/organ/internal/eyes/cybernetic/CE = new(null) + CE.insert_organ(H) H.regenerate_icons() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 07de4f3aeb24..1e2a279a7d7f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -498,8 +498,24 @@ var/global/list/datum/preferences/preferences_datums = list() new_BP.insert_organ(character) else if(status == "Cybernetic" && IO) - IO.mechanize() - + if(IO) + qdel(IO) + switch(name) + if(O_HEART) + var/obj/item/organ/internal/heart/cybernetic/C = new(null) + C.insert_organ(character) + if(O_KIDNEYS) + var/obj/item/organ/internal/kidneys/cybernetic/C = new(null) + C.insert_organ(character) + if(O_LIVER) + var/obj/item/organ/internal/liver/cybernetic/C = new(null) + C.insert_organ(character) + if(O_LUNGS) + var/obj/item/organ/internal/lungs/cybernetic/C = new(null) + C.insert_organ(character) + if(O_EYES) + var/obj/item/organ/internal/eyes/cybernetic/C = new(null) + C.insert_organ(character) else continue diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 17aa763bdca2..db85a5971585 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -219,10 +219,6 @@ var/obj/item/organ/internal/O = new path(null) O.insert_organ(H) - if(flags[IS_SYNTHETIC]) - for(var/obj/item/organ/internal/IO in H.organs) - IO.mechanize() - /datum/species/proc/create_bodyparts(mob/living/carbon/human/H) for(var/type in has_bodypart) var/path = has_bodypart[type] diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index cebd879e9f59..ca4ea2fd3e7d 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -233,12 +233,6 @@ return TRUE return FALSE -/obj/item/organ/proc/mechanize() //Being used to make robutt hearts, etc - status &= ~ORGAN_BROKEN - status &= ~ORGAN_SPLINTED - status += ORGAN_ROBOT - - /mob/living/carbon/human/proc/handle_stance() // Don't need to process any of this if they aren't standing anyways // unless their stance is damaged, and we want to check if they should stay down diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 7e27a6fd86ea..30a067c3c0fd 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -155,22 +155,6 @@ if(2) take_damage(7, 1) -/obj/item/organ/internal/mechanize() //Being used to make robutt hearts, etc - if(!is_robotic()) - var/list/states = icon_states('icons/obj/surgery.dmi') //Insensitive to specially-defined icon files for species like the Drask or whomever else. Everyone gets the same robotic heart. - if(slot == "heart" && ("[slot]-prosthetic-on" in states) && ("[slot]-prosthetic-off" in states)) //Give the robotic heart its robotic heart icons if they exist. - var/obj/item/organ/internal/heart/H = src - H.icon = icon('icons/obj/surgery.dmi') - H.icon_state = "[slot]-prosthetic" - H.dead_icon = "[slot]-prosthetic-off" - H.item_state_world = "[slot]-prosthetic_world" - H.update_icon() - else if("[slot]-prosthetic" in states) //Give the robotic organ its robotic organ icons if they exist. - icon = icon('icons/obj/surgery.dmi') - icon_state = "[slot]-prosthetic" - item_state_world = "[slot]-prosthetic_world" - name = "cybernetic [slot]" - ..() //Go apply all the organ flags/robotic statuses. /**************************************************** ORGANS DEFINES From fe87626737d36dbbe694df0c998f0512097bd4cd Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 7 Dec 2024 02:19:34 +0400 Subject: [PATCH 09/32] Dion's, vox's and slot's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Вырезала повторяющийся список, добавила лист совместимости органов, убрала возможность оперировать дион и сделала их органы неумирающими(не неуязвимыми) --- .../mob/living/carbon/human/human_defines.dm | 2 - code/modules/mob/living/carbon/species.dm | 4 +- code/modules/surgery/eye.dm | 18 +++--- code/modules/surgery/organs/organ.dm | 3 +- code/modules/surgery/organs/organ_helpers.dm | 6 -- code/modules/surgery/organs/organ_internal.dm | 61 ++++++++++++------- code/modules/surgery/organs_internal.dm | 42 +++++++------ 7 files changed, 72 insertions(+), 64 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a44d4e9fc1a7..d3e7402cbf82 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -127,5 +127,3 @@ var/list/allergies var/next_allergy_message = 0 - //Same as above, but stores "slot ID" - "organ" pairs for easy access. - var/list/internal_organs_slot = list() diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index db85a5971585..312e9e0f6506 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -890,9 +890,9 @@ ) has_organ = list( - O_HEART = /obj/item/organ/internal/heart, + O_HEART = /obj/item/organ/internal/heart/diona, O_BRAIN = /obj/item/organ/internal/brain/diona, - O_EYES = /obj/item/organ/internal/eyes, + O_EYES = /obj/item/organ/internal/eyes/diona, O_LUNGS = /obj/item/organ/internal/lungs/diona, O_LIVER = /obj/item/organ/internal/liver/diona, O_KIDNEYS = /obj/item/organ/internal/kidneys/diona diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index 091de04b90e0..e6d614f06c35 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -150,7 +150,7 @@ ////////////////////////////////////////////////////////////////// // EYE SURGERY manipulation // ////////////////////////////////////////////////////////////////// - +/* /datum/surgery_step/eye/manipulation priority = 1 allowed_species = null @@ -169,12 +169,12 @@ - var/obj/item/organ/internal/I = tool + var/obj/item/organ/internal/organ/eyes/I = tool if(I.requires_robotic_bodypart) user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") return FALSE - if(target_zone != I.parent_bodypart || target.get_organ_slot(I.slot)) + if(target_zone != I.parent_bodypart) user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") return FALSE @@ -214,7 +214,7 @@ BP.take_damage(10, 0, DAM_SHARP|DAM_EDGE, tool) if(IO) IO.take_damage(5, 0) - +*/ ////////////////////////////////////////////////////////////////// // EYE SURGERY manipulation for eyes // ////////////////////////////////////////////////////////////////// @@ -223,6 +223,8 @@ priority = 2 allowed_tools = list(/obj/item/organ/internal/eyes = 100) + allowed_species = list("exclude", IPC, DIONA) + min_duration = 110 max_duration = 150 @@ -239,15 +241,11 @@ user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") return FALSE - if(target.get_organ_slot(I.slot)) - user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") - return FALSE - if(I.damage > (I.max_damage * 0.75)) user.visible_message ( " \The [I] is in no state to be transplanted.") return FALSE - if(target.get_int_organ(I)) + if(target.get_int_organ_by_name(I)) user.visible_message ( " \The [target] already has [I].") return FALSE @@ -281,6 +279,8 @@ /obj/item/weapon/shard = 50, \ ) + allowed_species = list("exclude", IPC, DIONA) + min_duration = 110 max_duration = 150 diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index ca4ea2fd3e7d..85e6d9b2ec02 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -30,8 +30,7 @@ var/sterile = 0 //can the organ be infected by germs? var/requires_robotic_bodypart = FALSE - var/slot = "heart" - // DO NOT add slots with matching names to different zones - it will break internal_organs_slot list! + /obj/item/organ/Destroy() owner = null diff --git a/code/modules/surgery/organs/organ_helpers.dm b/code/modules/surgery/organs/organ_helpers.dm index f0ed01f31720..6972309acc03 100644 --- a/code/modules/surgery/organs/organ_helpers.dm +++ b/code/modules/surgery/organs/organ_helpers.dm @@ -1,14 +1,8 @@ /mob/proc/get_int_organ(typepath) //int stands for internal return -/mob/proc/get_organ_slot(slot) //is it a brain, is it a brain_tumor? - return - /mob/living/carbon/human/get_int_organ(typepath) return (locate(typepath) in organs_by_name) -/mob/living/carbon/human/get_organ_slot(slot) - return internal_organs_slot[slot] - /mob/living/carbon/human/proc/get_int_organ_by_name(tag_to_check) return organs_by_name[tag_to_check] diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 30a067c3c0fd..0a066d0462f1 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -10,9 +10,11 @@ var/damage = 0 // amount of damage to the organ var/min_bruised_damage = 10 - var/dead_icon + var/tough = FALSE //can organ be easily die? + var/dead_icon + var/list/compability = list(HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) // races with which organs are compatible /obj/item/organ/internal/New(mob/living/carbon/holder) if(istype(holder)) @@ -30,6 +32,8 @@ return ..() /obj/item/organ/internal/proc/die() + if(tough) + return if(is_robotic()) return damage = max_damage @@ -45,8 +49,6 @@ M.organs -= src if(M.organs_by_name[organ_tag] == src) M.organs_by_name -= organ_tag - if(M.internal_organs_slot[slot] == src) - M.internal_organs_slot.Remove(slot) if(vital && !special) if(M.stat != DEAD)//safety check! @@ -64,14 +66,13 @@ /obj/item/organ/internal/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) ..() - var/obj/item/organ/internal/replaced = H.get_organ_slot(slot) + var/obj/item/organ/internal/replaced = H.get_int_organ_by_name(organ_tag) if(replaced) replaced.remove(H, special = 1) owner.organs += src owner.organs_by_name[organ_tag] = src - H.internal_organs_slot[slot] = src if(parent) parent.bodypart_organs += src @@ -169,23 +170,26 @@ organ_tag = O_HEART vital = TRUE parent_bodypart = BP_CHEST + var/base_icon_state = "heart" var/heart_status = HEART_NORMAL var/fibrillation_timer_id = null var/failing_interval = 1 MINUTE var/beating = 0 + compability = list(HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + /obj/item/organ/internal/heart/update_icon() if(beating) - icon_state = "heart-on" - item_state_world = "heart-on_world" + item_state_world = "[base_icon_state]-on_world" + icon_state = "[base_icon_state]-on" else - icon_state = "heart-off" - item_state_world = "heart-off_world" + item_state_world = "[base_icon_state]-off_world" + icon_state = "[base_icon_state]-off" + /obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M, special = 0) ..() beating = 1 - update_icon() owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) @@ -223,16 +227,10 @@ desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." icon_state = "heart-prosthetic" item_state_world = "heart-prosthetic_world" + base_icon_state = "heart-prosthetic" dead_icon = "heart-prosthetic-off" status = ORGAN_ROBOT - -/obj/item/organ/internal/heart/cybernetic/update_icon() - if(beating) - icon_state = "heart-prosthetic" - item_state_world = "heart-prosthetic" - else - icon_state = "heart-prosthetic" - item_state_world = "heart-prosthetic" + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) /obj/item/organ/internal/heart/ipc name = "cooling pump" @@ -275,6 +273,7 @@ name = "vox heart" icon = 'icons/obj/special_organs/vox.dmi' parent_bodypart = BP_GROIN + compability = list(VOX) /obj/item/organ/internal/heart/tajaran name = "tajaran heart" @@ -295,6 +294,8 @@ icon = 'icons/obj/objects.dmi' icon_state = "nymph" item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/lungs name = "lungs" @@ -303,7 +304,6 @@ item_state_world = "lungs_world" organ_tag = O_LUNGS parent_bodypart = BP_CHEST - slot = "lungs" var/has_gills = FALSE /obj/item/organ/internal/lungs/vox @@ -312,6 +312,7 @@ desc = "They're filled with dust....wow." parent_bodypart = BP_GROIN icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) /obj/item/organ/internal/lungs/tajaran name = "tajaran lungs" @@ -334,6 +335,8 @@ icon = 'icons/obj/objects.dmi' icon_state = "nymph" item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/lungs/cybernetic name = "cybernetic lungs" @@ -342,6 +345,7 @@ item_state_world = "lungs-prosthetic_world" origin_tech = "biotech=4" status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) /obj/item/organ/internal/lungs/ipc name = "cooling element" @@ -411,7 +415,6 @@ organ_tag = O_LIVER parent_bodypart = BP_GROIN var/alcohol_intensity = 1 - slot = "liver" process_accuracy = 10 /obj/item/organ/internal/liver/diona @@ -421,11 +424,14 @@ icon_state = "podkid" item_state_world = "podkid" alcohol_intensity = 0.5 + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/liver/vox name = "waste tract" cases = list("канал отходов", "канала отходов", "каналу отходов", "канал отходов", "каналом отходов", "канале отходов") icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) alcohol_intensity = 1.6 /obj/item/organ/internal/liver/tajaran @@ -451,6 +457,7 @@ item_state_world = "liver-prosthetic_world" origin_tech = "biotech=4" status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) /obj/item/organ/internal/liver/ipc name = "accumulator" @@ -568,12 +575,12 @@ item_state_world = "kidneys_world" organ_tag = O_KIDNEYS parent_bodypart = BP_GROIN - slot = "kidneys" /obj/item/organ/internal/kidneys/vox name = "filtration bladder" cases = list("фильтрующий пузырь", "фильтрующего пузыря", "фильтрующему пузырю", "фильтрующий пузырь", "фильтрующим пузырём", "фильтрующем пузыре") icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) /obj/item/organ/internal/kidneys/tajaran name = "tajaran kidneys" @@ -595,6 +602,8 @@ icon = 'icons/obj/objects.dmi' icon_state = "nymph" item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/kidneys/cybernetic name = "cybernetic kidneys" @@ -603,6 +612,7 @@ item_state_world = "kidneys-prosthetic_world" origin_tech = "biotech=4" status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) /obj/item/organ/internal/kidneys/ipc name = "self-diagnosis unit" @@ -660,7 +670,6 @@ organ_tag = O_BRAIN vital = TRUE parent_bodypart = O_BRAIN - slot = "brain" icon_state = "brain2" item_state_world = "brain2_world" @@ -671,6 +680,8 @@ icon = 'icons/obj/objects.dmi' icon_state = "nymph" item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/brain/tajaran icon = 'icons/obj/special_organs/tajaran.dmi' @@ -685,6 +696,7 @@ icon = 'icons/obj/special_organs/vox.dmi' icon_state = "cortical-stack" item_state_world = "cortical-stack_world" + compability = list(VOX) /obj/item/organ/internal/brain/skrell icon = 'icons/obj/special_organs/skrell.dmi' @@ -744,7 +756,6 @@ cases = list("глаза", "глаз", "глазам", "глаза", "глазами", "глазах") organ_tag = O_EYES parent_bodypart = BP_HEAD - slot = "eyes" var/list/eye_colour = list(0,0,0) var/darksight = 2 var/nighteyes = FALSE @@ -798,6 +809,8 @@ icon = 'icons/obj/objects.dmi' icon_state = "podkid" item_state_world = "podkid" + compability = list(DIONA) + tough = TRUE /obj/item/organ/internal/eyes/zombie_vision name = "zombie eyes" @@ -817,6 +830,7 @@ item_state_world = "eyes-prosthetic_world" origin_tech = "biotech=4" status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) /obj/item/organ/internal/eyes/ipc name = "cameras" @@ -827,6 +841,7 @@ icon_state = "camera" item_state_world = "camera" + /obj/item/organ/internal/eyes/process() //Eye damage replaces the old eye_stat var. ..() if(is_bruised()) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index f84e3ee744b6..298c66f92ce9 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -6,7 +6,7 @@ /datum/surgery_step/organ_manipulation priority = 1 - allowed_species = null + allowed_species = list("exclude", IPC, DIONA) var/obj/item/organ/internal/I = null /datum/surgery_step/organ_manipulation/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -27,32 +27,34 @@ max_duration = 50 /datum/surgery_step/organ_manipulation/place/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!ishuman(target)) - return FALSE - - if(target_zone in list(O_EYES , O_MOUTH, BP_HEAD)) - return FALSE + if(!ishuman(target)) + return FALSE + if(target_zone in list(O_EYES , O_MOUTH, BP_HEAD)) + return FALSE + var/obj/item/organ/internal/I = tool + if(I.requires_robotic_bodypart) + user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") + return FALSE - var/obj/item/organ/internal/I = tool - if(I.requires_robotic_bodypart) - user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") - return FALSE + if(target_zone != I.parent_bodypart) + user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") + return FALSE - if(target_zone != I.parent_bodypart || target.get_organ_slot(I.slot)) - user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") - return FALSE + if(I.damage > (I.max_damage * 0.75)) + user.visible_message ( " \The [I] is in no state to be transplanted.") + return FALSE - if(I.damage > (I.max_damage * 0.75)) - user.visible_message ( " \The [I] is in no state to be transplanted.") - return FALSE + if(target.get_int_organ(I)) + user.visible_message ( " \The [target] already has [I].") + return FALSE - if(target.get_int_organ(I)) - user.visible_message ( " \The [target] already has [I].") - return FALSE + if(!(target.get_species() in I.compability)) + user.visible_message ( " \The [I] not compability to [target]") + return FALSE - return TRUE + return TRUE /datum/surgery_step/organ_manipulation/place/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) From 85494d5a6e022a9c86db6ca08d464c85430d0d5a Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Sat, 7 Dec 2024 03:10:05 +0400 Subject: [PATCH 10/32] Update code/modules/mob/living/carbon/human/human.dm Co-authored-by: KIBORG04 --- code/modules/mob/living/carbon/human/human.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 02a2eb284a42..ec5ecdda092b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1257,10 +1257,7 @@ /mob/living/carbon/human/proc/is_lung_ruptured() var/obj/item/organ/internal/lungs/IO = organs_by_name[O_LUNGS] - if(!IO) - return - - return IO.is_bruised() + return IO?.is_bruised() /mob/living/carbon/human/proc/rupture_lung() var/obj/item/organ/internal/lungs/IO = organs_by_name[O_LUNGS] From a79017fee33ae3279761a3643314f26fbc7e2f1e Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Sat, 7 Dec 2024 03:19:29 +0400 Subject: [PATCH 11/32] Update code/modules/mob/living/carbon/human/human_defines.dm Co-authored-by: KIBORG04 --- code/modules/mob/living/carbon/human/human_defines.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 4350d86665f7..f1be83c2696b 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -127,5 +127,4 @@ var/list/allergies var/next_allergy_message = 0 - var/wing_accessory_name = "none" From 909a8f6494c1e582693be5d1fdfa713220f89937 Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Sat, 7 Dec 2024 03:32:07 +0400 Subject: [PATCH 12/32] Update code/modules/surgery/organs/organ.dm Co-authored-by: KIBORG04 --- code/modules/surgery/organs/organ.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 85e6d9b2ec02..633992ac1d18 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -96,7 +96,8 @@ /obj/item/organ/proc/replaced(mob/living/carbon/human/target, obj/item/organ/external/parent_bodypart) - if(!istype(target)) return + if(!istype(target)) + return owner = target STOP_PROCESSING(SSobj, src) From b8e39bc0962dc0eec901222542a62d172beb180f Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 7 Dec 2024 04:19:11 +0400 Subject: [PATCH 13/32] Kill_appendix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Аппендецит и коменнты на глазах удалены, до новый встреч, аппендикс --- code/modules/surgery/appendix.dm | 53 ------------------------- code/modules/surgery/eye.dm | 67 -------------------------------- taucetistation.dme | 1 - 3 files changed, 121 deletions(-) delete mode 100644 code/modules/surgery/appendix.dm diff --git a/code/modules/surgery/appendix.dm b/code/modules/surgery/appendix.dm deleted file mode 100644 index 92c9ecd43688..000000000000 --- a/code/modules/surgery/appendix.dm +++ /dev/null @@ -1,53 +0,0 @@ -//Procedures in this file: Appendectomy -////////////////////////////////////////////////////////////////// -// APPENDECTOMY // -////////////////////////////////////////////////////////////////// -/* -/datum/surgery_step/appendectomy - priority = 2 - can_infect = 1 - blood_level = 1 - -/datum/surgery_step/appendectomy/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (!ishuman(target)) - return 0 - if (target_zone != BP_GROIN) - return 0 - var/obj/item/organ/external/BP = target.bodyparts_by_name[BP_GROIN] - if (!BP) - return 0 - if (BP.open < 2) - return 0 - return 1 - -/datum/surgery_step/appendectomy/cut_appendix - allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ - ) - - min_duration = 70 - max_duration = 90 - -/datum/surgery_step/appendectomy/cut_appendix/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.appendix == 0 - -/datum/surgery_step/appendectomy/cut_appendix/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts to separate [target]'s appendix from the abdominal wall with \the [tool].", \ - "You start to separate [target]'s appendix from the abdominal wall with \the [tool]." ) - target.custom_pain("The pain in your abdomen is living hell!",1) - ..() - -/datum/surgery_step/appendectomy/cut_appendix/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] has separated [target]'s appendix with \the [tool]." , \ - "You have separated [target]'s appendix with \the [tool].") - target.op_stage.appendix = 1 - -/datum/surgery_step/appendectomy/cut_appendix/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/BP = target.bodyparts_by_name[BP_GROIN] - user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!", \ - "Your hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!") - BP.take_damage(50, 0, DAM_SHARP|DAM_EDGE, tool) - -*/ diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index e6d614f06c35..b7ab3d33c661 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -147,74 +147,7 @@ BP.take_damage(0, 5, used_weapon = tool) IO.take_damage(5, 0) -////////////////////////////////////////////////////////////////// -// EYE SURGERY manipulation // -////////////////////////////////////////////////////////////////// -/* -/datum/surgery_step/eye/manipulation - priority = 1 - allowed_species = null - var/obj/item/organ/internal/I = null - -/datum/surgery_step/eye/manipulation/place - allowed_tools = list(/obj/item/organ/internal = 100) - - min_duration = 110 - max_duration = 150 - - -/datum/surgery_step/eye/manipulation/place/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!ishuman(target)) - return FALSE - - - - var/obj/item/organ/internal/organ/eyes/I = tool - if(I.requires_robotic_bodypart) - user.visible_message ("[I] is an organ that requires a robotic interface! [target]'s [parse_zone(target_zone)] does not have one.") - return FALSE - - if(target_zone != I.parent_bodypart) - user.visible_message ( "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") - return FALSE - - if(I.damage > (I.max_damage * 0.75)) - user.visible_message ( " \The [I] is in no state to be transplanted.") - return FALSE - - if(target.get_int_organ(I)) - user.visible_message ( " \The [target] already has [I].") - return FALSE - return TRUE - - - -/datum/surgery_step/eye/manipulation/place/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts transplanting \the [tool] into [target]'s [parse_zone(target_zone)].", \ - "You start transplanting \the [tool] into [target]'s [parse_zone(target_zone)].") - ..() - -/datum/surgery_step/eye/manipulation/place/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] mends the nerves and lenses in [target]'s with \the [tool]." , \ - "You mend the nerves and lenses in [target]'s with \the [tool].") - - I = tool - user.drop_from_inventory(tool) - I.insert_organ(target) - user.visible_message(" [user] has transplanted \the [tool] into [target].", \ - " You have transplanted \the [tool] into [target].") - I.status &= ~ORGAN_CUT_AWAY - -/datum/surgery_step/eye/manipulation/place/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/internal/eyes/IO = target.organs_by_name[O_EYES] - var/obj/item/organ/external/BP = target.get_bodypart(target_zone) - user.visible_message("[user]'s hand slips, stabbing \the [tool] into [target]'s eye!", \ - "Your hand slips, stabbing \the [tool] into [target]'s eye!") - BP.take_damage(10, 0, DAM_SHARP|DAM_EDGE, tool) - if(IO) - IO.take_damage(5, 0) -*/ ////////////////////////////////////////////////////////////////// // EYE SURGERY manipulation for eyes // ////////////////////////////////////////////////////////////////// diff --git a/taucetistation.dme b/taucetistation.dme index 833f1adc8bb0..ca542925a582 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -2461,7 +2461,6 @@ #include "code\modules\supermatter\LaserComputer.dm" #include "code\modules\supermatter\supermatter.dm" #include "code\modules\supermatter\ZeroPointLaser.dm" -#include "code\modules\surgery\appendix.dm" #include "code\modules\surgery\bones.dm" #include "code\modules\surgery\braincore.dm" #include "code\modules\surgery\eye.dm" From 6599d9d3253ee08466ec00e3b4f64e1e2d0cfa4a Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 7 Dec 2024 04:20:57 +0400 Subject: [PATCH 14/32] optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Прок get_organs_by_name взамен двух плохих проков --- code/modules/surgery/eye.dm | 2 +- code/modules/surgery/organs/organ_helpers.dm | 7 +------ code/modules/surgery/organs/organ_internal.dm | 4 ++-- code/modules/surgery/organs_internal.dm | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index b7ab3d33c661..608c809dcf45 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -178,7 +178,7 @@ user.visible_message ( " \The [I] is in no state to be transplanted.") return FALSE - if(target.get_int_organ_by_name(I)) + if(target.get_organ_by_name(I)) user.visible_message ( " \The [target] already has [I].") return FALSE diff --git a/code/modules/surgery/organs/organ_helpers.dm b/code/modules/surgery/organs/organ_helpers.dm index 6972309acc03..56bc9683f91d 100644 --- a/code/modules/surgery/organs/organ_helpers.dm +++ b/code/modules/surgery/organs/organ_helpers.dm @@ -1,8 +1,3 @@ -/mob/proc/get_int_organ(typepath) //int stands for internal - return -/mob/living/carbon/human/get_int_organ(typepath) - return (locate(typepath) in organs_by_name) - -/mob/living/carbon/human/proc/get_int_organ_by_name(tag_to_check) +/mob/living/carbon/human/proc/get_organ_by_name(tag_to_check) return organs_by_name[tag_to_check] diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 0a066d0462f1..4489263c2813 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -66,7 +66,7 @@ /obj/item/organ/internal/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) ..() - var/obj/item/organ/internal/replaced = H.get_int_organ_by_name(organ_tag) + var/obj/item/organ/internal/replaced = H.get_organ_by_name(organ_tag) if(replaced) replaced.remove(H, special = 1) @@ -780,7 +780,7 @@ ..() /mob/living/carbon/human/proc/update_eyes() - var/obj/item/organ/internal/eyes/eyes = get_int_organ(/obj/item/organ/internal/eyes) + var/obj/item/organ/internal/eyes/eyes = get_organ_by_name(O_EYES) if(eyes) eyes.update_colour() regenerate_icons() diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 298c66f92ce9..008c3ad940b1 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -46,7 +46,7 @@ user.visible_message ( " \The [I] is in no state to be transplanted.") return FALSE - if(target.get_int_organ(I)) + if(target.get_organ_by_name(I)) user.visible_message ( " \The [target] already has [I].") return FALSE From e29a026224b88d351f243341731dab40f1420e5b Mon Sep 17 00:00:00 2001 From: Triff Date: Sat, 7 Dec 2024 04:23:11 +0400 Subject: [PATCH 15/32] More_optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get_organ удалён и заменён на get_bodypart, органы воксов теперь не подвержены инфекциям, удалена переменная special --- .../mob/living/carbon/human/human_damage.dm | 7 --- code/modules/mob/living/carbon/human/life.dm | 2 +- code/modules/surgery/organs/organ.dm | 7 +-- code/modules/surgery/organs/organ_external.dm | 2 +- code/modules/surgery/organs/organ_internal.dm | 55 ++++++++++--------- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index e5b88d9cbb7e..f30f79f31d9f 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -22,13 +22,6 @@ ChangeToHusk() return -/mob/living/carbon/human/proc/get_organ(zone) - if(!zone) - zone = BP_CHEST - if(zone in list(O_EYES, O_MOUTH)) - zone = BP_HEAD - - return bodyparts[zone] // ============================================= diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index abeb61553848..444a33092395 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -332,7 +332,7 @@ var/global/list/tourette_bad_words= list( BP.add_autopsy_data("Radiation Poisoning", damage) /mob/living/carbon/human/is_cant_breathe() - var/lungs = get_int_organ_by_name(O_LUNGS) + var/lungs = get_organ_by_name(O_LUNGS) return ((handle_drowning() || health < config.health_threshold_crit) || !lungs) && !(reagents.has_reagent("inaprovaline") || HAS_TRAIT(src, TRAIT_AV)) /mob/living/carbon/human/handle_external_pre_breathing(datum/gas_mixture/breath) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 85e6d9b2ec02..c2d7387edd6a 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -36,7 +36,7 @@ owner = null return ..() -/obj/item/organ/proc/remove(mob/living/user,special = 0) +/obj/item/organ/proc/remove(mob/living/user) if(!istype(owner)) return @@ -89,7 +89,7 @@ /obj/item/organ/proc/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) set_owner(H, S) - STOP_PROCESSING(SSobj, src) + START_PROCESSING(SSobj, src) if(parent_bodypart) parent = owner.bodyparts_by_name[parent_bodypart] @@ -101,7 +101,7 @@ owner = target STOP_PROCESSING(SSobj, src) parent_bodypart.bodypart_organs |= src - if (!target.get_int_organ(src)) + if (!target.get_organ_by_name(src)) target.organs_by_name += src target.organs += src src.loc = target @@ -195,7 +195,6 @@ //processing organs is pretty cheap, do that first. for(var/obj/item/organ/internal/IO in organs) IO.process() - IO.on_life() handle_stance() diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index b2259131efbb..8bea8b0fcbe1 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -76,7 +76,7 @@ if(bodypart_organs) for(var/obj/item/organ/internal/O in bodypart_organs) bodypart_organs -= O - O.remove(owner,special = 1) + O.remove(owner) QDEL_NULL(controller) if(owner) owner.bodyparts -= src diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 4489263c2813..649e5fb9d5a5 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -42,7 +42,7 @@ if(owner && vital) owner.death() -/obj/item/organ/internal/remove(mob/living/carbon/human/M, special = 0) +/obj/item/organ/internal/remove(mob/living/carbon/human/M) owner = null STOP_PROCESSING(SSobj, src) if(M) @@ -50,13 +50,13 @@ if(M.organs_by_name[organ_tag] == src) M.organs_by_name -= organ_tag - if(vital && !special) + if(vital) if(M.stat != DEAD)//safety check! M.death() if(ishuman(M)) var/mob/living/carbon/human/H = M - var/obj/item/organ/external/parent = H.get_organ(check_zone(parent_bodypart)) + var/obj/item/organ/external/parent = H.get_bodypart(check_zone(parent_bodypart)) if(!istype(parent)) return else @@ -68,12 +68,14 @@ var/obj/item/organ/internal/replaced = H.get_organ_by_name(organ_tag) if(replaced) - replaced.remove(H, special = 1) + replaced.remove(H) owner.organs += src owner.organs_by_name[organ_tag] = src + START_PROCESSING(SSobj, src) + if(parent) parent.bodypart_organs += src @@ -91,7 +93,7 @@ //only show this if the organ is not robotic if(owner && parent_bodypart && amount > 0) - var/obj/item/organ/external/parent = owner.get_organ(parent_bodypart) + var/obj/item/organ/external/parent = owner.get_bodypart(parent_bodypart) if(parent && !silent) owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) if(damage >= max_damage) @@ -106,9 +108,6 @@ /obj/item/organ/internal/proc/is_broken() return damage >= min_broken_damage -/obj/item/organ/internal/proc/on_life() - return - /obj/item/organ/internal/process() //Process infections @@ -187,7 +186,7 @@ icon_state = "[base_icon_state]-off" -/obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M, special = 0) +/obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M) ..() beating = 1 owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) @@ -203,7 +202,7 @@ take_damage(1, 0) fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE) -/obj/item/organ/internal/heart/remove(mob/living/carbon/M, special = 0) +/obj/item/organ/internal/heart/remove(mob/living/carbon/M) ..() VARSET_IN(src, beating, 0, 100 SECONDS) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2 MINUTES) @@ -274,6 +273,7 @@ icon = 'icons/obj/special_organs/vox.dmi' parent_bodypart = BP_GROIN compability = list(VOX) + sterile = TRUE /obj/item/organ/internal/heart/tajaran name = "tajaran heart" @@ -313,6 +313,7 @@ parent_bodypart = BP_GROIN icon = 'icons/obj/special_organs/vox.dmi' compability = list(VOX) + sterile = TRUE /obj/item/organ/internal/lungs/tajaran name = "tajaran lungs" @@ -433,6 +434,7 @@ icon = 'icons/obj/special_organs/vox.dmi' compability = list(VOX) alcohol_intensity = 1.6 + sterile = TRUE /obj/item/organ/internal/liver/tajaran name = "tajaran liver" @@ -581,6 +583,7 @@ cases = list("фильтрующий пузырь", "фильтрующего пузыря", "фильтрующему пузырю", "фильтрующий пузырь", "фильтрующим пузырём", "фильтрующем пузыре") icon = 'icons/obj/special_organs/vox.dmi' compability = list(VOX) + sterile = TRUE /obj/item/organ/internal/kidneys/tajaran name = "tajaran kidneys" @@ -697,22 +700,22 @@ icon_state = "cortical-stack" item_state_world = "cortical-stack_world" compability = list(VOX) + sterile = TRUE /obj/item/organ/internal/brain/skrell icon = 'icons/obj/special_organs/skrell.dmi' desc = "A brain with a odd division in the middle." -/obj/item/organ/internal/brain/remove(mob/living/user,special = 0) +/obj/item/organ/internal/brain/remove(mob/living/user) if(!owner) return ..() // Probably a redundant removal; just bail var/obj/item/organ/internal/brain/B = src - if(!special) - var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() + var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() - if(borer) - borer.detatch() //Should remove borer if the brain is removed - RR + if(borer) + borer.detatch() //Should remove borer if the brain is removed - RR - B.transfer_identity(user) + B.transfer_identity(user) if(ishuman(owner)) var/mob/living/carbon/human/H = owner @@ -730,18 +733,17 @@ var/obj/item/device/mmi/posibrain/stored_mmi -/obj/item/organ/internal/brain/ipc/remove(mob/living/carbon/human/M, special = 0) - if(!special) - var/brain_type = /obj/item/device/mmi/posibrain +/obj/item/organ/internal/brain/ipc/remove(mob/living/carbon/human/M) + var/brain_type = /obj/item/device/mmi/posibrain - var/obj/item/organ/external/BP = owner.get_bodypart(parent_bodypart) - if(istype(BP, /obj/item/organ/external/chest/robot/ipc)) - var/obj/item/organ/external/chest/robot/ipc/I = BP - brain_type = I.posibrain_type + var/obj/item/organ/external/BP = owner.get_bodypart(parent_bodypart) + if(istype(BP, /obj/item/organ/external/chest/robot/ipc)) + var/obj/item/organ/external/chest/robot/ipc/I = BP + brain_type = I.posibrain_type - var/obj/item/device/mmi/P = new brain_type(owner.loc) - P.transfer_identity(owner) + var/obj/item/device/mmi/P = new brain_type(owner.loc) + P.transfer_identity(owner) /obj/item/organ/internal/brain/abomination @@ -769,7 +771,7 @@ owner.b_eyes ? owner.b_eyes : 0 ) -/obj/item/organ/internal/eyes/insert_organ(mob/living/carbon/human/M, special = 0) +/obj/item/organ/internal/eyes/insert_organ(mob/living/carbon/human/M) // Apply our eye colour to the target. if(istype(M) && eye_colour) var/mob/living/carbon/human/eyes = M @@ -799,6 +801,7 @@ /obj/item/organ/internal/eyes/vox name = "vox eyeballs" icon = 'icons/obj/special_organs/vox.dmi' + sterile = TRUE /obj/item/organ/internal/eyes/skrell name = "skrell eyeballs" From d84e2bf316a20860661dcadb3f660464979a5d0f Mon Sep 17 00:00:00 2001 From: Triff Date: Tue, 10 Dec 2024 02:10:09 +0400 Subject: [PATCH 16/32] Dinamic_heart_is_real MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сердце теперь ответственно за кровь, сердцебиение, пульс. В телах есть "насыщение кислородом" без которого мозг умирает, а без крови человек не умирает, а становиться беспомощным. А ещё кровь теперь генерируется с помощью печени, а без сердца человек ещё живёт... Некоторое время. Дальше лёгкие... yay... --- code/__DEFINES/mob.dm | 9 + code/modules/mob/living/carbon/human/human.dm | 6 + code/modules/mob/living/carbon/human/life.dm | 75 +---- code/modules/mob/living/carbon/species.dm | 8 + code/modules/surgery/organs/blood.dm | 227 ++++--------- code/modules/surgery/organs/heart.dm | 305 ++++++++++++++++++ code/modules/surgery/organs/organ_internal.dm | 238 ++++++-------- taucetistation.dme | 1 + 8 files changed, 500 insertions(+), 369 deletions(-) create mode 100644 code/modules/surgery/organs/heart.dm diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 4cb7bc1c6c21..eae3473c688b 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -277,3 +277,12 @@ #define TRAUMATIC_SHOCK_MIND_SHATTERING 80 #define TRAUMATIC_SHOCK_CRITICAL 100 +// Initial blood volume. +#define SPECIES_BLOOD_DEFAULT 560 + +//Blood levels. These are percentages based on the species blood_volume far. +#define BLOOD_VOLUME_FULL_P 100 +#define BLOOD_VOLUME_SAFE_P 85 +#define BLOOD_VOLUME_OKAY_P 70 +#define BLOOD_VOLUME_BAD_P 60 +#define BLOOD_VOLUME_SURVIVE_P 30 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index ec5ecdda092b..298db245c7f6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1816,6 +1816,12 @@ I = update_height(I) flick_overlay(I, viewing, anim_duration) +/mob/living/carbon/human/proc/need_breathe() + if(!species.breathing_organ && should_have_organ(species.breathing_organ)) + return 1 + else + return 0 + /mob/living/carbon/human/proc/should_have_organ(organ_check) var/obj/item/organ/external/BP diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 0b9ab5c0d7ad..c0c1f6340c4e 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -35,6 +35,8 @@ voice = GetVoice() + var/obj/item/organ/internal/heart/heart = organs_by_name[O_HEART] + //No need to update all of these procs if the guy is dead. if(stat != DEAD && !IS_IN_STASIS(src)) if(SSmobs.times_fired%4==2 || failed_last_breath || (health < config.health_threshold_crit)) //First, resolve location and get a breath @@ -62,13 +64,12 @@ handle_pain() - handle_heart_beat() //This block was in handle_regular_status_updates under != DEAD stabilize_body_temperature() //Body temperature adjusts itself handle_bodyparts() //Optimized. - if(!species.flags[NO_BLOOD] && bodytemperature >= 170) - handle_blood() + if(!species.flags[NO_BLOOD] && heart && bodytemperature >= 170) + heart.handle_blood() handle_drunkenness() @@ -95,7 +96,8 @@ if(species) species.on_life(src) - pulse = handle_pulse() + if(istype(heart) && !(heart.status & ORGAN_DEAD)) + pulse = heart.handle_pulse() if(client) handle_alerts() @@ -1210,71 +1212,6 @@ var/global/list/tourette_bad_words= list( drop_from_inventory(l_hand) drop_from_inventory(r_hand) -/mob/living/carbon/human/proc/handle_heart_beat() - - if(pulse == PULSE_NONE) return - - if(pulse == PULSE_2FAST || traumatic_shock >= TRAUMATIC_SHOCK_INTENSE || isspaceturf(get_turf(src))) - - var/temp = (5 - pulse)/2 - - if(heart_beat >= temp) - heart_beat = 0 - playsound_local(null, 'sound/effects/singlebeat.ogg', VOL_EFFECTS_MASTER, null, FALSE) - else if(temp != 0) - heart_beat++ - -/mob/living/carbon/human/proc/handle_pulse() - - if(life_tick % 5) - return pulse //update pulse every 5 life ticks (~1 tick/sec, depending on server load) - - if(species && species.flags[NO_BLOOD]) - return PULSE_NONE //No blood, no pulse. - - if(HAS_TRAIT(src, TRAIT_CPB)) - return PULSE_NORM - - if(stat == DEAD) - return PULSE_NONE //that's it, you're dead, nothing can influence your pulse - - var/obj/item/organ/internal/heart/IO = organs_by_name[O_HEART] - if(life_tick % 10) - switch(IO.heart_status) - if(HEART_FAILURE) - to_chat(src, "Your feel a prick in your heart!") - apply_effect(5,AGONY,0) - return PULSE_NONE - if(HEART_FIBR) - to_chat(src, "Your heart hurts a little.") - playsound_local(null, 'sound/machines/cardio/pulse_fibrillation.ogg', VOL_EFFECTS_MASTER, vary = FALSE) - apply_effect(1,AGONY,0) - return PULSE_SLOW - - var/temp = PULSE_NORM - - if(blood_amount() <= BLOOD_VOLUME_BAD) //how much blood do we have - temp = PULSE_THREADY //not enough :( - - if(status_flags & FAKEDEATH) - temp = PULSE_NONE //pretend that we're dead. unlike actual death, can be inflienced by meds - - //handles different chems' influence on pulse - for(var/datum/reagent/R in reagents.reagent_list) - if(R.id in bradycardics) - if(temp <= PULSE_THREADY && temp >= PULSE_NORM) - temp-- - if(R.id in tachycardics) - if(temp <= PULSE_FAST && temp >= PULSE_NONE) - temp++ - if(R.id in heartstopper) //To avoid using fakedeath - temp = PULSE_NONE - if(R.id in cheartstopper) //Conditional heart-stoppage - if(R.volume >= R.overdose) - temp = PULSE_NONE - - return temp - /mob/living/carbon/human/handle_nutrition() . = ..() if(nutrition > NUTRITION_LEVEL_FAT) diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 9b60a11204c8..9bfbc7af6b2a 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -26,6 +26,7 @@ var/datum/action/innate/race/race_ability = null var/list/race_verbs = list() var/list/race_traits = list() + var/blood_oxy = 1 var/brute_mod = 1 // Physical damage multiplier (0 == immunity). var/burn_mod = 1 // Burn damage multiplier. var/oxy_mod = 1 // Oxyloss multiplier. @@ -51,6 +52,10 @@ // Is used when a bodypart of this race is butchered. Otherwise there are overrides for flesh, robot, and bone bodyparts. var/list/bodypart_butcher_results + var/breathing_organ // If set, this organ is required for breathing. Defaults to "lungs" if the species has them. + + var/blood_volume = SPECIES_BLOOD_DEFAULT // Initial blood volume. + var/list/restricted_inventory_slots = list() // Slots that the race does not have due to biological differences. var/inhale_type = "oxygen" // Non-oxygen gas breathed, if any. @@ -201,6 +206,9 @@ if(!has_organ[O_HEART]) flags[NO_BLOOD] = TRUE // this status also uncaps vital body parts damage, since such species otherwise will be very hard to kill. + if(!breathing_organ && has_organ[O_LUNGS]) + breathing_organ = O_LUNGS + /datum/species/proc/can_be_role(role) if(!prohibit_roles) return TRUE diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index c173b1da0112..4b57755a264a 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -85,170 +85,6 @@ var/global/const/BLOOD_VOLUME_SURVIVE = 122 /mob/living/carbon/human/proc/blood_trans_to(obj/target, amount = 1) return vessel.trans_to(target, amount) -// Takes care blood loss and regeneration: -/mob/living/carbon/var/tmp/next_blood_squirt = 0 // until this moved to heart or not... - -/mob/living/carbon/human/proc/handle_blood() - var/blood_total = blood_amount(exact = TRUE) - - // Blood regeneration if there is some space: - if(blood_total < BLOOD_VOLUME_NORMAL) - var/change_volume = 0.1 // Regenerate blood VERY slowly - if (reagents.has_reagent("nutriment")) // Getting food speeds it up - change_volume += 0.4 - reagents.remove_reagent("nutriment", 0.1) - if (reagents.has_reagent("copper") && get_species(src) == SKRELL) // skrell blood base on copper - change_volume += 1 - reagents.remove_reagent("copper", 0.1) - if (reagents.has_reagent("iron")) // Hematogen candy anyone? - if(get_species(src) == SKRELL) // a little more toxins when trying to restore blood with iron - var/mob/living/carbon/human/H = src - H.adjustToxLoss(1) - else - change_volume += 0.8 - reagents.remove_reagent("iron", 0.1) - blood_add(change_volume) - blood_total += change_volume - - // Damaged heart virtually reduces the blood volume, as the blood isn't - // being pumped properly anymore. - var/obj/item/organ/internal/heart/IO = organs_by_name[O_HEART] - if(!IO) - return - - var/blood_volume = blood_total // Blood volume adjusted by heart - - if(IO.damage > 1 && IO.damage < IO.min_bruised_damage || IO.heart_status == HEART_FIBR) - blood_volume *= 0.8 - else if(IO.damage >= IO.min_bruised_damage && IO.damage < IO.min_broken_damage) - blood_volume *= 0.6 - else if((IO.damage >= IO.min_broken_damage && IO.damage < INFINITY) || IO.heart_status == HEART_FAILURE) - blood_volume *= 0.3 - - // Effects of bloodloss - if(!HAS_TRAIT(src, TRAIT_CPB)) - switch(blood_volume) - if(BLOOD_VOLUME_SAFE to 10000) - if(pale) - pale = FALSE - update_body() - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - if(!pale) - pale = TRUE - update_body() - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel [word]") - if(prob(1)) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel [word]") - if(oxyloss < 20) - oxyloss += 3 - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - if(!pale) - pale = TRUE - update_body() - blurEyes(6) - if(oxyloss < 50) - oxyloss += 10 - oxyloss += 1 - if(prob(15)) - Paralyse(rand(1,3)) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel extremely [word]") - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - oxyloss += 5 - toxloss += 3 - if(prob(15)) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel extremely [word]") - if(0 to BLOOD_VOLUME_SURVIVE) - if(!iszombie(src)) // zombies dont care about blood - death() - - // Without enough blood you slowly go hungry. - if(blood_volume < BLOOD_VOLUME_SAFE) - if(nutrition >= 300) - nutrition -= 10 - else if(nutrition >= 200) - nutrition -= 3 - - if(reagents.has_reagent("metatrombine")) - return - - // Bleeding out: - var/blood_max = 0 - var/list/do_spray = list() - for(var/obj/item/organ/external/BP in bodyparts) - if(BP.is_robotic_part()) - continue - - var/open_wound - if(BP.status & ORGAN_BLEEDING) - if(BP.open) - blood_max += 2 // Yer stomach is cut open - if(HAS_TRAIT(src, TRAIT_HEMOPHILIAC)) - blood_max += 4 - - for(var/datum/wound/W in BP.wounds) - if(!open_wound && (W.damage_type == CUT || W.damage_type == PIERCE) && W.damage && !W.is_treated()) - open_wound = TRUE - - if(W.bleeding()) - if(BP.applied_pressure) - if(ishuman(BP.applied_pressure)) - var/mob/living/carbon/human/H = BP.applied_pressure - H.bloody_hands(src, 0) - // somehow you can apply pressure to every wound on the organ at the same time - // you're basically forced to do nothing at all, so let's make it pretty effective - var/min_eff_damage = max(0, W.damage - 10) / 6 // still want a little bit to drip out, for effect - blood_max += max(min_eff_damage, W.damage - 30) / 40 - else - blood_max += W.damage / 40 - - if(BP.status & ORGAN_ARTERY_CUT) - var/bleed_amount = blood_total / (BP.applied_pressure ? 500 : 250) * BP.arterial_bleed_severity - if(bleed_amount) - if(open_wound) - blood_max += bleed_amount - do_spray += "the [BP.artery_name] in \the [src]'s [BP.name]" - else - blood_remove(bleed_amount) - playsound(src, 'sound/effects/ArterialBleed.ogg', VOL_EFFECTS_MASTER) - - if(blood_max == 0) // so... there is no blood loss, lets stop right here. - return - - switch(pulse) - if(PULSE_NONE) - blood_max *= 0.2 // simulates passive blood loss. - if(PULSE_SLOW) - blood_max *= 0.8 - if(PULSE_FAST) - blood_max *= 1.25 - if(PULSE_2FAST) - blood_max *= 1.5 - if(PULSE_THREADY) - blood_max *= 1.8 - - if(reagents.has_reagent("inaprovaline")) - blood_max *= 0.8 - - if(!isturf(loc)) // No floor to drip on - blood_remove(blood_max) - return - - if(world.time >= next_blood_squirt && do_spray.len) // It becomes very spammy otherwise. Arterial bleeding will still happen outside of this block, just not the squirt effect. - if(prob(50)) // added 50 prob for message and halved delay between squit effects (difference between us and Bay12), lets see how this will be on live server. - visible_message("Blood squirts from [pick(do_spray)]!") - next_blood_squirt = world.time + 50 - var/turf/sprayloc = get_turf(src) - var/third = CEIL(blood_max / 3) - drip(third, sprayloc) - blood_max -= third - if(blood_max > 0) - blood_squirt(blood_max, sprayloc) - else - drip(blood_max) // No fancy shooting of blood, just bleeding // Makes a blood drop, leaking certain amount of blood from the mob /mob/living/carbon/human/proc/drip(amt, tar = src, ddir) @@ -503,3 +339,66 @@ var/global/const/BLOOD_VOLUME_SURVIVE = 122 ) ) return blood_recipient_can_receive[blood_recipient][blood_donor] + + +//Percentage of maximum blood volume. +/mob/living/carbon/human/proc/get_blood_volume() + return round((vessel.get_reagent_amount("blood")/species.blood_volume)*100) + +//Percentage of maximum blood volume, affected by the condition of circulation organs +/mob/living/carbon/human/proc/get_blood_circulation() + var/obj/item/organ/internal/heart/heart = organs_by_name[O_HEART] + var/blood_volume = get_blood_volume() + if(!heart) + return 0.25 * blood_volume + + var/recent_pump = LAZYACCESS(heart.external_pump, 1) > world.time - (20 SECONDS) + var/pulse_mod = 1 + if((status_flags & FAKEDEATH) || heart.is_robotic()) + pulse_mod = 1 + else + switch(heart.pulse) + if(PULSE_NONE) + if(recent_pump) + pulse_mod = LAZYACCESS(heart.external_pump, 2) + else + pulse_mod *= 0.25 + if(PULSE_SLOW) + pulse_mod *= 0.9 + if(PULSE_FAST) + pulse_mod *= 1.1 + if(PULSE_2FAST, PULSE_THREADY) + pulse_mod *= 1.25 + blood_volume *= pulse_mod + + var/min_efficiency = recent_pump ? 0.5 : 0.3 + blood_volume *= max(min_efficiency, (1-(heart.damage / heart.max_damage))) + +/*Need help with it + if(owner.reagents.has_reagent("metatrombine")) + blood_volume *= max(0, 1-chem_effects[CE_BLOCKAGE]) +*/ + return min(blood_volume, 100) + +//Whether the species needs blood to carry oxygen. Used in get_blood_oxygenation and may be expanded based on blood rather than species in the future. +/mob/living/carbon/human/proc/blood_carries_oxygen() + return species.blood_oxy + +//Percentage of maximum blood volume, affected by the condition of circulation organs, affected by the oxygen loss. What ultimately matters for brain +/mob/living/carbon/human/proc/get_blood_oxygenation() + var/blood_volume = get_blood_circulation() + if(blood_carries_oxygen()) + if(!need_breathe()) + return blood_volume + else + blood_volume = 100 + + var/blood_volume_mod = max(0, 1 - getOxyLoss()/(species.total_health/2)) + var/oxygenated_mult = 0 + if(reagents.has_reagent("dexalin")) // Dexalin. + oxygenated_mult = 0.5 + else if(reagents.has_reagent("dexalinp")) // Dexplus. + oxygenated_mult = 0.8 + blood_volume_mod = blood_volume_mod + oxygenated_mult - (blood_volume_mod * oxygenated_mult) + blood_volume = blood_volume * blood_volume_mod + return min(blood_volume, 100) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm new file mode 100644 index 000000000000..49c66c21717a --- /dev/null +++ b/code/modules/surgery/organs/heart.dm @@ -0,0 +1,305 @@ +/obj/item/organ/internal/heart + name = "heart" + icon = 'icons/obj/surgery.dmi' + icon_state = "heart-on" + item_state_world = "heart-on_world" + cases = list("сердце", "сердца", "сердцу", "сердце", "сердцем", "сердце") + organ_tag = O_HEART + parent_bodypart = BP_CHEST + max_damage = 45 + var/heart_beat + var/pulse = PULSE_NORM + var/base_icon_state = "heart" + var/heart_status = HEART_NORMAL + var/fibrillation_timer_id = null + var/failing_interval = 1 MINUTE + var/beating = 0 + + var/list/external_pump + + compability = list(HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/heart/update_icon() + if(beating) + item_state_world = "[base_icon_state]-on_world" + icon_state = "[base_icon_state]-on" + else + item_state_world = "[base_icon_state]-off_world" + icon_state = "[base_icon_state]-off" + +//work? + +/obj/item/organ/internal/heart/process() + if(owner) + handle_pulse() + if(pulse) + handle_heart_beat() + handle_blood() + ..() + +/obj/item/organ/internal/heart/proc/handle_pulse() + + if(is_robotic(src)) + pulse = PULSE_NONE //that's it, you're dead (or your metal heart is), nothing can influence your pulse + return + + if(owner.life_tick % 5) + return pulse //update pulse every 5 life ticks (~1 tick/sec, depending on server load) + + if(owner.species && owner.species.flags[NO_BLOOD]) + return PULSE_NONE //No blood, no pulse. + + if(HAS_TRAIT(owner, TRAIT_CPB)) + return PULSE_NORM + + if(owner.stat == DEAD) + return PULSE_NONE //that's it, you're dead, nothing can influence your pulse + + if(owner.life_tick % 10) + switch(heart_status) + if(HEART_FAILURE) + to_chat(src, "Your feel a prick in your heart!") + owner.apply_effect(5,AGONY,0) + return PULSE_NONE + if(HEART_FIBR) + to_chat(src, "Your heart hurts a little.") + owner.playsound_local(null, 'sound/machines/cardio/pulse_fibrillation.ogg', VOL_EFFECTS_MASTER, vary = FALSE) + owner.apply_effect(1,AGONY,0) + return PULSE_SLOW + + var/temp = PULSE_NORM + + if(owner.blood_amount() <= BLOOD_VOLUME_BAD) //how much blood do we have + temp = PULSE_THREADY //not enough :( + + if(owner.status_flags & FAKEDEATH) + temp = PULSE_NONE //pretend that we're dead. unlike actual death, can be inflienced by meds + + //handles different chems' influence on pulse + for(var/datum/reagent/R in owner.reagents.reagent_list) + if(R.id in bradycardics) + if(temp <= PULSE_THREADY && temp >= PULSE_NORM) + temp-- + if(R.id in tachycardics) + if(temp <= PULSE_FAST && temp >= PULSE_NONE) + temp++ + if(R.id in heartstopper) //To avoid using fakedeath + temp = PULSE_NONE + if(R.id in cheartstopper) //Conditional heart-stoppage + if(R.volume >= R.overdose) + temp = PULSE_NONE + + return temp + +// Takes care blood loss and regeneration: +/obj/item/organ/internal/heart/var/tmp/next_blood_squirt = 0 // until this moved to heart or not... + +/obj/item/organ/internal/heart/proc/handle_blood() + + if(!owner.species.flags[NO_BLOOD] && owner.bodytemperature >= 170 || owner.stat == DEAD || !owner) + + if(owner.reagents.has_reagent("metatrombine")) + return + + // Bleeding out: + var/blood_max = 0 + var/list/do_spray = list() + for(var/obj/item/organ/external/BP in owner.bodyparts) + if(BP.is_robotic_part()) + continue + + var/open_wound + if(BP.status & ORGAN_BLEEDING) + if(BP.open) + blood_max += 2 // Yer stomach is cut open + if(HAS_TRAIT(src, TRAIT_HEMOPHILIAC)) + blood_max += 4 + + for(var/datum/wound/W in BP.wounds) + if(!open_wound && (W.damage_type == CUT || W.damage_type == PIERCE) && W.damage && !W.is_treated()) + open_wound = TRUE + + if(W.bleeding()) + if(BP.applied_pressure) + if(ishuman(BP.applied_pressure)) + var/mob/living/carbon/human/H = BP.applied_pressure + H.bloody_hands(src, 0) + // somehow you can apply pressure to every wound on the organ at the same time + // you're basically forced to do nothing at all, so let's make it pretty effective + var/min_eff_damage = max(0, W.damage - 10) / 6 // still want a little bit to drip out, for effect + blood_max += max(min_eff_damage, W.damage - 30) / 40 + else + blood_max += W.damage / 40 + + if(BP.status & ORGAN_ARTERY_CUT) + var/bleed_amount = owner.blood_amount() / (BP.applied_pressure ? 500 : 250) * BP.arterial_bleed_severity + if(bleed_amount) + if(open_wound) + blood_max += bleed_amount + do_spray += "the [BP.artery_name] in \the [src]'s [BP.name]" + else + owner.blood_remove(bleed_amount) + playsound(src, 'sound/effects/ArterialBleed.ogg', VOL_EFFECTS_MASTER) + + if(blood_max == 0) // so... there is no blood loss, lets stop right here. + return + + switch(pulse) + if(PULSE_NONE) + blood_max *= 0.2 // simulates passive blood loss. + if(PULSE_SLOW) + blood_max *= 0.8 + if(PULSE_FAST) + blood_max *= 1.25 + if(PULSE_2FAST) + blood_max *= 1.5 + if(PULSE_THREADY) + blood_max *= 1.8 + + if(reagents.has_reagent("inaprovaline")) + blood_max *= 0.8 + + if(!isturf(loc)) // No floor to drip on + owner.blood_remove(blood_max) + return + + if(world.time >= next_blood_squirt && do_spray.len) // It becomes very spammy otherwise. Arterial bleeding will still happen outside of this block, just not the squirt effect. + if(prob(50)) // added 50 prob for message and halved delay between squit effects (difference between us and Bay12), lets see how this will be on live server. + visible_message("Blood squirts from [pick(do_spray)]!") + next_blood_squirt = world.time + 50 + var/turf/sprayloc = get_turf(src) + var/third = CEIL(blood_max / 3) + owner.drip(third, sprayloc) + blood_max -= third + if(blood_max > 0) + owner.blood_squirt(blood_max, sprayloc) + else + owner.drip(blood_max) // No fancy shooting of blood, just bleeding + + +//work! +/obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M) + ..() + beating = 1 + owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) + + +/obj/item/organ/internal/heart/proc/heart_stop() + if(!owner.reagents.has_reagent("inaprovaline") || owner.stat == DEAD) + heart_status = HEART_FAILURE + deltimer(fibrillation_timer_id) + fibrillation_timer_id = null + owner.metabolism_factor.AddModifier("Heart", multiple = 0.0) + else + take_damage(1, 0) + fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE) + +/obj/item/organ/internal/heart/remove(mob/living/carbon/M) + ..() + VARSET_IN(src, beating, 0, 100 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2 MINUTES) + + +/obj/item/organ/internal/heart/proc/heart_fibrillate() + heart_status = HEART_FIBR + if(HAS_TRAIT(owner, TRAIT_FAT)) + failing_interval = 30 SECONDS + fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), failing_interval, TIMER_UNIQUE|TIMER_STOPPABLE) + owner.metabolism_factor.AddModifier("Heart", multiple = 0.5) + +/obj/item/organ/internal/heart/proc/heart_normalize() + heart_status = HEART_NORMAL + deltimer(fibrillation_timer_id) + fibrillation_timer_id = null + owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) + + +/obj/item/organ/internal/heart/proc/handle_heart_beat() + + if(pulse == PULSE_NONE) return + + if(pulse == PULSE_2FAST) + + var/temp = (5 - pulse)/2 + + if(heart_beat >= temp) + heart_beat = 0 + owner.playsound_local(null, 'sound/effects/singlebeat.ogg', VOL_EFFECTS_MASTER, null, FALSE) + else if(temp != 0) + heart_beat++ + +/obj/item/organ/internal/heart/cybernetic + name = "cybernetic heart" + desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." + icon_state = "heart-prosthetic" + item_state_world = "heart-prosthetic_world" + base_icon_state = "heart-prosthetic" + dead_icon = "heart-prosthetic-off" + status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/heart/ipc + name = "cooling pump" + cases = list("помпа системы охлаждения", "помпы системы охлаждения", "помпе системы охлаждения", "помпу системы охлаждения", "помпой системы охлаждения", "помпой системы охлаждения") + + var/pumping_rate = 5 + var/bruised_loss = 3 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/device.dmi' + icon_state = "miniaturesuitcooler0" + + +/obj/item/organ/internal/heart/ipc/update_icon() + if(beating) + icon_state = "miniaturesuitcooler0" + item_state_world = "miniaturesuitcooler0" + else + icon_state = "miniaturesuitcooler0" + item_state_world = "miniaturesuitcooler0" + +/obj/item/organ/internal/heart/ipc/process() + if(owner.nutrition < 1) + return + if(is_broken()) + return + + var/obj/item/organ/internal/lungs/ipc/lungs = owner.organs_by_name[O_LUNGS] + if(!istype(lungs)) + return + + var/pumping_volume = pumping_rate + if(is_bruised()) + pumping_volume -= bruised_loss + + if(pumping_volume > 0) + lungs.add_refrigerant(pumping_volume) + +/obj/item/organ/internal/heart/vox + name = "vox heart" + icon = 'icons/obj/special_organs/vox.dmi' + parent_bodypart = BP_GROIN + compability = list(VOX) + sterile = TRUE + +/obj/item/organ/internal/heart/tajaran + name = "tajaran heart" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/heart/unathi + name = "unathi heart" + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A large looking heart." + +/obj/item/organ/internal/heart/skrell + name = "skrell heart" + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "A stream lined heart." + +/obj/item/organ/internal/heart/diona + name = "circulatory siphonostele" + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 649e5fb9d5a5..81ca8c1ba6df 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -160,142 +160,6 @@ ORGANS DEFINES ****************************************************/ -/obj/item/organ/internal/heart - name = "heart" - icon = 'icons/obj/surgery.dmi' - icon_state = "heart-on" - item_state_world = "heart-on_world" - cases = list("сердце", "сердца", "сердцу", "сердце", "сердцем", "сердце") - organ_tag = O_HEART - vital = TRUE - parent_bodypart = BP_CHEST - var/base_icon_state = "heart" - var/heart_status = HEART_NORMAL - var/fibrillation_timer_id = null - var/failing_interval = 1 MINUTE - var/beating = 0 - - compability = list(HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/heart/update_icon() - if(beating) - item_state_world = "[base_icon_state]-on_world" - icon_state = "[base_icon_state]-on" - else - item_state_world = "[base_icon_state]-off_world" - icon_state = "[base_icon_state]-off" - - -/obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M) - ..() - beating = 1 - owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) - - -/obj/item/organ/internal/heart/proc/heart_stop() - if(!owner.reagents.has_reagent("inaprovaline") || owner.stat == DEAD) - heart_status = HEART_FAILURE - deltimer(fibrillation_timer_id) - fibrillation_timer_id = null - owner.metabolism_factor.AddModifier("Heart", multiple = 0.0) - else - take_damage(1, 0) - fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE) - -/obj/item/organ/internal/heart/remove(mob/living/carbon/M) - ..() - VARSET_IN(src, beating, 0, 100 SECONDS) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2 MINUTES) - - -/obj/item/organ/internal/heart/proc/heart_fibrillate() - heart_status = HEART_FIBR - if(HAS_TRAIT(owner, TRAIT_FAT)) - failing_interval = 30 SECONDS - fibrillation_timer_id = addtimer(CALLBACK(src, PROC_REF(heart_stop)), failing_interval, TIMER_UNIQUE|TIMER_STOPPABLE) - owner.metabolism_factor.AddModifier("Heart", multiple = 0.5) - -/obj/item/organ/internal/heart/proc/heart_normalize() - heart_status = HEART_NORMAL - deltimer(fibrillation_timer_id) - fibrillation_timer_id = null - owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) - -/obj/item/organ/internal/heart/cybernetic - name = "cybernetic heart" - desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." - icon_state = "heart-prosthetic" - item_state_world = "heart-prosthetic_world" - base_icon_state = "heart-prosthetic" - dead_icon = "heart-prosthetic-off" - status = ORGAN_ROBOT - compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/heart/ipc - name = "cooling pump" - cases = list("помпа системы охлаждения", "помпы системы охлаждения", "помпе системы охлаждения", "помпу системы охлаждения", "помпой системы охлаждения", "помпой системы охлаждения") - - var/pumping_rate = 5 - var/bruised_loss = 3 - requires_robotic_bodypart = TRUE - status = ORGAN_ROBOT - icon = 'icons/obj/device.dmi' - icon_state = "miniaturesuitcooler0" - - -/obj/item/organ/internal/heart/ipc/update_icon() - if(beating) - icon_state = "miniaturesuitcooler0" - item_state_world = "miniaturesuitcooler0" - else - icon_state = "miniaturesuitcooler0" - item_state_world = "miniaturesuitcooler0" - -/obj/item/organ/internal/heart/ipc/process() - if(owner.nutrition < 1) - return - if(is_broken()) - return - - var/obj/item/organ/internal/lungs/ipc/lungs = owner.organs_by_name[O_LUNGS] - if(!istype(lungs)) - return - - var/pumping_volume = pumping_rate - if(is_bruised()) - pumping_volume -= bruised_loss - - if(pumping_volume > 0) - lungs.add_refrigerant(pumping_volume) - -/obj/item/organ/internal/heart/vox - name = "vox heart" - icon = 'icons/obj/special_organs/vox.dmi' - parent_bodypart = BP_GROIN - compability = list(VOX) - sterile = TRUE - -/obj/item/organ/internal/heart/tajaran - name = "tajaran heart" - icon = 'icons/obj/special_organs/tajaran.dmi' - -/obj/item/organ/internal/heart/unathi - name = "unathi heart" - icon = 'icons/obj/special_organs/unathi.dmi' - desc = "A large looking heart." - -/obj/item/organ/internal/heart/skrell - name = "skrell heart" - icon = 'icons/obj/special_organs/skrell.dmi' - desc = "A stream lined heart." - -/obj/item/organ/internal/heart/diona - name = "circulatory siphonostele" - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - item_state_world = "nymph" - compability = list(DIONA) - tough = TRUE /obj/item/organ/internal/lungs name = "lungs" @@ -506,6 +370,27 @@ if (src.damage && src.damage < src.min_bruised_damage && owner.reagents.has_reagent("anti_toxin")) src.damage -= 0.2 * process_accuracy + var/blood_total = owner.blood_amount() + + // Blood regeneration if there is some space: + if(blood_total < BLOOD_VOLUME_NORMAL) + var/change_volume = 0.1 // Regenerate blood VERY slowly + if (owner.reagents.has_reagent("nutriment")) // Getting food speeds it up + change_volume += 0.4 + owner.reagents.remove_reagent("nutriment", 0.1) + if (owner.reagents.has_reagent("copper") && owner.get_species(owner) == SKRELL) // skrell blood base on copper + change_volume += 1 + owner.reagents.remove_reagent("copper", 0.1) + if (owner.reagents.has_reagent("iron")) // Hematogen candy anyone? + if(owner.get_species(owner) == SKRELL) // a little more toxins when trying to restore blood with iron + var/mob/living/carbon/human/H = owner + H.adjustToxLoss(1) + else + change_volume += 0.8 + owner.reagents.remove_reagent("iron", 0.1) + owner.blood_add(change_volume) + blood_total += change_volume + // Damaged liver means some chemicals are very dangerous if(src.damage >= src.min_bruised_damage) for(var/datum/reagent/R in owner.reagents.reagent_list) @@ -675,6 +560,87 @@ parent_bodypart = O_BRAIN icon_state = "brain2" item_state_world = "brain2_world" + var/oxygen_reserve = 6 + + +/obj/item/organ/internal/brain/process() + + if(!owner) + return + + if(!owner.should_have_organ(O_HEART)) + return + + // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. + var/blood_volume = owner.get_blood_oxygenation() + if(blood_volume < BLOOD_VOLUME_SURVIVE_P) + if(!owner.reagents.has_reagent("inaprovaline") || prob(60)) + oxygen_reserve = max(0, oxygen_reserve-1) + else + oxygen_reserve = min(initial(oxygen_reserve), oxygen_reserve+1) + if(!oxygen_reserve) //(hardcrit) + owner.Paralyse(3) + +/* i don't think it's needed + if(damage > 1 && damage < min_bruised_damage || heart_status == HEART_FIBR) + blood_volume *= 0.8 + else if(damage >= min_bruised_damage && damage < min_broken_damage) + blood_volume *= 0.6 + else if((damage >= min_broken_damage && damage < INFINITY) || heart_status == HEART_FAILURE) + blood_volume *= 0.3 +*/ + + // Effects of bloodloss + if(!HAS_TRAIT(src, TRAIT_CPB)) + switch(blood_volume) + if(BLOOD_VOLUME_SAFE_P to 10000) + if(owner.pale) + owner.pale = FALSE + owner.update_body() + if(BLOOD_VOLUME_OKAY_P to BLOOD_VOLUME_SAFE_P) + if(!owner.pale) + owner.pale = TRUE + owner.update_body() + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel [word]") + if(prob(1)) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel [word]") + if(owner.oxyloss < 20) + owner.oxyloss += 3 + if(BLOOD_VOLUME_BAD_P to BLOOD_VOLUME_OKAY_P) + if(!owner.pale) + owner.pale = TRUE + owner.update_body() + owner.blurEyes(6) + if(owner.oxyloss < 50) + owner.oxyloss += 10 + owner.oxyloss += 1 + if(prob(15)) + owner.Paralyse(rand(1,3)) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel extremely [word]") + if(BLOOD_VOLUME_SURVIVE_P to BLOOD_VOLUME_BAD_P) + owner.oxyloss += 5 + if(!owner.paralysis && prob(15)) + owner.Paralyse(3,5) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel extremely [word]") + if(0 to BLOOD_VOLUME_SURVIVE_P) + if(!iszombie(owner)) // zombies dont care about blood + owner.blurEyes(6) + owner.Paralyse(6) + owner.Weaken(6) + owner.oxyloss += 15 + + // Without enough blood you slowly go hungry. + if(blood_volume < BLOOD_VOLUME_SAFE_P) + if(owner.nutrition >= 300) + owner.nutrition -= 10 + else if(owner.nutrition >= 200) + owner.nutrition -= 3 + + ..() /obj/item/organ/internal/brain/diona name = "main node nymph" diff --git a/taucetistation.dme b/taucetistation.dme index 0565f64bbb04..dffb8642419f 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -2480,6 +2480,7 @@ #include "code\modules\surgery\tissue.dm" #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\organs\blood.dm" +#include "code\modules\surgery\organs\heart.dm" #include "code\modules\surgery\organs\organ.dm" #include "code\modules\surgery\organs\organ_external.dm" #include "code\modules\surgery\organs\organ_helpers.dm" From 8100f5df32b68d289c13ea4b172f5cad0fda7175 Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 11 Dec 2024 06:58:54 +0400 Subject: [PATCH 17/32] Dinamic_lungs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Динамичные лёгкие, крута! Изменения заметны только в коде! --- code/game/atoms.dm | 3 + code/modules/mob/inventory.dm | 8 + code/modules/mob/living/carbon/carbon.dm | 16 +- code/modules/mob/living/carbon/human/life.dm | 75 ++-- code/modules/mob/living/carbon/species.dm | 2 +- code/modules/surgery/organs/blood.dm | 4 - code/modules/surgery/organs/heart.dm | 3 +- code/modules/surgery/organs/lungs.dm | 342 ++++++++++++++++++ code/modules/surgery/organs/organ_internal.dm | 146 +------- taucetistation.dme | 1 + 10 files changed, 409 insertions(+), 191 deletions(-) create mode 100644 code/modules/surgery/organs/lungs.dm diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 432a9a016da4..238d2e0111ae 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -221,6 +221,9 @@ return flags & INSERT_CONTAINER */ +/atom/proc/return_air_for_internal_lifeform() + return return_air() + /atom/proc/allow_drop() return 1 diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 0010ad40c32a..18d61197bc20 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -585,3 +585,11 @@ var/global/list/slot_equipment_priority = list( if(SLOT_R_HAND) return r_hand return null + +// Returns all items which covers any given body part +/mob/proc/get_covering_equipped_items(bodyparts) + . = list() + for(var/entry in get_equipped_items()) + var/obj/item/I = entry + if(I.body_parts_covered & bodyparts) + . += I diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 05f6828cfefd..4d05336ea8f0 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -244,12 +244,12 @@ breath.update_values() -/mob/living/carbon/proc/breathe() +/mob/living/carbon/proc/breathe(active_breathe = 1) if(is_skip_breathe()) return null //First, check if we can breathe at all - if(suiciding || is_cant_breathe()) + if(suiciding || is_cant_breathe() || !active_breathe) losebreath = max(2, losebreath + 1) if(losebreath > 0) //Suffocating so do not take a breath @@ -290,10 +290,11 @@ handle_external_pre_breathing(breath) - if(!breath || (breath.total_moles <= 0)) - handle_suffocating() - inhale_alert = TRUE - return + if(!breath) + var/static/datum/gas_mixture/vacuum //avoid having to create a new gas mixture for each breath in space + if(!vacuum) vacuum = new + + breath = vacuum //still nothing? must be vacuum breath.volume = BREATH_VOLUME @@ -303,6 +304,9 @@ return breath +/mob/living/carbon/proc/get_breath_volume() + return BREATH_VOLUME + /mob/living/carbon/calculate_affecting_pressure(pressure) return pressure diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c0c1f6340c4e..a2a689d70a1f 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -334,8 +334,7 @@ var/global/list/tourette_bad_words= list( BP.add_autopsy_data("Radiation Poisoning", damage) /mob/living/carbon/human/is_cant_breathe() - var/lungs = get_organ_by_name(O_LUNGS) - return ((handle_drowning() || health < config.health_threshold_crit) || !lungs) && !(reagents.has_reagent("inaprovaline") || HAS_TRAIT(src, TRAIT_AV)) + return ((handle_drowning() || health < config.health_threshold_crit)) && !(reagents.has_reagent("inaprovaline") || HAS_TRAIT(src, TRAIT_AV)) /mob/living/carbon/human/handle_external_pre_breathing(datum/gas_mixture/breath) ..() @@ -346,16 +345,30 @@ var/global/list/tourette_bad_words= list( rupture_lung() /mob/living/carbon/human/breathe() - var/datum/gas_mixture/breath = ..() - failed_last_breath = inhale_alert + var/species_organ = species.breathing_organ + + if(species_organ) + var/active_breaths = 0 + var/obj/item/organ/internal/lungs/L = organs_by_name[species_organ] + if(L) + active_breaths = L.active_breathing + ..(active_breaths) + +/mob/living/carbon/human/handle_breath(datum/gas_mixture/breath) + if(status_flags & GODMODE) + return + var/species_organ = species.breathing_organ + if(!species_organ) + return + + var/obj/item/organ/internal/lungs/L = organs_by_name[species_organ] + if(!L) + failed_last_breath = 1 + else + failed_last_breath = L.handle_breath(breath) //if breath is null or vacuum, the lungs will handle it for us + return !failed_last_breath - if(breath) - //spread some viruses while we are at it - if (virus2.len > 0) - if (prob(10) && get_infection_chance(src)) - for(var/mob/living/carbon/M in view(1,src)) - spread_disease_to(M) /mob/living/carbon/human/get_breath_from_internal(volume_needed) if(!internal) @@ -378,27 +391,6 @@ var/global/list/tourette_bad_words= list( playsound(src, breathsound, VOL_EFFECTS_MASTER, null, FALSE, null, -6) return internal.remove_air_volume(volume_needed) -/mob/living/carbon/human/handle_breath_temperature(datum/gas_mixture/breath) - // Hot air hurts :( - if(breath.temperature > species.heat_level_1) - if(breath.temperature > species.heat_level_3) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, BP_HEAD, used_weapon = "Excessive Heat") - else if(breath.temperature > species.heat_level_2) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Heat") - else - apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Heat") - else if(breath.temperature < species.breath_cold_level_1) - if(breath.temperature >= species.breath_cold_level_2) - apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Cold") - else if(breath.temperature >= species.breath_cold_level_3) - apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Cold") - else - apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, BP_HEAD, used_weapon = "Excessive Cold") - - //breathing in hot/cold air also heats/cools you a bit - var/affecting_temp = (breath.temperature - bodytemperature) * breath.return_relative_density() - - adjust_bodytemperature(affecting_temp / 5, use_insulation = TRUE, use_steps = TRUE) /mob/living/carbon/human/handle_suffocating(datum/gas_mixture/breath) if(suiciding) @@ -523,25 +515,6 @@ var/global/list/tourette_bad_words= list( //END FIRE CODE -/* -/mob/living/carbon/human/proc/adjust_body_temperature(current, loc_temp, boost) - var/temperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - temperature = min(loc_temp, temperature+change) - else if(current > loc_temp) - temperature = max(loc_temp, temperature-change) - temp_change = (temperature - current) - return temp_change -*/ - /mob/living/carbon/human/stabilize_body_temperature() if (species.flags[IS_SYNTHETIC]) return @@ -1232,7 +1205,7 @@ var/global/list/tourette_bad_words= list( */ -#undef HUMAN_MAX_OXYLOSS + #undef HUMAN_CRIT_MAX_OXYLOSS #undef LIGHT_DAM_THRESHOLD diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 9bfbc7af6b2a..b88e757f0162 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -52,7 +52,7 @@ // Is used when a bodypart of this race is butchered. Otherwise there are overrides for flesh, robot, and bone bodyparts. var/list/bodypart_butcher_results - var/breathing_organ // If set, this organ is required for breathing. Defaults to "lungs" if the species has them. + var/breathing_organ = O_LUNGS // If set, this organ is required for breathing. Defaults to "lungs" if the species has them. var/blood_volume = SPECIES_BLOOD_DEFAULT // Initial blood volume. diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index 4b57755a264a..397ec366d9eb 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -374,10 +374,6 @@ var/global/const/BLOOD_VOLUME_SURVIVE = 122 var/min_efficiency = recent_pump ? 0.5 : 0.3 blood_volume *= max(min_efficiency, (1-(heart.damage / heart.max_damage))) -/*Need help with it - if(owner.reagents.has_reagent("metatrombine")) - blood_volume *= max(0, 1-chem_effects[CE_BLOCKAGE]) -*/ return min(blood_volume, 100) //Whether the species needs blood to carry oxygen. Used in get_blood_oxygenation and may be expanded based on blood rather than species in the future. diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 49c66c21717a..1b1911b1aced 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -97,6 +97,7 @@ /obj/item/organ/internal/heart/proc/handle_blood() if(!owner.species.flags[NO_BLOOD] && owner.bodytemperature >= 170 || owner.stat == DEAD || !owner) + return if(owner.reagents.has_reagent("metatrombine")) return @@ -180,7 +181,6 @@ //work! /obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M) ..() - beating = 1 owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) @@ -196,6 +196,7 @@ /obj/item/organ/internal/heart/remove(mob/living/carbon/M) ..() + heart_status = HEART_FAILURE VARSET_IN(src, beating, 0, 100 SECONDS) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2 MINUTES) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm new file mode 100644 index 000000000000..292342374a42 --- /dev/null +++ b/code/modules/surgery/organs/lungs.dm @@ -0,0 +1,342 @@ + +/obj/item/organ/internal/lungs + name = "lungs" + cases = list("лёгкие", "лёгких", "лёгким", "лёгкие", "лёгкими", "лёгких") + icon_state = "lungs" + item_state_world = "lungs_world" + organ_tag = O_LUNGS + parent_bodypart = BP_CHEST + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + var/exhale_type = "carbon_dioxide" + var/breath_type = "oxygen" + var/has_gills = FALSE + var/active_breathing = 1 + var/min_breath_pressure = 16 + var/last_int_pressure + var/last_ext_pressure + var/max_pressure_diff = 60 + var/breath_fail_ratio // How badly they failed a breath. Higher is worse. + var/poison_type = "phoron" + var/last_successful_breath + var/breathing = 0 + var/safe_toxins_max = 0.2 + + + +/obj/item/organ/internal/lungs/proc/rupture() + var/obj/item/organ/external/parent = owner.get_bodypart(parent_bodypart) + if(istype(parent)) + owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50) + bruise() + +/obj/item/organ/internal/lungs/proc/check_rupturing(datum/gas_mixture/breath) +//breath.total_moles < BREATH_MOLES / 5 || breath.total_moles > BREATH_MOLES * 5 + if(damage > 50) + var/lung_rupture_prob = is_robotic(src) ? prob(30) : prob(60) //Robotic lungs are less likely to rupture. + if(!is_bruised() && lung_rupture_prob) //only rupture if NOT already ruptured + rupture() + +/obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath, forced) + + + var/const/safe_exhaled_max = 10 // Yes it's an arbitrary value who cares? + var/const/safe_toxins_max = 0.005 + var/const/safe_fractol_max = 0.15 + var/const/SA_para_min = 1 + var/const/SA_sleep_min = 5 + var/const/SA_giggle_min = 0.15 + + var/list/breath_gas = breath.gas + var/breath_total_moles = breath.total_moles + + var/inhaling = breath_gas[breath_type] + var/exhaling = breath_gas[exhale_type] + var/poison = breath_gas[poison_type] + var/sleeping_agent = breath_gas["sleeping_agent"] + + var/inhaled_gas_used = 0 + var/breath_pressure = breath.return_pressure() + + var/inhale_pp = inhaling ? (inhaling / breath_total_moles) * breath_pressure : 0 + var/exhaled_pp = exhaling ? (exhaling / breath_total_moles) * breath_pressure : 0 + var/poison_pp = poison ? (poison / breath_total_moles) * breath_pressure : 0 + var/SA_pp = sleeping_agent ? (sleeping_agent / breath_total_moles) * breath_pressure : 0 + + // Anyone can breath this! + var/druggy_breath_type = "fractol" + var/druggy_inhaling = breath_gas[druggy_breath_type] + var/druggy_inhale_pp = druggy_inhaling ? (druggy_inhaling / breath_total_moles) * breath_pressure : 0 + + breath_type = inhale_pp >= druggy_inhale_pp ? breath_type : druggy_breath_type + inhaling = inhale_pp >= druggy_inhale_pp ? inhaling : druggy_inhaling + inhale_pp = inhale_pp >= druggy_inhale_pp ? inhale_pp : druggy_inhale_pp + + + if(!owner) + return 1 + + if(!breath || (max_damage <= 0)) + breath_fail_ratio = 1 + handle_failed_breath() + return 1 + + var/datum/gas_mixture/environment = owner.loc.return_air_for_internal_lifeform() + last_ext_pressure = environment && environment.return_pressure() + last_int_pressure = breath_pressure + if(breath.total_moles == 0) + breath_fail_ratio = 1 + handle_failed_breath() + return 1 + + var/safe_pressure_min = min_breath_pressure // Minimum safe partial pressure of breathable gas in kPa + // Lung damage increases the minimum safe pressure. + safe_pressure_min *= 1 + rand(1,4) * damage/max_damage + + var/failed_inhale = 0 + var/failed_exhale = 0 + + var/inhale_efficiency = min(round(((inhaling/breath.total_moles)*breath_pressure)/safe_pressure_min, 0.001), 3) + + if(inhale_pp < safe_pressure_min) + if(prob(20)&& active_breathing) + owner.emote("gasp") + if(inhale_pp > 0) + var/ratio = inhale_pp / safe_pressure_min + + // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!) + owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS * (1 - ratio)) + inhaled_gas_used = inhaling * ratio * BREATH_USED_PART + else + owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + + failed_inhale = 1 + owner.inhale_alert = TRUE + + breath.adjust_gas(breath_type, -inhaled_gas_used, update = FALSE) //update afterwards + + if(exhale_type) + breath.adjust_gas_temp(exhale_type, inhaled_gas_used, owner.bodytemperature, update = FALSE) //update afterwards + + // CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, + // this will hurt you, but only once per 4 ticks, instead of once per tick. + + if(exhaled_pp > safe_exhaled_max) + + // If it's the first breath with too much CO2 in it, lets start a counter, + // then have them pass out after 12s or so. + if(!owner.co2overloadtime) + owner.co2overloadtime = world.time + else if(world.time - owner.co2overloadtime > 120) + // Lets hurt em a little, let them know we mean business + owner.Paralyse(3) + owner.adjustOxyLoss(3) + + // They've been in here 30s now, lets start to kill them for their own good! + if(world.time - owner.co2overloadtime > 300) + owner.adjustOxyLoss(8) + + // Lets give them some chance to know somethings not right though I guess. + if(prob(20)) + owner.emote("cough") + else + owner.co2overloadtime = null + + if(druggy_inhale_pp > safe_fractol_max) + owner.adjustDrugginess(1) + if(prob(5)) + owner.emote("twitch") + owner.random_move() + else if(prob(7)) + owner.emote(pick("drool","moan","giggle")) + + + owner.inhale_alert = 0 // Reset our toxins alert for now. + // Too much poison in the air. + if(poison_pp > safe_toxins_max) + var/ratio = (poison / safe_toxins_max) * 10 + if(owner.reagents) + owner.reagents.add_reagent("toxin", clamp(ratio, MIN_TOXIN_DAMAGE, MAX_TOXIN_DAMAGE)) + breath.adjust_gas(poison_type, -poison * BREATH_USED_PART, update = FALSE) //update after + owner.poison_alert = TRUE + + // Moved after reagent injection so we don't instantly poison ourselves with CO2 or whatever. + if(exhale_type && (!istype(owner.wear_mask))) + breath.adjust_gas_temp(exhale_type, inhaled_gas_used, owner.bodytemperature, update = 0) //update afterwards + + // If there's some other shit in the air lets deal with it here. + if(sleeping_agent) + // Enough to make us paralysed for a bit + if(SA_pp > SA_para_min) + // 3 gives them one second to wake up and run away a bit! + owner.Paralyse(3) + + // Enough to make us sleep as well + if(SA_pp > SA_sleep_min) + owner.Sleeping(10 SECONDS) + owner.analgesic = clamp(owner.analgesic + 5, 0, 10) + + // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning + else if(SA_pp > SA_giggle_min) + if(prob(20)) + owner.emote(pick("giggle", "laugh")) + + breath.adjust_gas("sleeping_agent", -sleeping_agent * BREATH_USED_PART, update = FALSE) //update after + + // Were we able to breathe? + var/failed_breath = failed_inhale || failed_exhale + if(!failed_breath) + last_successful_breath = world.time + owner.adjustOxyLoss(-5 * inhale_efficiency) + + handle_breath_temperature(breath) + breath.update_values() + + check_rupturing() + + if(failed_breath) + handle_failed_breath() + else + owner.inhale_alert = 0 + return failed_breath + +/obj/item/organ/internal/lungs/proc/handle_failed_breath() + if(prob(15)) + if(!owner.species.flags[IS_SYNTHETIC]) + if(active_breathing) + owner.emote("gasp") + else + owner.emote(pick("shiver","twitch")) + + owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS*breath_fail_ratio) + + owner.inhale_alert = max(owner.inhale_alert, 2) + last_int_pressure = 0 + +/obj/item/organ/internal/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath) + // Hot air hurts :( + if(breath.temperature > owner.species.heat_level_1) + if(breath.temperature > owner.species.heat_level_3) + owner.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, BP_HEAD, used_weapon = "Excessive Heat") + else if(breath.temperature > owner.species.heat_level_2) + owner.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Heat") + else + owner.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Heat") + else if(breath.temperature < owner.species.breath_cold_level_1) + if(breath.temperature >= owner.species.breath_cold_level_2) + owner.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Cold") + else if(breath.temperature >= owner.species.breath_cold_level_3) + owner.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Cold") + else + owner.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, BP_HEAD, used_weapon = "Excessive Cold") + + //breathing in hot/cold air also heats/cools you a bit + var/affecting_temp = (breath.temperature - owner.bodytemperature) * breath.return_relative_density() + + owner.adjust_bodytemperature(affecting_temp / 5, use_insulation = TRUE, use_steps = TRUE) + + + +/obj/item/organ/internal/lungs/process() + ..() + if (owner.species && owner.species.flags[NO_BREATHE]) + return + if (germ_level > INFECTION_LEVEL_ONE) + if(!owner.reagents.has_reagent("dextromethorphan") && prob(5)) + owner.emote("cough") //respitory tract infection + + if(is_bruised()) + if(prob(2)) + owner.emote("cough") + owner.drip(10) + if(prob(4) && !HAS_TRAIT(owner, TRAIT_AV)) + owner.emote("gasp") + owner.losebreath += 15 + + +/obj/item/organ/internal/lungs/vox + name = "air capillary sack" + cases = list("воздушно-капиллярный мешок", "воздушно-капиллярного мешка", "воздушно-капиллярному мешку", "воздушно-капиллярный мешок", "воздушно-капиллярным мешком", "воздушно-капиллярном мешке") + desc = "They're filled with dust....wow." + parent_bodypart = BP_GROIN + icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) + sterile = TRUE + +/obj/item/organ/internal/lungs/tajaran + name = "tajaran lungs" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/lungs/unathi + name = "unathi lungs" + icon = 'icons/obj/special_organs/unathi.dmi' + +/obj/item/organ/internal/lungs/skrell + name = "respiration sac" + cases = list("дыхательная сумка", "дыхательной сумки", "дыхательной сумке", "дыхательную сумку", "дыхательной сумкой", "дыхательной сумке") + has_gills = TRUE + icon = 'icons/obj/special_organs/skrell.dmi' + +/obj/item/organ/internal/lungs/diona + name = "virga inopinatus" + cases = list("полая ветка", "полой ветки", "полой ветки", "полую ветку", "полой веткой", "полой ветке") + process_accuracy = 10 + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE + +/obj/item/organ/internal/lungs/cybernetic + name = "cybernetic lungs" + desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement." + icon_state = "lungs-prosthetic" + item_state_world = "lungs-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/lungs/ipc + name = "cooling element" + cases = list("охлаждающий элемент", "охлаждающего элемента", "охлаждающему элементу", "охлаждающий элемент", "охлаждающим элементом", "охлаждающем элементе") + + var/refrigerant_max = 50 + var/refrigerant = 50 + var/refrigerant_rate = 5 + var/bruised_loss = 3 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/robot_component.dmi' + icon_state = "working" + item_state_world = "working" + +/obj/item/organ/internal/lungs/ipc/process() + if(owner.nutrition < 1) + return + var/temp_gain = owner.species.synth_temp_gain + + if(refrigerant > 0 && !is_broken()) + var/refrigerant_spent = refrigerant_rate + refrigerant -= refrigerant_rate + if(refrigerant < 0) + refrigerant_spent += refrigerant + refrigerant = 0 + + if(is_bruised()) + refrigerant_spent -= bruised_loss + + if(refrigerant_spent > 0) + temp_gain -= refrigerant_spent + + if(HAS_TRAIT(owner, TRAIT_COOLED) & owner.bodytemperature > 290) + owner.adjust_bodytemperature(-50) + + if(temp_gain > 0) + owner.adjust_bodytemperature(temp_gain, max_temp = owner.species.synth_temp_max) + +/obj/item/organ/internal/lungs/ipc/proc/add_refrigerant(volume) + if(refrigerant < refrigerant_max) + refrigerant += volume + if(refrigerant > refrigerant_max) + refrigerant = refrigerant_max diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 81ca8c1ba6df..99df7aa06e0f 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -155,123 +155,13 @@ if(2) take_damage(7, 1) +/obj/item/organ/internal/proc/bruise() + damage = max(damage, min_bruised_damage) /**************************************************** ORGANS DEFINES ****************************************************/ - -/obj/item/organ/internal/lungs - name = "lungs" - cases = list("лёгкие", "лёгких", "лёгким", "лёгкие", "лёгкими", "лёгких") - icon_state = "lungs" - item_state_world = "lungs_world" - organ_tag = O_LUNGS - parent_bodypart = BP_CHEST - var/has_gills = FALSE - -/obj/item/organ/internal/lungs/vox - name = "air capillary sack" - cases = list("воздушно-капиллярный мешок", "воздушно-капиллярного мешка", "воздушно-капиллярному мешку", "воздушно-капиллярный мешок", "воздушно-капиллярным мешком", "воздушно-капиллярном мешке") - desc = "They're filled with dust....wow." - parent_bodypart = BP_GROIN - icon = 'icons/obj/special_organs/vox.dmi' - compability = list(VOX) - sterile = TRUE - -/obj/item/organ/internal/lungs/tajaran - name = "tajaran lungs" - icon = 'icons/obj/special_organs/tajaran.dmi' - -/obj/item/organ/internal/lungs/unathi - name = "unathi lungs" - icon = 'icons/obj/special_organs/unathi.dmi' - -/obj/item/organ/internal/lungs/skrell - name = "respiration sac" - cases = list("дыхательная сумка", "дыхательной сумки", "дыхательной сумке", "дыхательную сумку", "дыхательной сумкой", "дыхательной сумке") - has_gills = TRUE - icon = 'icons/obj/special_organs/skrell.dmi' - -/obj/item/organ/internal/lungs/diona - name = "virga inopinatus" - cases = list("полая ветка", "полой ветки", "полой ветки", "полую ветку", "полой веткой", "полой ветке") - process_accuracy = 10 - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - item_state_world = "nymph" - compability = list(DIONA) - tough = TRUE - -/obj/item/organ/internal/lungs/cybernetic - name = "cybernetic lungs" - desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement." - icon_state = "lungs-prosthetic" - item_state_world = "lungs-prosthetic_world" - origin_tech = "biotech=4" - status = ORGAN_ROBOT - compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/lungs/ipc - name = "cooling element" - cases = list("охлаждающий элемент", "охлаждающего элемента", "охлаждающему элементу", "охлаждающий элемент", "охлаждающим элементом", "охлаждающем элементе") - - var/refrigerant_max = 50 - var/refrigerant = 50 - var/refrigerant_rate = 5 - var/bruised_loss = 3 - requires_robotic_bodypart = TRUE - status = ORGAN_ROBOT - icon = 'icons/obj/robot_component.dmi' - icon_state = "working" - item_state_world = "working" - -/obj/item/organ/internal/lungs/process() - ..() - if (owner.species && owner.species.flags[NO_BREATHE]) - return - if (germ_level > INFECTION_LEVEL_ONE) - if(!owner.reagents.has_reagent("dextromethorphan") && prob(5)) - owner.emote("cough") //respitory tract infection - - if(is_bruised()) - if(prob(2)) - owner.emote("cough") - owner.drip(10) - if(prob(4) && !HAS_TRAIT(owner, TRAIT_AV)) - owner.emote("gasp") - owner.losebreath += 15 - -/obj/item/organ/internal/lungs/ipc/process() - if(owner.nutrition < 1) - return - var/temp_gain = owner.species.synth_temp_gain - - if(refrigerant > 0 && !is_broken()) - var/refrigerant_spent = refrigerant_rate - refrigerant -= refrigerant_rate - if(refrigerant < 0) - refrigerant_spent += refrigerant - refrigerant = 0 - - if(is_bruised()) - refrigerant_spent -= bruised_loss - - if(refrigerant_spent > 0) - temp_gain -= refrigerant_spent - - if(HAS_TRAIT(owner, TRAIT_COOLED) & owner.bodytemperature > 290) - owner.adjust_bodytemperature(-50) - - if(temp_gain > 0) - owner.adjust_bodytemperature(temp_gain, max_temp = owner.species.synth_temp_max) - -/obj/item/organ/internal/lungs/ipc/proc/add_refrigerant(volume) - if(refrigerant < refrigerant_max) - refrigerant += volume - if(refrigerant > refrigerant_max) - refrigerant = refrigerant_max - /obj/item/organ/internal/liver name = "liver" cases = list("печень", "печени", "печени", "печень", "печенью", "печени") @@ -280,6 +170,9 @@ organ_tag = O_LIVER parent_bodypart = BP_GROIN var/alcohol_intensity = 1 + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 process_accuracy = 10 /obj/item/organ/internal/liver/diona @@ -401,6 +294,14 @@ if(istype(R, /datum/reagent/toxin)) owner.adjustToxLoss(0.3 * process_accuracy) + // Without enough blood you slowly go hungry. + var/blood_volume = owner.get_blood_oxygenation() + if(blood_volume < BLOOD_VOLUME_SAFE_P) + if(owner.nutrition >= 300) + owner.nutrition -= 10 + else if(owner.nutrition >= 200) + owner.nutrition -= 3 + /obj/item/organ/internal/liver/process() ..() handle_liver_infection() @@ -426,6 +327,7 @@ return damage += 0.2 + /obj/item/organ/internal/liver/ipc/process() var/obj/item/weapon/stock_parts/cell/C = locate(/obj/item/weapon/stock_parts/cell) in src @@ -460,6 +362,9 @@ cases = list("почки", "почек", "почкам", "почки", "почками", "почках") icon_state = "kidneys" item_state_world = "kidneys_world" + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 organ_tag = O_KIDNEYS parent_bodypart = BP_GROIN @@ -581,15 +486,6 @@ if(!oxygen_reserve) //(hardcrit) owner.Paralyse(3) -/* i don't think it's needed - if(damage > 1 && damage < min_bruised_damage || heart_status == HEART_FIBR) - blood_volume *= 0.8 - else if(damage >= min_bruised_damage && damage < min_broken_damage) - blood_volume *= 0.6 - else if((damage >= min_broken_damage && damage < INFINITY) || heart_status == HEART_FAILURE) - blood_volume *= 0.3 -*/ - // Effects of bloodloss if(!HAS_TRAIT(src, TRAIT_CPB)) switch(blood_volume) @@ -633,13 +529,6 @@ owner.Weaken(6) owner.oxyloss += 15 - // Without enough blood you slowly go hungry. - if(blood_volume < BLOOD_VOLUME_SAFE_P) - if(owner.nutrition >= 300) - owner.nutrition -= 10 - else if(owner.nutrition >= 200) - owner.nutrition -= 3 - ..() /obj/item/organ/internal/brain/diona @@ -724,6 +613,7 @@ cases = list("глаза", "глаз", "глазам", "глаза", "глазами", "глазах") organ_tag = O_EYES parent_bodypart = BP_HEAD + max_damage = 45 var/list/eye_colour = list(0,0,0) var/darksight = 2 var/nighteyes = FALSE diff --git a/taucetistation.dme b/taucetistation.dme index dffb8642419f..859ab88a585a 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -2481,6 +2481,7 @@ #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\organs\blood.dm" #include "code\modules\surgery\organs\heart.dm" +#include "code\modules\surgery\organs\lungs.dm" #include "code\modules\surgery\organs\organ.dm" #include "code\modules\surgery\organs\organ_external.dm" #include "code\modules\surgery\organs\organ_helpers.dm" From e8846c13861da84e609972c7c04d28dc3781a312 Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 11 Dec 2024 07:59:59 +0400 Subject: [PATCH 18/32] some changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Парочка изменений, наверное? --- code/modules/client/character_menu/general.dm | 4 ++-- code/modules/surgery/eye.dm | 2 ++ code/modules/surgery/organs/lungs.dm | 16 ---------------- code/modules/surgery/organs/organ.dm | 9 +++++++++ code/modules/surgery/organs_internal.dm | 2 ++ tgui/packages/tgui/interfaces/BodyScanner.js | 9 ++++----- 6 files changed, 19 insertions(+), 23 deletions(-) diff --git a/code/modules/client/character_menu/general.dm b/code/modules/client/character_menu/general.dm index f757bffec3a7..8043169fc3d6 100644 --- a/code/modules/client/character_menu/general.dm +++ b/code/modules/client/character_menu/general.dm @@ -79,9 +79,9 @@ else if(status == "amputated") ++ind . += "
  • Amputated [organ_name]
  • " - else if(status == "mechanical") + else if(status == "Cybernetic") ++ind - . += "
  • Mechanical [organ_name]
  • " + . += "
  • Cybernetic [organ_name]
  • " if(species == IPC) . += "
    Head: [ipc_head]" diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index 608c809dcf45..587fcd312138 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -241,6 +241,8 @@ user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ "You could not find anything inside [target]'s [BP.name].") return + if(!(target.op_stage.eyes == 2)) + return var/obj/item/organ/internal/I = choosen_organ I.status |= ORGAN_CUT_AWAY I.remove(target) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 292342374a42..ba919e3d3690 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -11,33 +11,17 @@ max_damage = 70 var/exhale_type = "carbon_dioxide" var/breath_type = "oxygen" - var/has_gills = FALSE var/active_breathing = 1 var/min_breath_pressure = 16 var/last_int_pressure var/last_ext_pressure - var/max_pressure_diff = 60 var/breath_fail_ratio // How badly they failed a breath. Higher is worse. var/poison_type = "phoron" var/last_successful_breath var/breathing = 0 - var/safe_toxins_max = 0.2 -/obj/item/organ/internal/lungs/proc/rupture() - var/obj/item/organ/external/parent = owner.get_bodypart(parent_bodypart) - if(istype(parent)) - owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50) - bruise() - -/obj/item/organ/internal/lungs/proc/check_rupturing(datum/gas_mixture/breath) -//breath.total_moles < BREATH_MOLES / 5 || breath.total_moles > BREATH_MOLES * 5 - if(damage > 50) - var/lung_rupture_prob = is_robotic(src) ? prob(30) : prob(60) //Robotic lungs are less likely to rupture. - if(!is_bruised() && lung_rupture_prob) //only rupture if NOT already ruptured - rupture() - /obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath, forced) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 32a4899650e5..b0db01608ea9 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -197,6 +197,15 @@ for(var/obj/item/organ/internal/IO in organs) IO.process() + + var/obj/item/organ/internal/liver/liver = organs_by_name[O_LIVER] + if(!liver && should_have_organ(liver)) + adjustToxLoss(2) + + var/obj/item/organ/internal/kidneys/kidneys = organs_by_name[O_LIVER] + if(!kidneys && should_have_organ(kidneys)) + adjustToxLoss(1) + handle_stance() if(!force_process && !bad_bodyparts.len) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 008c3ad940b1..ca8e3017bce0 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -116,6 +116,8 @@ user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ "You could not find anything inside [target]'s [BP.name].") return + if(!(BP.open >= 2 && (target_zone != BP_CHEST || target.op_stage.ribcage == 2))) + return var/obj/item/organ/internal/I = choosen_organ I.status |= ORGAN_CUT_AWAY I.remove(target) diff --git a/tgui/packages/tgui/interfaces/BodyScanner.js b/tgui/packages/tgui/interfaces/BodyScanner.js index 6fe5cf0c4e2a..bcc5d06c57e3 100644 --- a/tgui/packages/tgui/interfaces/BodyScanner.js +++ b/tgui/packages/tgui/interfaces/BodyScanner.js @@ -278,7 +278,7 @@ const BodyScannerMainOrgansExternal = (props) => { || !!o.germ_level || !!o.unknown_implant) && 'average') - || (!!o.status.robotic && 'label') + || (!!o.status.Cybernetic && 'label') } width="33%" > @@ -346,7 +346,7 @@ const BodyScannerMainOrgansExternal = (props) => { )))} {reduceOrganStatus([ !!o.status.splinted && Наложена шина, - !!o.status.robotic && Протез, + !!o.status.Cybernetic && Протез, ])} @@ -381,7 +381,7 @@ const BodyScannerMainOrgansInternal = (props) => { { {reduceOrganStatus([!!o.germ_level && o.germ_level])} {reduceOrganStatus([ - !!o.robotic && Протез, - !!o.assisted && Вспомогательный имплант, + !!o.Cybernetic && Протез, !!o.dead && Отказ, ])} From 8e9288e5e9bbcf165c95dcbd6ff3527f8ed091bd Mon Sep 17 00:00:00 2001 From: Triff <148008815+TriflesChase@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:00:48 +0400 Subject: [PATCH 19/32] Update code/modules/surgery/organs_internal.dm Co-authored-by: NinjaPikachuska <89906909+NinjaPikachuska@users.noreply.github.com> --- code/modules/surgery/organs_internal.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index ca8e3017bce0..2e6db9d5e16c 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -110,7 +110,7 @@ for(var/embed_organ in BP.bodypart_organs) embed_organs += embed_organ for(var/atom/embed_organ as anything in embed_organs) - embed_organs[embed_organ] = image(icon = embed_organ.icon, icon_state = embed_organ.icon_state) + embed_organs[embed_organ] = image(icon = embed_organ.icon, icon_state = initial(embed_organ.icon_state)) var/choosen_organ = show_radial_menu(user, target, embed_organs, radius = 50, require_near = TRUE, tooltips = TRUE) if(!choosen_organ) user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ From b0f8ff56a2fc24b1a42d6fb352a0f3e555191764 Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 11 Dec 2024 08:03:52 +0400 Subject: [PATCH 20/32] shadowling --- code/modules/mob/living/carbon/species.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index b88e757f0162..9156610bdbc3 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -1472,8 +1472,6 @@ restricted_inventory_slots = list(SLOT_BELT, SLOT_WEAR_ID, SLOT_L_EAR, SLOT_R_EAR, SLOT_BACK, SLOT_L_STORE, SLOT_R_STORE) - has_organ = list(O_HEART = /obj/item/organ/internal/heart) // A huge buff to be honest. - flags = list( NO_BREATHE = TRUE ,NO_BLOOD = TRUE @@ -1490,6 +1488,7 @@ has_organ = list( O_BRAIN = /obj/item/organ/internal/brain + ,O_HEART = /obj/item/organ/internal/heart ,O_EYES = /obj/item/organ/internal/eyes/night_vision ) From 337fc42ac9cdad1e645bd2eac882e8c6ebd79bcd Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 11 Dec 2024 08:12:43 +0400 Subject: [PATCH 21/32] lungs fix --- code/modules/surgery/organs/lungs.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index ba919e3d3690..c31a3b386760 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -11,6 +11,7 @@ max_damage = 70 var/exhale_type = "carbon_dioxide" var/breath_type = "oxygen" + var/has_gills = FALSE var/active_breathing = 1 var/min_breath_pressure = 16 var/last_int_pressure @@ -21,7 +22,6 @@ var/breathing = 0 - /obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath, forced) @@ -177,8 +177,6 @@ handle_breath_temperature(breath) breath.update_values() - check_rupturing() - if(failed_breath) handle_failed_breath() else From 96c46d72a02c931d9456e6c08ae91de6e92d354d Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 25 Dec 2024 03:14:27 +0400 Subject: [PATCH 22/32] holydays_organ_update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Перенесла все органы в свои папки, удалила все проки, что не использовались, поменяла название и органы всяким расам, моли и абдукторы теперь не умирают от потери крови, убрала токс флуд из за отсутствия печени и почек, потому что это глупый способ наказания, теперь отсутствие крови бьёт не по кислороду, а сразу по мозгу(не убьёт, но сделает неприятно), я запрещаю бегать без сердца, удалила второй предмет-мозг перенеся его к общему, и ещё парочка других исправлений, которые я забыла упоминуть --- .../mob/living/carbon/brain/brain_item.dm | 39 -- code/modules/mob/living/carbon/species.dm | 8 +- code/modules/surgery/eye.dm | 26 +- code/modules/surgery/organs/brain.dm | 223 +++++++ code/modules/surgery/organs/eyes.dm | 110 ++++ code/modules/surgery/organs/heart.dm | 10 +- code/modules/surgery/organs/kidneys.dm | 101 +++ code/modules/surgery/organs/liver.dm | 198 ++++++ code/modules/surgery/organs/lungs.dm | 5 + code/modules/surgery/organs/organ.dm | 53 +- code/modules/surgery/organs/organ_helpers.dm | 4 +- code/modules/surgery/organs/organ_internal.dm | 578 +----------------- code/modules/surgery/organs_internal.dm | 3 +- taucetistation.dme | 5 +- 14 files changed, 684 insertions(+), 679 deletions(-) delete mode 100644 code/modules/mob/living/carbon/brain/brain_item.dm create mode 100644 code/modules/surgery/organs/brain.dm create mode 100644 code/modules/surgery/organs/eyes.dm create mode 100644 code/modules/surgery/organs/kidneys.dm create mode 100644 code/modules/surgery/organs/liver.dm diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm deleted file mode 100644 index f8e293b3bf99..000000000000 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ /dev/null @@ -1,39 +0,0 @@ -/obj/item/organ/internal/brain - name = "brain" - desc = "A piece of juicy meat found in a persons head." - icon = 'icons/obj/surgery.dmi' - icon_state = "brain2" - force = 1.0 - w_class = SIZE_TINY - throwforce = 1.0 - throw_speed = 3 - throw_range = 5 - origin_tech = "biotech=3" - attack_verb = list("attacked", "slapped", "whacked") - - var/mob/living/carbon/brain/brainmob = null - -/obj/item/organ/internal/brain/atom_init() - . = ..() - //Shifting the brain "mob" over to the brain object so it's easier to keep track of. --NEO - //WASSSSSUUUPPPP /N - spawn(5) - brainmob?.client?.screen.len = null //clear the hud - -/obj/item/organ/internal/brain/proc/transfer_identity(mob/living/carbon/H) - name = "[H]'s brain" - brainmob = new(src) - brainmob.name = H.real_name - brainmob.real_name = H.real_name - brainmob.dna = H.dna.Clone() - brainmob.timeofhostdeath = H.timeofdeath - if(H.mind) - H.mind.transfer_to(brainmob) - - to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a brain.") -/obj/item/organ/internal/brain/examine(mob/user) // -- TLE - ..() - if(brainmob && brainmob.client)//if thar be a brain inside... the brain. - to_chat(user, "You can feel the small spark of life still left in this one.") - else - to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later..") diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 9156610bdbc3..21c51f043fd1 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -1489,7 +1489,7 @@ has_organ = list( O_BRAIN = /obj/item/organ/internal/brain ,O_HEART = /obj/item/organ/internal/heart - ,O_EYES = /obj/item/organ/internal/eyes/night_vision + ,O_EYES = /obj/item/organ/internal/eyes/dark_vision ) burn_mod = 2 @@ -1931,7 +1931,7 @@ has_organ = list( O_BRAIN = /obj/item/organ/internal/brain/abomination - ,O_EYES = /obj/item/organ/internal/eyes/night_vision + ,O_EYES = /obj/item/organ/internal/eyes/dark_vision ) burn_mod = 0.2 brute_mod = 0.2 @@ -2077,7 +2077,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart ,O_BRAIN = /obj/item/organ/internal/brain - ,O_EYES = /obj/item/organ/internal/eyes/night_vision + ,O_EYES = /obj/item/organ/internal/eyes/dark_vision ,O_LUNGS = /obj/item/organ/internal/lungs ,O_LIVER = /obj/item/organ/internal/liver/serpentid ,O_KIDNEYS = /obj/item/organ/internal/kidneys @@ -2240,7 +2240,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart ,O_BRAIN = /obj/item/organ/internal/brain - ,O_EYES = /obj/item/organ/internal/eyes/tajaran + ,O_EYES = /obj/item/organ/internal/eyes/night_vision ,O_LUNGS = /obj/item/organ/internal/lungs ,O_LIVER = /obj/item/organ/internal/liver ,O_KIDNEYS = /obj/item/organ/internal/kidneys diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index 587fcd312138..cc815fae94f2 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -178,7 +178,7 @@ user.visible_message ( " \The [I] is in no state to be transplanted.") return FALSE - if(target.get_organ_by_name(I)) + if(target.get_int_organ(I)) user.visible_message ( " \The [target] already has [I].") return FALSE @@ -231,24 +231,18 @@ var/obj/item/organ/external/BP = target.get_bodypart(target_zone) if (BP.bodypart_organs.len) - var/list/embed_organs = list() - for(var/embed_organ in BP.bodypart_organs) - embed_organs += embed_organ - for(var/atom/embed_organ as anything in embed_organs) - embed_organs[embed_organ] = image(icon = embed_organ.icon, icon_state = embed_organ.icon_state) - var/choosen_organ = show_radial_menu(user, target, embed_organs, radius = 50, require_near = TRUE, tooltips = TRUE) - if(!choosen_organ) + var/obj/item/organ/internal/eyes/eyes = target.organs_by_name[O_EYES] + if(eyes) + eyes.status |= ORGAN_CUT_AWAY + eyes.remove(target) + eyes.loc = get_turf(target) + BP.bodypart_organs -= eyes + playsound(target, 'sound/effects/squelch1.ogg', VOL_EFFECTS_MASTER) + if(!eyes) user.visible_message("[user] could not find anything inside [target]'s [BP.name], and pulls \the [tool] out.", \ "You could not find anything inside [target]'s [BP.name].") return - if(!(target.op_stage.eyes == 2)) - return - var/obj/item/organ/internal/I = choosen_organ - I.status |= ORGAN_CUT_AWAY - I.remove(target) - I.loc = get_turf(target) - BP.bodypart_organs -= I - playsound(target, 'sound/effects/squelch1.ogg', VOL_EFFECTS_MASTER) + /datum/surgery_step/eye/manipulation/remove/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/internal/eyes/IO = target.organs_by_name[O_EYES] diff --git a/code/modules/surgery/organs/brain.dm b/code/modules/surgery/organs/brain.dm new file mode 100644 index 000000000000..cecc6e591286 --- /dev/null +++ b/code/modules/surgery/organs/brain.dm @@ -0,0 +1,223 @@ + +/obj/item/organ/internal/brain + name = "brain" + desc = "A piece of juicy meat found in a persons head." + cases = list("мозг", "мозга", "мозгу", "мозг", "мозгом", "мозге") + organ_tag = O_BRAIN + vital = TRUE + parent_bodypart = BP_HEAD + icon = 'icons/obj/surgery.dmi' + icon_state = "brain2" + item_state_world = "brain2_world" + max_damage = 100 + min_broken_damage = 75 + min_bruised_damage = 25 + + var/can_use_mmi = TRUE + var/oxygen_reserve = 6 + + force = 1.0 + w_class = SIZE_TINY + throwforce = 1.0 + throw_speed = 3 + throw_range = 5 + origin_tech = "biotech=3" + attack_verb = list("attacked", "slapped", "whacked") + + var/mob/living/carbon/brain/brainmob = null + +/obj/item/organ/internal/brain/atom_init() + . = ..() + //Shifting the brain "mob" over to the brain object so it's easier to keep track of. --NEO + //WASSSSSUUUPPPP /N + spawn(5) + brainmob?.client?.screen.len = null //clear the hud + + +/obj/item/organ/internal/brain/process() + + if(owner) + + handle_damage_effects() + + if(owner.should_have_organ(O_HEART)) + if(owner.species.flags[NO_BLOOD]) + return + // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. + var/blood_volume = owner.get_blood_oxygenation() + if(blood_volume < BLOOD_VOLUME_SURVIVE_P) + if(!owner.reagents.has_reagent("inaprovaline") || prob(60)) + oxygen_reserve = max(0, oxygen_reserve-1) + else + oxygen_reserve = min(initial(oxygen_reserve), oxygen_reserve+1) + if(!oxygen_reserve) //(hardcrit) + owner.Paralyse(3) + var/can_heal = damage && damage < max_damage && (owner.reagents.has_reagent("brainheal?????")|| (damage < 30 && owner.reagents.has_reagent("inaprovaline"))) + var/damprob + // Effects of bloodloss + if(!HAS_TRAIT(owner, TRAIT_CPB)) + switch(blood_volume) + if(BLOOD_VOLUME_SAFE_P to 10000) + if(owner.pale) + owner.pale = FALSE + owner.update_body() + if(can_heal) + damage = max(damage-1, 0) + if(BLOOD_VOLUME_OKAY_P to BLOOD_VOLUME_SAFE_P) + if(!owner.pale) + owner.pale = TRUE + owner.update_body() + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel [word]") + if(prob(1)) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel [word]") + damprob = owner.reagents.has_reagent("inaprovaline") ? 30 : 60 + if(prob(damprob) && damage < 20) + take_damage(1) + if(BLOOD_VOLUME_BAD_P to BLOOD_VOLUME_OKAY_P) + if(!owner.pale) + owner.pale = TRUE + owner.update_body() + owner.blurEyes(6) + damprob = owner.reagents.has_reagent("inaprovaline") ? 40 : 80 + if(prob(damprob) && damage < 40) + take_damage(1) + if(!owner.paralysis && prob(10)) + owner.Paralyse(rand(1,3)) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel extremely [word]") + if(BLOOD_VOLUME_SURVIVE_P to BLOOD_VOLUME_BAD_P) + owner.blurEyes(6) + damprob = owner.reagents.has_reagent("inaprovaline") ? 60 : 100 + if(prob(damprob) && damage < 60) + take_damage(1) + if(!owner.paralysis && prob(15)) + owner.Paralyse(3,5) + var/word = pick("dizzy", "woosey", "faint") + to_chat(src, "You feel extremely [word]") + if(0 to BLOOD_VOLUME_SURVIVE_P) + if(!iszombie(owner)) // zombies dont care about blood + owner.blurEyes(6) + damprob = owner.reagents.has_reagent("inaprovaline") ? 80 : 100 + if(prob(damprob)) + take_damage(1) + if(prob(damprob)) + take_damage(1) + + ..() + + +/obj/item/organ/internal/brain/proc/handle_damage_effects() + if(owner.stat) + return + if(damage > 0 && prob(1)) + owner.custom_pain("Your head feels numb and painful.",10) + if(is_bruised() && prob(1) && owner.eye_blurry <= 0) + to_chat(owner, "It becomes hard to see for some reason.") + owner.eye_blurry = 10 + if(damage >= 0.5*max_damage && prob(1) && owner.get_active_hand()) + to_chat(owner, "Your hand won't respond properly, and you drop what you are holding!") + owner.drop_item() + if(damage >= 0.6*max_damage) + owner.slurring = max(owner.slurring, 2) + if(is_broken()) + if(!owner.lying) + to_chat(owner, "You black out!") + owner.Paralyse(10) + +/obj/item/organ/internal/brain/diona + name = "main node nymph" + cases = list("главная нимфа", "главной нимфы", "главной нимфе", "главную нимфу", "главной нимфой", "главной нимфе") + parent_bodypart = BP_CHEST + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE + +/obj/item/organ/internal/brain/tajaran + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/brain/unathi + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A smallish looking brain." + +/obj/item/organ/internal/brain/vox + name = "cortical-stack" + desc = "A peculiarly advanced bio-electronic device that seems to hold the memories and identity of a Vox." + icon = 'icons/obj/special_organs/vox.dmi' + icon_state = "cortical-stack" + item_state_world = "cortical-stack_world" + compability = list(VOX) + sterile = TRUE + +/obj/item/organ/internal/brain/skrell + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "A brain with a odd division in the middle." + +/obj/item/organ/internal/brain/remove(mob/living/user) + + if(!owner) + return ..() // Probably a redundant removal; just bail + + if(name == initial(name)) + name = "\the [owner.real_name]'s [initial(name)]" + + var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() + + if(borer) + borer.detatch() //Should remove borer if the brain is removed - RR + + transfer_identity(owner) + + ..() + +/obj/item/organ/internal/brain/ipc + name = "positronic brain" + cases = list("позитронный мозг", "позитронного мозга", "позитронному мозгу", "позитронный мозг", "позитронным мозгом", "позитронном мозге") + parent_bodypart = BP_CHEST + requires_robotic_bodypart = TRUE + icon = 'icons/obj/assemblies.dmi' + icon_state = "posibrain-occupied" + item_state_world = "posibrain-occupied" + var/obj/item/device/mmi/posibrain/stored_mmi + + +/obj/item/organ/internal/brain/ipc/remove(mob/living/carbon/human/M) + var/brain_type = /obj/item/device/mmi/posibrain + + var/obj/item/organ/external/BP = owner.get_bodypart(parent_bodypart) + if(istype(BP, /obj/item/organ/external/chest/robot/ipc)) + var/obj/item/organ/external/chest/robot/ipc/I = BP + brain_type = I.posibrain_type + + + var/obj/item/device/mmi/P = new brain_type(owner.loc) + P.transfer_identity(owner) + + ..() + +/obj/item/organ/internal/brain/abomination + name = "deformed brain" + cases = list("деформированный мозг", "деформированного мозга", "деформированному мозгу", "деформированный мозг", "деформированным мозгом", "деформированном мозге") + parent_bodypart = BP_CHEST + +/obj/item/organ/internal/brain/proc/transfer_identity(mob/living/carbon/H) + name = "[H]'s brain" + brainmob = new(src) + brainmob.name = H.real_name + brainmob.real_name = H.real_name + brainmob.dna = H.dna.Clone() + brainmob.timeofhostdeath = H.timeofdeath + if(H.mind) + H.mind.transfer_to(brainmob) + + to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a brain.") + +/obj/item/organ/internal/brain/examine(mob/user) // -- TLE + ..() + if(brainmob && brainmob.client)//if thar be a brain inside... the brain. + to_chat(user, "You can feel the small spark of life still left in this one.") + else + to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later..") diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm new file mode 100644 index 000000000000..60c07f84cd06 --- /dev/null +++ b/code/modules/surgery/organs/eyes.dm @@ -0,0 +1,110 @@ + +/obj/item/organ/internal/eyes + name = "eyes" + icon_state = "eyes" + item_state_world = "eyes_world" + cases = list("глаза", "глаз", "глазам", "глаза", "глазами", "глазах") + organ_tag = O_EYES + parent_bodypart = BP_HEAD + max_damage = 45 + min_bruised_damage = 15 + min_broken_damage = 35 + var/list/eye_colour = list(0,0,0) + var/darksight = 2 + var/nighteyes = FALSE + +/obj/item/organ/internal/eyes/proc/update_colour() + if(!owner) + return + eye_colour = list( + owner.r_eyes ? owner.r_eyes : 0, + owner.g_eyes ? owner.g_eyes : 0, + owner.b_eyes ? owner.b_eyes : 0 + ) + +/obj/item/organ/internal/eyes/insert_organ(mob/living/carbon/human/M) +// Apply our eye colour to the target. + if(istype(M) && eye_colour) + var/mob/living/carbon/human/eyes = M + eyes.r_eyes = eye_colour[1] + eyes.g_eyes = eye_colour[2] + eyes.b_eyes = eye_colour[3] + eyes.update_eyes() + ..() + +/mob/living/carbon/human/proc/update_eyes() + var/obj/item/organ/internal/eyes/eyes = organs_by_name[O_EYES] + if(eyes) + eyes.update_colour() + regenerate_icons() + +/obj/item/organ/internal/eyes/tajaran + name = "tajaran eyeballs" + icon = 'icons/obj/special_organs/tajaran.dmi' + darksight = 8 + nighteyes = TRUE + +/obj/item/organ/internal/eyes/unathi + name = "unathi eyeballs" + icon = 'icons/obj/special_organs/unathi.dmi' + darksight = 3 + +/obj/item/organ/internal/eyes/vox + name = "vox eyeballs" + icon = 'icons/obj/special_organs/vox.dmi' + sterile = TRUE + +/obj/item/organ/internal/eyes/skrell + name = "skrell eyeballs" + icon = 'icons/obj/special_organs/skrell.dmi' + +/obj/item/organ/internal/eyes/diona + name = "nutrient sac" + icon = 'icons/obj/objects.dmi' + icon_state = "podkid" + item_state_world = "podkid" + compability = list(DIONA) + tough = TRUE + +/obj/item/organ/internal/eyes/zombie_vision + name = "zombie eyes" + desc = "A dead set of eyes that don't blink" + darksight = 8 + nighteyes = TRUE + +/obj/item/organ/internal/eyes/night_vision + name = "strange eye" + desc = "Ф pair of eyes that copy the abilities of the Tajaran." + darksight = 8 + nighteyes = TRUE + +/obj/item/organ/internal/eyes/dark_vision + name = "shadow eyes" + desc = "A spooky set of eyes that can see in the dark." + darksight = 8 + +/obj/item/organ/internal/eyes/cybernetic + name = "cybernetic eyes" + icon_state = "eyes-prosthetic" + desc = "An electronic device designed to mimic the functions of a pair of human eyes. It has no benefits over organic eyes, but is easy to produce." + item_state_world = "eyes-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/eyes/ipc + name = "cameras" + cases = list("камеры", "камер", "камерам", "камеры", "камерами", "камерах") + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/robot_component.dmi' + icon_state = "camera" + item_state_world = "camera" + + +/obj/item/organ/internal/eyes/process() //Eye damage replaces the old eye_stat var. + ..() + if(is_bruised()) + owner.blurEyes(20) + if(is_broken()) + owner.eye_blind = 20 diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 1b1911b1aced..b1df525dfafe 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -7,6 +7,8 @@ organ_tag = O_HEART parent_bodypart = BP_CHEST max_damage = 45 + min_bruised_damage = 15 + min_broken_damage = 35 var/heart_beat var/pulse = PULSE_NORM var/base_icon_state = "heart" @@ -27,8 +29,6 @@ item_state_world = "[base_icon_state]-off_world" icon_state = "[base_icon_state]-off" -//work? - /obj/item/organ/internal/heart/process() if(owner) handle_pulse() @@ -96,6 +96,9 @@ /obj/item/organ/internal/heart/proc/handle_blood() + if(!owner) + return + if(!owner.species.flags[NO_BLOOD] && owner.bodytemperature >= 170 || owner.stat == DEAD || !owner) return @@ -177,13 +180,12 @@ else owner.drip(blood_max) // No fancy shooting of blood, just bleeding - -//work! /obj/item/organ/internal/heart/insert_organ(mob/living/carbon/M) ..() owner.metabolism_factor.AddModifier("Heart", multiple = 1.0) + /obj/item/organ/internal/heart/proc/heart_stop() if(!owner.reagents.has_reagent("inaprovaline") || owner.stat == DEAD) heart_status = HEART_FAILURE diff --git a/code/modules/surgery/organs/kidneys.dm b/code/modules/surgery/organs/kidneys.dm new file mode 100644 index 000000000000..5b0e75b5d4a9 --- /dev/null +++ b/code/modules/surgery/organs/kidneys.dm @@ -0,0 +1,101 @@ + +/obj/item/organ/internal/kidneys + name = "kidneys" + cases = list("почки", "почек", "почкам", "почки", "почками", "почках") + icon_state = "kidneys" + item_state_world = "kidneys_world" + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + organ_tag = O_KIDNEYS + parent_bodypart = BP_GROIN + +/obj/item/organ/internal/kidneys/vox + name = "filtration bladder" + cases = list("фильтрующий пузырь", "фильтрующего пузыря", "фильтрующему пузырю", "фильтрующий пузырь", "фильтрующим пузырём", "фильтрующем пузыре") + icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) + sterile = TRUE + +/obj/item/organ/internal/kidneys/tajaran + name = "tajaran kidneys" + icon = 'icons/obj/special_organs/tajaran.dmi' + +/obj/item/organ/internal/kidneys/unathi + name = "unathi kidneys" + icon = 'icons/obj/special_organs/unathi.dmi' + +/obj/item/organ/internal/kidneys/skrell + name = "skrell kidneys" + icon = 'icons/obj/special_organs/skrell.dmi' + desc = "The smallest kidneys you have ever seen, it probably doesn't even work." + +/obj/item/organ/internal/kidneys/diona + name = "vacuole" + cases = list("вакуоль", "вакуоли", "вакуолям", "вакуоль", "вакуолью", "вакуоли") + parent_bodypart = BP_GROIN + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + item_state_world = "nymph" + compability = list(DIONA) + tough = TRUE + +/obj/item/organ/internal/kidneys/cybernetic + name = "cybernetic kidneys" + icon_state = "kidneys-prosthetic" + desc = "An electronic device designed to mimic the functions of human kidneys. It has no benefits over a pair of organic kidneys, but is easy to produce." + item_state_world = "kidneys-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/kidneys/ipc + name = "self-diagnosis unit" + cases = list("устройство самодиагностики", "устройства самодиагностики", "устройству самодиагностики", "устройство самодиагностики", "устройством самодиагностики", "устройстве самодиагностики") + parent_bodypart = BP_GROIN + status = ORGAN_ROBOT + var/next_warning = 0 + requires_robotic_bodypart = TRUE + + icon = 'icons/obj/robot_component.dmi' + icon_state = "analyser" + item_state_world = "analyser" + +/obj/item/organ/internal/kidneys/process() + + ..() + + if(!owner) + return + + // Coffee is really bad for you with busted kidneys. + // This should probably be expanded in some way, but fucked if I know + // what else kidneys can process in our reagent list. + var/datum/reagent/coffee = locate(/datum/reagent/consumable/drink/coffee) in owner.reagents.reagent_list + if(coffee) + if(is_bruised()) + owner.adjustToxLoss(0.1 * process_accuracy) + else if(is_broken()) + owner.adjustToxLoss(0.3 * process_accuracy) + + +/obj/item/organ/internal/kidneys/ipc/process() + if(owner.nutrition < 1) + return + if(next_warning > world.time) + return + next_warning = world.time + 10 SECONDS + + var/damage_report = "" + var/first = TRUE + + for(var/obj/item/organ/internal/IO in owner.organs) + if(IO.is_bruised()) + if(!first) + damage_report += "\n" + first = FALSE + damage_report += "%[uppertext(IO.name)]% INJURY DETECTED. CEASE DAMAGE TO %[uppertext(IO.name)]%. REQUEST ASSISTANCE." + + if(damage_report != "") + to_chat(owner, damage_report) + diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm new file mode 100644 index 000000000000..82bf0e740acb --- /dev/null +++ b/code/modules/surgery/organs/liver.dm @@ -0,0 +1,198 @@ + +/obj/item/organ/internal/liver + name = "liver" + cases = list("печень", "печени", "печени", "печень", "печенью", "печени") + icon_state = "liver" + item_state_world = "liver_world" + organ_tag = O_LIVER + parent_bodypart = BP_GROIN + var/alcohol_intensity = 1 + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + process_accuracy = 10 + +/obj/item/organ/internal/liver/diona + name = "chlorophyll sac" + cases = list("хлорофилловый мешок", "хлорофиллового мешка", "хлорофилловому мешку", "хлорофилловый мешок", "хлорофилловым мешком", "хлорофилловом мешке") + icon = 'icons/obj/objects.dmi' + icon_state = "podkid" + item_state_world = "podkid" + alcohol_intensity = 0.5 + compability = list(DIONA) + tough = TRUE + +/obj/item/organ/internal/liver/vox + name = "waste tract" + cases = list("канал отходов", "канала отходов", "каналу отходов", "канал отходов", "каналом отходов", "канале отходов") + icon = 'icons/obj/special_organs/vox.dmi' + compability = list(VOX) + alcohol_intensity = 1.6 + sterile = TRUE + +/obj/item/organ/internal/liver/tajaran + name = "tajaran liver" + icon = 'icons/obj/special_organs/tajaran.dmi' + alcohol_intensity = 1.4 + +/obj/item/organ/internal/liver/unathi + name = "unathi liver" + icon = 'icons/obj/special_organs/unathi.dmi' + desc = "A large looking liver." + alcohol_intensity = 0.8 + +/obj/item/organ/internal/liver/skrell + name = "skrell liver" + icon = 'icons/obj/special_organs/skrell.dmi' + alcohol_intensity = 0 + +/obj/item/organ/internal/liver/cybernetic + name = "cybernetic liver" + icon_state = "liver-prosthetic" + desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce." + item_state_world = "liver-prosthetic_world" + origin_tech = "biotech=4" + status = ORGAN_ROBOT + compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) + +/obj/item/organ/internal/liver/ipc + name = "accumulator" + cases = list("аккумулятор", "аккумулятора", "аккумулятору", "аккумулятор", "аккумулятором", "аккумуляторе") + var/accumulator_warning = 0 + requires_robotic_bodypart = TRUE + status = ORGAN_ROBOT + icon = 'icons/obj/power.dmi' + icon_state = "hpcell" + item_state_world = "hpcell" + +/obj/item/organ/internal/liver/ipc/set_owner(mob/living/carbon/human/H, datum/species/S) + ..() + new/obj/item/weapon/stock_parts/cell/crap(src) + RegisterSignal(owner, COMSIG_ATOM_ELECTROCUTE_ACT, PROC_REF(ipc_cell_explode)) + +/obj/item/organ/internal/liver/proc/handle_liver_infection() + if(germ_level > INFECTION_LEVEL_ONE) + if(prob(1)) + to_chat(owner, "Your skin itches.") + if(germ_level > INFECTION_LEVEL_TWO) + if(prob(1)) + INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, vomit)) + +/obj/item/organ/internal/liver/proc/handle_liver_life() + if(owner.life_tick % process_accuracy != 0) + return + + if(src.damage < 0) + src.damage = 0 + + //High toxins levels are dangerous + if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("anti_toxin")) + //Healthy liver suffers on its own + if (src.damage < min_broken_damage) + src.damage += 0.2 * process_accuracy + //Damaged one shares the fun + else + var/obj/item/organ/internal/IO = pick(owner.organs) + if(IO) + IO.damage += 0.2 * process_accuracy + + //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 * process_accuracy + + var/blood_total = owner.blood_amount() + + // Blood regeneration if there is some space: + if(blood_total < BLOOD_VOLUME_NORMAL) + var/change_volume = 0.1 // Regenerate blood VERY slowly + if (owner.reagents.has_reagent("nutriment")) // Getting food speeds it up + change_volume += 0.4 + owner.reagents.remove_reagent("nutriment", 0.1) + if (owner.reagents.has_reagent("copper") && owner.get_species(owner) == SKRELL) // skrell blood base on copper + change_volume += 1 + owner.reagents.remove_reagent("copper", 0.1) + if (owner.reagents.has_reagent("iron")) // Hematogen candy anyone? + if(owner.get_species(owner) == SKRELL) // a little more toxins when trying to restore blood with iron + var/mob/living/carbon/human/H = owner + H.adjustToxLoss(1) + else + change_volume += 0.8 + owner.reagents.remove_reagent("iron", 0.1) + owner.blood_add(change_volume) + blood_total += change_volume + + // Damaged liver means some chemicals are very dangerous + if(src.damage >= src.min_bruised_damage) + for(var/datum/reagent/R in owner.reagents.reagent_list) + // Ethanol and all drinks are bad + if(istype(R, /datum/reagent/consumable/ethanol)) + owner.adjustToxLoss(0.1 * process_accuracy) + // Can't cope with toxins at all + if(istype(R, /datum/reagent/toxin)) + owner.adjustToxLoss(0.3 * process_accuracy) + + // Without enough blood you slowly go hungry. + var/blood_volume = owner.get_blood_oxygenation() + if(blood_volume < BLOOD_VOLUME_SAFE_P) + if(owner.nutrition >= 300) + owner.nutrition -= 10 + else if(owner.nutrition >= 200) + owner.nutrition -= 3 + +/obj/item/organ/internal/liver/process() + ..() + if(!owner) + return + + handle_liver_infection() + handle_liver_life() + +/obj/item/organ/internal/liver/serpentid + +/obj/item/organ/internal/liver/serpentid/handle_liver_life() + if(is_bruised()) + if(owner.life_tick % process_accuracy == 0) + for(var/datum/reagent/R in owner.reagents.reagent_list) + if(istype(R, /datum/reagent/consumable/ethanol)) + owner.adjustToxLoss(0.1 * process_accuracy) + if(istype(R, /datum/reagent/toxin)) + owner.adjustToxLoss(0.3 * process_accuracy) + owner.adjustOxyLoss(damage) + + if(owner.reagents.get_reagent_amount("dexalinp") >= 4.0) + return + owner.reagents.add_reagent("dexalinp", REAGENTS_METABOLISM * 1.5) + + if(owner.reagents.get_reagent_amount("dexalinp") >= 3.0) + return + damage += 0.2 + + +/obj/item/organ/internal/liver/ipc/process() + var/obj/item/weapon/stock_parts/cell/C = locate(/obj/item/weapon/stock_parts/cell) in src + + if(!C) + if(!owner.is_bruised_organ(O_KIDNEYS) && prob(2)) + to_chat(owner, "%ACCUMULATOR% DAMAGED BEYOND FUNCTION. SHUTTING DOWN.") + owner.SetParalysis(2) + owner.blurEyes(2) + owner.silent = 2 + return + if(damage) + C.charge = owner.nutrition + if(owner.nutrition > (C.maxcharge - damage * 5)) + owner.nutrition = C.maxcharge - damage * 5 + if(owner.nutrition < 1) + owner.SetParalysis(2) + if(accumulator_warning < world.time) + to_chat(owner, "%ACCUMULATOR% LOW CHARGE. SHUTTING DOWN.") + accumulator_warning = world.time + 15 SECONDS + +/obj/item/organ/internal/liver/ipc/proc/ipc_cell_explode() + var/obj/item/weapon/stock_parts/cell/C = locate() in src + if(!C) + return + var/turf/T = get_turf(owner.loc) + if(owner.nutrition > (C.maxcharge * 1.2)) + explosion(T, 0, 1, 2) + C.ex_act(EXPLODE_DEVASTATE) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index c31a3b386760..1b4df87a484e 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -16,6 +16,7 @@ var/min_breath_pressure = 16 var/last_int_pressure var/last_ext_pressure + var/max_pressure_diff = 60 var/breath_fail_ratio // How badly they failed a breath. Higher is worse. var/poison_type = "phoron" var/last_successful_breath @@ -222,6 +223,10 @@ /obj/item/organ/internal/lungs/process() ..() + + if(!owner) + return + if (owner.species && owner.species.flags[NO_BREATHE]) return if (germ_level > INFECTION_LEVEL_ONE) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index b0db01608ea9..1bc2309674a1 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -54,36 +54,8 @@ owner = H /obj/item/organ/process() + return 0 - //dead already, no need for more processing - if(status & ORGAN_DEAD) - return - - if(is_preserved()) - return - - //Process infections - if ((is_robotic()) || (sterile) ||(owner && owner.species && (owner.species.flags & IS_PLANT))) - germ_level = 0 - return - - if(!owner) - if(reagents) - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in reagents.reagent_list - if(B && prob(40)) - reagents.remove_reagent("blood",0.1) - blood_splatter(src,B,1) - // Maybe scale it down a bit, have it REALLY kick in once past the basic infection threshold - // Another mercy for surgeons preparing transplant organs - germ_level++ - if(germ_level >= INFECTION_LEVEL_ONE) - germ_level += rand(2,6) - if(germ_level >= INFECTION_LEVEL_TWO) - germ_level += rand(2,6) - - else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs - //** Handle antibiotics and curing infections - handle_antibiotics() /obj/item/organ/proc/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) @@ -94,20 +66,6 @@ if(parent_bodypart) parent = owner.bodyparts_by_name[parent_bodypart] -/obj/item/organ/proc/replaced(mob/living/carbon/human/target, obj/item/organ/external/parent_bodypart) - - if(!istype(target)) - return - - owner = target - STOP_PROCESSING(SSobj, src) - parent_bodypart.bodypart_organs |= src - if (!target.get_organ_by_name(src)) - target.organs_by_name += src - target.organs += src - src.loc = target - if(is_robotic()) - status |= ORGAN_ROBOT /obj/item/organ/proc/receive_chem(chemical) return 0 @@ -197,15 +155,6 @@ for(var/obj/item/organ/internal/IO in organs) IO.process() - - var/obj/item/organ/internal/liver/liver = organs_by_name[O_LIVER] - if(!liver && should_have_organ(liver)) - adjustToxLoss(2) - - var/obj/item/organ/internal/kidneys/kidneys = organs_by_name[O_LIVER] - if(!kidneys && should_have_organ(kidneys)) - adjustToxLoss(1) - handle_stance() if(!force_process && !bad_bodyparts.len) diff --git a/code/modules/surgery/organs/organ_helpers.dm b/code/modules/surgery/organs/organ_helpers.dm index 56bc9683f91d..30279fa964c7 100644 --- a/code/modules/surgery/organs/organ_helpers.dm +++ b/code/modules/surgery/organs/organ_helpers.dm @@ -1,3 +1,3 @@ -/mob/living/carbon/human/proc/get_organ_by_name(tag_to_check) - return organs_by_name[tag_to_check] +/mob/living/carbon/human/proc/get_int_organ(typepath) + return (locate(typepath) in organs) diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 99df7aa06e0f..34d5082f4d75 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -44,7 +44,7 @@ /obj/item/organ/internal/remove(mob/living/carbon/human/M) owner = null - STOP_PROCESSING(SSobj, src) + START_PROCESSING(SSobj, src) if(M) M.organs -= src if(M.organs_by_name[organ_tag] == src) @@ -66,26 +66,20 @@ /obj/item/organ/internal/insert_organ(mob/living/carbon/human/H, surgically = FALSE, datum/species/S) ..() - var/obj/item/organ/internal/replaced = H.get_organ_by_name(organ_tag) + var/obj/item/organ/internal/replaced = H.organs_by_name[organ_tag] if(replaced) replaced.remove(H) + qdel(replaced) owner.organs += src owner.organs_by_name[organ_tag] = src - START_PROCESSING(SSobj, src) - if(parent) parent.bodypart_organs += src -/obj/item/organ/internal/replaced(mob/living/carbon/human/target, obj/item/organ/external/affected) - insert_organ(target) - ..() /obj/item/organ/internal/take_damage(amount, silent=0) - if(!isnum(silent)) - return // prevent basic take_damage usage (TODO remove workaround) if(is_robotic()) src.damage += (amount * 0.8) else @@ -115,11 +109,24 @@ if(status & ORGAN_DEAD) return - if (is_robotic() || (owner.species && owner.species.flags[IS_PLANT])) //TODO make robotic organs and bodyparts separate types instead of a flag + if (is_robotic() || (owner && owner.species && owner.species.flags[IS_PLANT])) //TODO make robotic organs and bodyparts separate types instead of a flag germ_level = 0 return - if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs + if(!owner) + if(is_preserved()) + return + // Maybe scale it down a bit, have it REALLY kick in once past the basic infection threshold + // Another mercy for surgeons preparing transplant organs + germ_level++ + if(germ_level >= INFECTION_LEVEL_ONE) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_TWO) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_THREE) + die() + + else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Handle antibiotics and curing infections handle_antibiotics() @@ -158,552 +165,3 @@ /obj/item/organ/internal/proc/bruise() damage = max(damage, min_bruised_damage) -/**************************************************** - ORGANS DEFINES -****************************************************/ - -/obj/item/organ/internal/liver - name = "liver" - cases = list("печень", "печени", "печени", "печень", "печенью", "печени") - icon_state = "liver" - item_state_world = "liver_world" - organ_tag = O_LIVER - parent_bodypart = BP_GROIN - var/alcohol_intensity = 1 - min_bruised_damage = 25 - min_broken_damage = 45 - max_damage = 70 - process_accuracy = 10 - -/obj/item/organ/internal/liver/diona - name = "chlorophyll sac" - cases = list("хлорофилловый мешок", "хлорофиллового мешка", "хлорофилловому мешку", "хлорофилловый мешок", "хлорофилловым мешком", "хлорофилловом мешке") - icon = 'icons/obj/objects.dmi' - icon_state = "podkid" - item_state_world = "podkid" - alcohol_intensity = 0.5 - compability = list(DIONA) - tough = TRUE - -/obj/item/organ/internal/liver/vox - name = "waste tract" - cases = list("канал отходов", "канала отходов", "каналу отходов", "канал отходов", "каналом отходов", "канале отходов") - icon = 'icons/obj/special_organs/vox.dmi' - compability = list(VOX) - alcohol_intensity = 1.6 - sterile = TRUE - -/obj/item/organ/internal/liver/tajaran - name = "tajaran liver" - icon = 'icons/obj/special_organs/tajaran.dmi' - alcohol_intensity = 1.4 - -/obj/item/organ/internal/liver/unathi - name = "unathi liver" - icon = 'icons/obj/special_organs/unathi.dmi' - desc = "A large looking liver." - alcohol_intensity = 0.8 - -/obj/item/organ/internal/liver/skrell - name = "skrell liver" - icon = 'icons/obj/special_organs/skrell.dmi' - alcohol_intensity = 0 - -/obj/item/organ/internal/liver/cybernetic - name = "cybernetic liver" - icon_state = "liver-prosthetic" - desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce." - item_state_world = "liver-prosthetic_world" - origin_tech = "biotech=4" - status = ORGAN_ROBOT - compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/liver/ipc - name = "accumulator" - cases = list("аккумулятор", "аккумулятора", "аккумулятору", "аккумулятор", "аккумулятором", "аккумуляторе") - var/accumulator_warning = 0 - requires_robotic_bodypart = TRUE - status = ORGAN_ROBOT - icon = 'icons/obj/power.dmi' - icon_state = "hpcell" - item_state_world = "hpcell" - -/obj/item/organ/internal/liver/ipc/set_owner(mob/living/carbon/human/H, datum/species/S) - ..() - new/obj/item/weapon/stock_parts/cell/crap(src) - RegisterSignal(owner, COMSIG_ATOM_ELECTROCUTE_ACT, PROC_REF(ipc_cell_explode)) - -/obj/item/organ/internal/liver/proc/handle_liver_infection() - if(germ_level > INFECTION_LEVEL_ONE) - if(prob(1)) - to_chat(owner, "Your skin itches.") - if(germ_level > INFECTION_LEVEL_TWO) - if(prob(1)) - INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, vomit)) - -/obj/item/organ/internal/liver/proc/handle_liver_life() - if(owner.life_tick % process_accuracy != 0) - return - - if(src.damage < 0) - src.damage = 0 - - //High toxins levels are dangerous - if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("anti_toxin")) - //Healthy liver suffers on its own - if (src.damage < min_broken_damage) - src.damage += 0.2 * process_accuracy - //Damaged one shares the fun - else - var/obj/item/organ/internal/IO = pick(owner.organs) - if(IO) - IO.damage += 0.2 * process_accuracy - - //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 * process_accuracy - - var/blood_total = owner.blood_amount() - - // Blood regeneration if there is some space: - if(blood_total < BLOOD_VOLUME_NORMAL) - var/change_volume = 0.1 // Regenerate blood VERY slowly - if (owner.reagents.has_reagent("nutriment")) // Getting food speeds it up - change_volume += 0.4 - owner.reagents.remove_reagent("nutriment", 0.1) - if (owner.reagents.has_reagent("copper") && owner.get_species(owner) == SKRELL) // skrell blood base on copper - change_volume += 1 - owner.reagents.remove_reagent("copper", 0.1) - if (owner.reagents.has_reagent("iron")) // Hematogen candy anyone? - if(owner.get_species(owner) == SKRELL) // a little more toxins when trying to restore blood with iron - var/mob/living/carbon/human/H = owner - H.adjustToxLoss(1) - else - change_volume += 0.8 - owner.reagents.remove_reagent("iron", 0.1) - owner.blood_add(change_volume) - blood_total += change_volume - - // Damaged liver means some chemicals are very dangerous - if(src.damage >= src.min_bruised_damage) - for(var/datum/reagent/R in owner.reagents.reagent_list) - // Ethanol and all drinks are bad - if(istype(R, /datum/reagent/consumable/ethanol)) - owner.adjustToxLoss(0.1 * process_accuracy) - // Can't cope with toxins at all - if(istype(R, /datum/reagent/toxin)) - owner.adjustToxLoss(0.3 * process_accuracy) - - // Without enough blood you slowly go hungry. - var/blood_volume = owner.get_blood_oxygenation() - if(blood_volume < BLOOD_VOLUME_SAFE_P) - if(owner.nutrition >= 300) - owner.nutrition -= 10 - else if(owner.nutrition >= 200) - owner.nutrition -= 3 - -/obj/item/organ/internal/liver/process() - ..() - handle_liver_infection() - handle_liver_life() - -/obj/item/organ/internal/liver/serpentid - -/obj/item/organ/internal/liver/serpentid/handle_liver_life() - if(is_bruised()) - if(owner.life_tick % process_accuracy == 0) - for(var/datum/reagent/R in owner.reagents.reagent_list) - if(istype(R, /datum/reagent/consumable/ethanol)) - owner.adjustToxLoss(0.1 * process_accuracy) - if(istype(R, /datum/reagent/toxin)) - owner.adjustToxLoss(0.3 * process_accuracy) - owner.adjustOxyLoss(damage) - - if(owner.reagents.get_reagent_amount("dexalinp") >= 4.0) - return - owner.reagents.add_reagent("dexalinp", REAGENTS_METABOLISM * 1.5) - - if(owner.reagents.get_reagent_amount("dexalinp") >= 3.0) - return - damage += 0.2 - - -/obj/item/organ/internal/liver/ipc/process() - var/obj/item/weapon/stock_parts/cell/C = locate(/obj/item/weapon/stock_parts/cell) in src - - if(!C) - if(!owner.is_bruised_organ(O_KIDNEYS) && prob(2)) - to_chat(owner, "%ACCUMULATOR% DAMAGED BEYOND FUNCTION. SHUTTING DOWN.") - owner.SetParalysis(2) - owner.blurEyes(2) - owner.silent = 2 - return - if(damage) - C.charge = owner.nutrition - if(owner.nutrition > (C.maxcharge - damage * 5)) - owner.nutrition = C.maxcharge - damage * 5 - if(owner.nutrition < 1) - owner.SetParalysis(2) - if(accumulator_warning < world.time) - to_chat(owner, "%ACCUMULATOR% LOW CHARGE. SHUTTING DOWN.") - accumulator_warning = world.time + 15 SECONDS - -/obj/item/organ/internal/liver/ipc/proc/ipc_cell_explode() - var/obj/item/weapon/stock_parts/cell/C = locate() in src - if(!C) - return - var/turf/T = get_turf(owner.loc) - if(owner.nutrition > (C.maxcharge * 1.2)) - explosion(T, 0, 1, 2) - C.ex_act(EXPLODE_DEVASTATE) - -/obj/item/organ/internal/kidneys - name = "kidneys" - cases = list("почки", "почек", "почкам", "почки", "почками", "почках") - icon_state = "kidneys" - item_state_world = "kidneys_world" - min_bruised_damage = 25 - min_broken_damage = 45 - max_damage = 70 - organ_tag = O_KIDNEYS - parent_bodypart = BP_GROIN - -/obj/item/organ/internal/kidneys/vox - name = "filtration bladder" - cases = list("фильтрующий пузырь", "фильтрующего пузыря", "фильтрующему пузырю", "фильтрующий пузырь", "фильтрующим пузырём", "фильтрующем пузыре") - icon = 'icons/obj/special_organs/vox.dmi' - compability = list(VOX) - sterile = TRUE - -/obj/item/organ/internal/kidneys/tajaran - name = "tajaran kidneys" - icon = 'icons/obj/special_organs/tajaran.dmi' - -/obj/item/organ/internal/kidneys/unathi - name = "unathi kidneys" - icon = 'icons/obj/special_organs/unathi.dmi' - -/obj/item/organ/internal/kidneys/skrell - name = "skrell kidneys" - icon = 'icons/obj/special_organs/skrell.dmi' - desc = "The smallest kidneys you have ever seen, it probably doesn't even work." - -/obj/item/organ/internal/kidneys/diona - name = "vacuole" - cases = list("вакуоль", "вакуоли", "вакуолям", "вакуоль", "вакуолью", "вакуоли") - parent_bodypart = BP_GROIN - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - item_state_world = "nymph" - compability = list(DIONA) - tough = TRUE - -/obj/item/organ/internal/kidneys/cybernetic - name = "cybernetic kidneys" - icon_state = "kidneys-prosthetic" - desc = "An electronic device designed to mimic the functions of human kidneys. It has no benefits over a pair of organic kidneys, but is easy to produce." - item_state_world = "kidneys-prosthetic_world" - origin_tech = "biotech=4" - status = ORGAN_ROBOT - compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/kidneys/ipc - name = "self-diagnosis unit" - cases = list("устройство самодиагностики", "устройства самодиагностики", "устройству самодиагностики", "устройство самодиагностики", "устройством самодиагностики", "устройстве самодиагностики") - parent_bodypart = BP_GROIN - status = ORGAN_ROBOT - var/next_warning = 0 - requires_robotic_bodypart = TRUE - - icon = 'icons/obj/robot_component.dmi' - icon_state = "analyser" - item_state_world = "analyser" - -/obj/item/organ/internal/kidneys/process() - - ..() - - if(!owner) - return - - // Coffee is really bad for you with busted kidneys. - // This should probably be expanded in some way, but fucked if I know - // what else kidneys can process in our reagent list. - var/datum/reagent/coffee = locate(/datum/reagent/consumable/drink/coffee) in owner.reagents.reagent_list - if(coffee) - if(is_bruised()) - owner.adjustToxLoss(0.1 * process_accuracy) - else if(is_broken()) - owner.adjustToxLoss(0.3 * process_accuracy) - - -/obj/item/organ/internal/kidneys/ipc/process() - if(owner.nutrition < 1) - return - if(next_warning > world.time) - return - next_warning = world.time + 10 SECONDS - - var/damage_report = "" - var/first = TRUE - - for(var/obj/item/organ/internal/IO in owner.organs) - if(IO.is_bruised()) - if(!first) - damage_report += "\n" - first = FALSE - damage_report += "%[uppertext(IO.name)]% INJURY DETECTED. CEASE DAMAGE TO %[uppertext(IO.name)]%. REQUEST ASSISTANCE." - - if(damage_report != "") - to_chat(owner, damage_report) - -/obj/item/organ/internal/brain - name = "brain" - cases = list("мозг", "мозга", "мозгу", "мозг", "мозгом", "мозге") - organ_tag = O_BRAIN - vital = TRUE - parent_bodypart = O_BRAIN - icon_state = "brain2" - item_state_world = "brain2_world" - var/oxygen_reserve = 6 - - -/obj/item/organ/internal/brain/process() - - if(!owner) - return - - if(!owner.should_have_organ(O_HEART)) - return - - // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. - var/blood_volume = owner.get_blood_oxygenation() - if(blood_volume < BLOOD_VOLUME_SURVIVE_P) - if(!owner.reagents.has_reagent("inaprovaline") || prob(60)) - oxygen_reserve = max(0, oxygen_reserve-1) - else - oxygen_reserve = min(initial(oxygen_reserve), oxygen_reserve+1) - if(!oxygen_reserve) //(hardcrit) - owner.Paralyse(3) - - // Effects of bloodloss - if(!HAS_TRAIT(src, TRAIT_CPB)) - switch(blood_volume) - if(BLOOD_VOLUME_SAFE_P to 10000) - if(owner.pale) - owner.pale = FALSE - owner.update_body() - if(BLOOD_VOLUME_OKAY_P to BLOOD_VOLUME_SAFE_P) - if(!owner.pale) - owner.pale = TRUE - owner.update_body() - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel [word]") - if(prob(1)) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel [word]") - if(owner.oxyloss < 20) - owner.oxyloss += 3 - if(BLOOD_VOLUME_BAD_P to BLOOD_VOLUME_OKAY_P) - if(!owner.pale) - owner.pale = TRUE - owner.update_body() - owner.blurEyes(6) - if(owner.oxyloss < 50) - owner.oxyloss += 10 - owner.oxyloss += 1 - if(prob(15)) - owner.Paralyse(rand(1,3)) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel extremely [word]") - if(BLOOD_VOLUME_SURVIVE_P to BLOOD_VOLUME_BAD_P) - owner.oxyloss += 5 - if(!owner.paralysis && prob(15)) - owner.Paralyse(3,5) - var/word = pick("dizzy", "woosey", "faint") - to_chat(src, "You feel extremely [word]") - if(0 to BLOOD_VOLUME_SURVIVE_P) - if(!iszombie(owner)) // zombies dont care about blood - owner.blurEyes(6) - owner.Paralyse(6) - owner.Weaken(6) - owner.oxyloss += 15 - - ..() - -/obj/item/organ/internal/brain/diona - name = "main node nymph" - cases = list("главная нимфа", "главной нимфы", "главной нимфе", "главную нимфу", "главной нимфой", "главной нимфе") - parent_bodypart = BP_CHEST - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - item_state_world = "nymph" - compability = list(DIONA) - tough = TRUE - -/obj/item/organ/internal/brain/tajaran - icon = 'icons/obj/special_organs/tajaran.dmi' - -/obj/item/organ/internal/brain/unathi - icon = 'icons/obj/special_organs/unathi.dmi' - desc = "A smallish looking brain." - -/obj/item/organ/internal/brain/vox - name = "cortical-stack" - desc = "A peculiarly advanced bio-electronic device that seems to hold the memories and identity of a Vox." - icon = 'icons/obj/special_organs/vox.dmi' - icon_state = "cortical-stack" - item_state_world = "cortical-stack_world" - compability = list(VOX) - sterile = TRUE - -/obj/item/organ/internal/brain/skrell - icon = 'icons/obj/special_organs/skrell.dmi' - desc = "A brain with a odd division in the middle." - -/obj/item/organ/internal/brain/remove(mob/living/user) - - if(!owner) return ..() // Probably a redundant removal; just bail - var/obj/item/organ/internal/brain/B = src - var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() - - if(borer) - borer.detatch() //Should remove borer if the brain is removed - RR - - B.transfer_identity(user) - - if(ishuman(owner)) - var/mob/living/carbon/human/H = owner - H.update_hair(1) - ..() - -/obj/item/organ/internal/brain/ipc - name = "positronic brain" - cases = list("позитронный мозг", "позитронного мозга", "позитронному мозгу", "позитронный мозг", "позитронным мозгом", "позитронном мозге") - parent_bodypart = BP_CHEST - requires_robotic_bodypart = TRUE - icon = 'icons/obj/assemblies.dmi' - icon_state = "posibrain-occupied" - item_state_world = "posibrain-occupied" - var/obj/item/device/mmi/posibrain/stored_mmi - - -/obj/item/organ/internal/brain/ipc/remove(mob/living/carbon/human/M) - var/brain_type = /obj/item/device/mmi/posibrain - - var/obj/item/organ/external/BP = owner.get_bodypart(parent_bodypart) - if(istype(BP, /obj/item/organ/external/chest/robot/ipc)) - var/obj/item/organ/external/chest/robot/ipc/I = BP - brain_type = I.posibrain_type - - - var/obj/item/device/mmi/P = new brain_type(owner.loc) - P.transfer_identity(owner) - - -/obj/item/organ/internal/brain/abomination - name = "deformed brain" - cases = list("деформированный мозг", "деформированного мозга", "деформированному мозгу", "деформированный мозг", "деформированным мозгом", "деформированном мозге") - parent_bodypart = BP_CHEST - -/obj/item/organ/internal/eyes - name = "eyes" - icon_state = "eyes" - item_state_world = "eyes_world" - cases = list("глаза", "глаз", "глазам", "глаза", "глазами", "глазах") - organ_tag = O_EYES - parent_bodypart = BP_HEAD - max_damage = 45 - var/list/eye_colour = list(0,0,0) - var/darksight = 2 - var/nighteyes = FALSE - -/obj/item/organ/internal/eyes/proc/update_colour() - if(!owner) - return - eye_colour = list( - owner.r_eyes ? owner.r_eyes : 0, - owner.g_eyes ? owner.g_eyes : 0, - owner.b_eyes ? owner.b_eyes : 0 - ) - -/obj/item/organ/internal/eyes/insert_organ(mob/living/carbon/human/M) -// Apply our eye colour to the target. - if(istype(M) && eye_colour) - var/mob/living/carbon/human/eyes = M - eyes.r_eyes = eye_colour[1] - eyes.g_eyes = eye_colour[2] - eyes.b_eyes = eye_colour[3] - eyes.update_eyes() - ..() - -/mob/living/carbon/human/proc/update_eyes() - var/obj/item/organ/internal/eyes/eyes = get_organ_by_name(O_EYES) - if(eyes) - eyes.update_colour() - regenerate_icons() - -/obj/item/organ/internal/eyes/tajaran - name = "tajaran eyeballs" - icon = 'icons/obj/special_organs/tajaran.dmi' - darksight = 8 - nighteyes = TRUE - -/obj/item/organ/internal/eyes/unathi - name = "unathi eyeballs" - icon = 'icons/obj/special_organs/unathi.dmi' - darksight = 3 - -/obj/item/organ/internal/eyes/vox - name = "vox eyeballs" - icon = 'icons/obj/special_organs/vox.dmi' - sterile = TRUE - -/obj/item/organ/internal/eyes/skrell - name = "skrell eyeballs" - icon = 'icons/obj/special_organs/skrell.dmi' - -/obj/item/organ/internal/eyes/diona - name = "nutrient sac" - icon = 'icons/obj/objects.dmi' - icon_state = "podkid" - item_state_world = "podkid" - compability = list(DIONA) - tough = TRUE - -/obj/item/organ/internal/eyes/zombie_vision - name = "zombie eyes" - desc = "A dead set of eyes that don't blink" - darksight = 8 - nighteyes = TRUE - -/obj/item/organ/internal/eyes/night_vision - name = "shadow eyes" - desc = "A spooky set of eyes that can see in the dark." - darksight = 8 - -/obj/item/organ/internal/eyes/cybernetic - name = "cybernetic eyes" - icon_state = "eyes-prosthetic" - desc = "An electronic device designed to mimic the functions of a pair of human eyes. It has no benefits over organic eyes, but is easy to produce." - item_state_world = "eyes-prosthetic_world" - origin_tech = "biotech=4" - status = ORGAN_ROBOT - compability = list(VOX, HUMAN, PLUVIAN, UNATHI, TAJARAN, SKRELL) - -/obj/item/organ/internal/eyes/ipc - name = "cameras" - cases = list("камеры", "камер", "камерам", "камеры", "камерами", "камерах") - requires_robotic_bodypart = TRUE - status = ORGAN_ROBOT - icon = 'icons/obj/robot_component.dmi' - icon_state = "camera" - item_state_world = "camera" - - -/obj/item/organ/internal/eyes/process() //Eye damage replaces the old eye_stat var. - ..() - if(is_bruised()) - owner.blurEyes(20) - if(is_broken()) - owner.eye_blind = 20 diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 2e6db9d5e16c..21427607f54b 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -46,7 +46,7 @@ user.visible_message ( " \The [I] is in no state to be transplanted.") return FALSE - if(target.get_organ_by_name(I)) + if(target.get_int_organ(I)) user.visible_message ( " \The [target] already has [I].") return FALSE @@ -134,3 +134,4 @@ user.visible_message("[user]'s hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!", \ "Your hand slips, scraping tissue inside [target]'s [BP.name] with \the [tool]!") BP.take_damage(20, 0, DAM_SHARP|DAM_EDGE, tool) + diff --git a/taucetistation.dme b/taucetistation.dme index 859ab88a585a..2ccb0b930938 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -1914,7 +1914,6 @@ #include "code\modules\mob\living\carbon\telekinesis.dm" #include "code\modules\mob\living\carbon\update_icons.dm" #include "code\modules\mob\living\carbon\brain\brain.dm" -#include "code\modules\mob\living\carbon\brain\brain_item.dm" #include "code\modules\mob\living\carbon\brain\death.dm" #include "code\modules\mob\living\carbon\brain\emote.dm" #include "code\modules\mob\living\carbon\brain\life.dm" @@ -2480,7 +2479,11 @@ #include "code\modules\surgery\tissue.dm" #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\organs\blood.dm" +#include "code\modules\surgery\organs\brain.dm" +#include "code\modules\surgery\organs\eyes.dm" #include "code\modules\surgery\organs\heart.dm" +#include "code\modules\surgery\organs\kidneys.dm" +#include "code\modules\surgery\organs\liver.dm" #include "code\modules\surgery\organs\lungs.dm" #include "code\modules\surgery\organs\organ.dm" #include "code\modules\surgery\organs\organ_external.dm" From 632a891030ef848f3d21bddfb5e4143100a9d820 Mon Sep 17 00:00:00 2001 From: Triff Date: Wed, 25 Dec 2024 15:25:22 +0400 Subject: [PATCH 23/32] tgui_organs I hope I didn't break everything --- tgui/public/tgui.bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/public/tgui.bundle.js b/tgui/public/tgui.bundle.js index 806cfffa92f5..15f6ecba4138 100644 --- a/tgui/public/tgui.bundle.js +++ b/tgui/public/tgui.bundle.js @@ -1 +1 @@ -!function(){var e={92179:function(e,t,n){"use strict";t.__esModule=!0,t.popperGenerator=h,t.createPopper=void 0;var o=f(n(30505)),r=f(n(43545)),i=f(n(46213)),a=f(n(32440)),c=(f(n(61131)),f(n(45700))),u=f(n(68369)),l=(f(n(38574)),f(n(25435)),f(n(22709)),f(n(36284))),s=f(n(19574));t.detectOverflow=s["default"];var d=n(67458);n(56728);function f(e){return e&&e.__esModule?e:{"default":e}}var p={placement:"bottom",modifiers:[],strategy:"absolute"};function m(){for(var e=arguments.length,t=new Array(e),n=0;n=0&&(0,s.isHTMLElement)(e)?(0,c["default"])(e):e;if(!(0,s.isElement)(n))return[];return t.filter((function(e){return(0,s.isElement)(e)&&(0,p["default"])(e,n)&&"body"!==(0,m["default"])(e)}))}(e):[].concat(t),r=[].concat(o,[n]),i=r[0],u=r.reduce((function(t,n){var o=b(e,n);return t.top=(0,v.max)(o.top,t.top),t.right=(0,v.min)(o.right,t.right),t.bottom=(0,v.min)(o.bottom,t.bottom),t.left=(0,v.max)(o.left,t.left),t}),b(e,i));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u};var o=n(56728),r=g(n(78331)),i=g(n(68692)),a=g(n(46213)),c=g(n(32440)),u=g(n(58386)),l=g(n(61131)),s=n(67458),d=g(n(94294)),f=g(n(31613)),p=g(n(97607)),m=g(n(99624)),h=g(n(20935)),v=n(62836);function g(e){return e&&e.__esModule?e:{"default":e}}function b(e,t){return t===o.viewport?(0,h["default"])((0,r["default"])(e)):(0,s.isHTMLElement)(t)?function(e){var t=(0,d["default"])(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(t):(0,h["default"])((0,i["default"])((0,u["default"])(e)))}},30505:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e,t,n){void 0===n&&(n=!1);var s=(0,a.isHTMLElement)(t),d=(0,a.isHTMLElement)(t)&&function(e){var t=e.getBoundingClientRect(),n=t.width/e.offsetWidth||1,o=t.height/e.offsetHeight||1;return 1!==n||1!==o}(t),f=(0,u["default"])(t),p=(0,o["default"])(e,d),m={scrollLeft:0,scrollTop:0},h={x:0,y:0};(s||!s&&!n)&&(("body"!==(0,i["default"])(t)||(0,l["default"])(f))&&(m=(0,r["default"])(t)),(0,a.isHTMLElement)(t)?((h=(0,o["default"])(t,!0)).x+=t.clientLeft,h.y+=t.clientTop):f&&(h.x=(0,c["default"])(f)));return{x:p.left+m.scrollLeft-h.x,y:p.top+m.scrollTop-h.y,width:p.width,height:p.height}};var o=s(n(94294)),r=s(n(71942)),i=s(n(99624)),a=n(67458),c=s(n(45471)),u=s(n(58386)),l=s(n(37229));function s(e){return e&&e.__esModule?e:{"default":e}}},61131:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return(0,r["default"])(e).getComputedStyle(e)};var o,r=(o=n(31677))&&o.__esModule?o:{"default":o}},58386:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return(((0,o.isElement)(e)?e.ownerDocument:e.document)||window.document).documentElement};var o=n(67458)},68692:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t,n=(0,o["default"])(e),u=(0,a["default"])(e),l=null==(t=e.ownerDocument)?void 0:t.body,s=(0,c.max)(n.scrollWidth,n.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),d=(0,c.max)(n.scrollHeight,n.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0),f=-u.scrollLeft+(0,i["default"])(e),p=-u.scrollTop;"rtl"===(0,r["default"])(l||n).direction&&(f+=(0,c.max)(n.clientWidth,l?l.clientWidth:0)-s);return{width:s,height:d,x:f,y:p}};var o=u(n(58386)),r=u(n(61131)),i=u(n(45471)),a=u(n(1255)),c=n(62836);function u(e){return e&&e.__esModule?e:{"default":e}}},50552:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}},43545:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=(0,r["default"])(e),n=e.offsetWidth,o=e.offsetHeight;Math.abs(t.width-n)<=1&&(n=t.width);Math.abs(t.height-o)<=1&&(o=t.height);return{x:e.offsetLeft,y:e.offsetTop,width:n,height:o}};var o,r=(o=n(94294))&&o.__esModule?o:{"default":o}},99624:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return e?(e.nodeName||"").toLowerCase():null}},71942:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return e!==(0,r["default"])(e)&&(0,i.isHTMLElement)(e)?(0,a["default"])(e):(0,o["default"])(e)};var o=c(n(1255)),r=c(n(31677)),i=n(67458),a=c(n(50552));function c(e){return e&&e.__esModule?e:{"default":e}}},32440:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=(0,o["default"])(e),n=s(e);for(;n&&(0,c["default"])(n)&&"static"===(0,i["default"])(n).position;)n=s(n);if(n&&("html"===(0,r["default"])(n)||"body"===(0,r["default"])(n)&&"static"===(0,i["default"])(n).position))return t;return n||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&(0,a.isHTMLElement)(e)){if("fixed"===(0,i["default"])(e).position)return null}var n=(0,u["default"])(e);for(;(0,a.isHTMLElement)(n)&&["html","body"].indexOf((0,r["default"])(n))<0;){var o=(0,i["default"])(n);if("none"!==o.transform||"none"!==o.perspective||"paint"===o.contain||-1!==["transform","perspective"].indexOf(o.willChange)||t&&"filter"===o.willChange||t&&o.filter&&"none"!==o.filter)return n;n=n.parentNode}return null}(e)||t};var o=l(n(31677)),r=l(n(99624)),i=l(n(61131)),a=n(67458),c=l(n(79130)),u=l(n(31613));function l(e){return e&&e.__esModule?e:{"default":e}}function s(e){return(0,a.isHTMLElement)(e)&&"fixed"!==(0,i["default"])(e).position?e.offsetParent:null}},31613:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){if("html"===(0,o["default"])(e))return e;return e.assignedSlot||e.parentNode||((0,i.isShadowRoot)(e)?e.host:null)||(0,r["default"])(e)};var o=a(n(99624)),r=a(n(58386)),i=n(67458);function a(e){return e&&e.__esModule?e:{"default":e}}},66055:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function u(e){if(["html","body","#document"].indexOf((0,i["default"])(e))>=0)return e.ownerDocument.body;if((0,a.isHTMLElement)(e)&&(0,r["default"])(e))return e;return u((0,o["default"])(e))};var o=c(n(31613)),r=c(n(37229)),i=c(n(99624)),a=n(67458);function c(e){return e&&e.__esModule?e:{"default":e}}},78331:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=(0,o["default"])(e),n=(0,r["default"])(e),a=t.visualViewport,c=n.clientWidth,u=n.clientHeight,l=0,s=0;a&&(c=a.width,u=a.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(l=a.offsetLeft,s=a.offsetTop));return{width:c,height:u,x:l+(0,i["default"])(e),y:s}};var o=a(n(31677)),r=a(n(58386)),i=a(n(45471));function a(e){return e&&e.__esModule?e:{"default":e}}},31677:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}},1255:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=(0,r["default"])(e),n=t.pageXOffset,o=t.pageYOffset;return{scrollLeft:n,scrollTop:o}};var o,r=(o=n(31677))&&o.__esModule?o:{"default":o}},45471:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return(0,o["default"])((0,r["default"])(e)).left+(0,i["default"])(e).scrollLeft};var o=a(n(94294)),r=a(n(58386)),i=a(n(1255));function a(e){return e&&e.__esModule?e:{"default":e}}},67458:function(e,t,n){"use strict";t.__esModule=!0,t.isElement=function(e){var t=(0,r["default"])(e).Element;return e instanceof t||e instanceof Element},t.isHTMLElement=function(e){var t=(0,r["default"])(e).HTMLElement;return e instanceof t||e instanceof HTMLElement},t.isShadowRoot=function(e){if("undefined"==typeof ShadowRoot)return!1;var t=(0,r["default"])(e).ShadowRoot;return e instanceof t||e instanceof ShadowRoot};var o,r=(o=n(31677))&&o.__esModule?o:{"default":o}},37229:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=(0,r["default"])(e),n=t.overflow,o=t.overflowX,i=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+i+o)};var o,r=(o=n(61131))&&o.__esModule?o:{"default":o}},79130:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return["table","td","th"].indexOf((0,r["default"])(e))>=0};var o,r=(o=n(99624))&&o.__esModule?o:{"default":o}},46213:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function u(e,t){var n;void 0===t&&(t=[]);var c=(0,o["default"])(e),l=c===(null==(n=e.ownerDocument)?void 0:n.body),s=(0,i["default"])(c),d=l?[s].concat(s.visualViewport||[],(0,a["default"])(c)?c:[]):c,f=t.concat(d);return l?f:f.concat(u((0,r["default"])(d)))};var o=c(n(66055)),r=c(n(31613)),i=c(n(31677)),a=c(n(37229));function c(e){return e&&e.__esModule?e:{"default":e}}},56728:function(e,t){"use strict";t.__esModule=!0,t.modifierPhases=t.afterWrite=t.write=t.beforeWrite=t.afterMain=t.main=t.beforeMain=t.afterRead=t.read=t.beforeRead=t.placements=t.variationPlacements=t.reference=t.popper=t.viewport=t.clippingParents=t.end=t.start=t.basePlacements=t.auto=t.left=t.right=t.bottom=t.top=void 0;t.top="top";var n="bottom";t.bottom=n;var o="right";t.right=o;var r="left";t.left=r;var i="auto";t.auto=i;var a=["top",n,o,r];t.basePlacements=a;var c="start";t.start=c;var u="end";t.end=u;t.clippingParents="clippingParents";t.viewport="viewport";t.popper="popper";t.reference="reference";var l=a.reduce((function(e,t){return e.concat([t+"-"+c,t+"-"+u])}),[]);t.variationPlacements=l;var s=[].concat(a,[i]).reduce((function(e,t){return e.concat([t,t+"-"+c,t+"-"+u])}),[]);t.placements=s;var d="beforeRead";t.beforeRead=d;var f="read";t.read=f;var p="afterRead";t.afterRead=p;var m="beforeMain";t.beforeMain=m;var h="main";t.main=h;var v="afterMain";t.afterMain=v;var g="beforeWrite";t.beforeWrite=g;var b="write";t.write=b;var C="afterWrite";t.afterWrite=C;var y=[d,f,p,m,h,v,g,b,C];t.modifierPhases=y},34739:function(e,t,n){"use strict";t.__esModule=!0;var o={popperGenerator:!0,detectOverflow:!0,createPopperBase:!0,createPopper:!0,createPopperLite:!0};t.createPopperLite=t.createPopper=t.createPopperBase=t.detectOverflow=t.popperGenerator=void 0;var r=n(56728);Object.keys(r).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(o,e)||e in t&&t[e]===r[e]||(t[e]=r[e]))}));var i=n(18726);Object.keys(i).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(o,e)||e in t&&t[e]===i[e]||(t[e]=i[e]))}));var a=n(92179);t.popperGenerator=a.popperGenerator,t.detectOverflow=a.detectOverflow,t.createPopperBase=a.createPopper;var c=n(48069);t.createPopper=c.createPopper;var u=n(39030);t.createPopperLite=u.createPopper},34559:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o,r=(o=n(99624))&&o.__esModule?o:{"default":o},i=n(67458);var a={name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},o=t.attributes[e]||{},a=t.elements[e];(0,i.isHTMLElement)(a)&&(0,r["default"])(a)&&(Object.assign(a.style,n),Object.keys(o).forEach((function(e){var t=o[e];!1===t?a.removeAttribute(e):a.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach((function(e){var o=t.elements[e],a=t.attributes[e]||{},c=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]).reduce((function(e,t){return e[t]="",e}),{});(0,i.isHTMLElement)(o)&&(0,r["default"])(o)&&(Object.assign(o.style,c),Object.keys(a).forEach((function(e){o.removeAttribute(e)})))}))}},requires:["computeStyles"]};t["default"]=a},76340:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o=f(n(22709)),r=f(n(43545)),i=f(n(97607)),a=f(n(32440)),c=f(n(16615)),u=f(n(52534)),l=f(n(32055)),s=f(n(76294)),d=n(56728);n(67458);function f(e){return e&&e.__esModule?e:{"default":e}}var p=function(e,t){return e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e,(0,l["default"])("number"!=typeof e?e:(0,s["default"])(e,d.basePlacements))};var m={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,i=e.name,l=e.options,s=n.elements.arrow,f=n.modifiersData.popperOffsets,m=(0,o["default"])(n.placement),h=(0,c["default"])(m),v=[d.left,d.right].indexOf(m)>=0?"height":"width";if(s&&f){var g=p(l.padding,n),b=(0,r["default"])(s),C="y"===h?d.top:d.left,y="y"===h?d.bottom:d.right,N=n.rects.reference[v]+n.rects.reference[h]-f[h]-n.rects.popper[v],V=f[h]-n.rects.reference[h],_=(0,a["default"])(s),x=_?"y"===h?_.clientHeight||0:_.clientWidth||0:0,w=N/2-V/2,S=g[C],k=x-b[v]-g[y],E=x/2-b[v]/2+w,B=(0,u["default"])(S,E,k),I=h;n.modifiersData[i]=((t={})[I]=B,t.centerOffset=B-E,t)}},effect:function(e){var t=e.state,n=e.options.element,o=void 0===n?"[data-popper-arrow]":n;null!=o&&("string"!=typeof o||(o=t.elements.popper.querySelector(o)))&&(0,i["default"])(t.elements.popper,o)&&(t.elements.arrow=o)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};t["default"]=m},11300:function(e,t,n){"use strict";t.__esModule=!0,t.mapToStyles=f,t["default"]=void 0;var o=n(56728),r=s(n(32440)),i=s(n(31677)),a=s(n(58386)),c=s(n(61131)),u=s(n(22709)),l=n(62836);function s(e){return e&&e.__esModule?e:{"default":e}}var d={top:"auto",right:"auto",bottom:"auto",left:"auto"};function f(e){var t,n=e.popper,u=e.popperRect,s=e.placement,f=e.offsets,p=e.position,m=e.gpuAcceleration,h=e.adaptive,v=e.roundOffsets,g=!0===v?function(e){var t=e.x,n=e.y,o=window.devicePixelRatio||1;return{x:(0,l.round)((0,l.round)(t*o)/o)||0,y:(0,l.round)((0,l.round)(n*o)/o)||0}}(f):"function"==typeof v?v(f):f,b=g.x,C=void 0===b?0:b,y=g.y,N=void 0===y?0:y,V=f.hasOwnProperty("x"),_=f.hasOwnProperty("y"),x=o.left,w=o.top,S=window;if(h){var k=(0,r["default"])(n),E="clientHeight",B="clientWidth";k===(0,i["default"])(n)&&(k=(0,a["default"])(n),"static"!==(0,c["default"])(k).position&&(E="scrollHeight",B="scrollWidth")),k=k,s===o.top&&(w=o.bottom,N-=k[E]-u.height,N*=m?1:-1),s===o.left&&(x=o.right,C-=k[B]-u.width,C*=m?1:-1)}var I,L=Object.assign({position:p},h&&d);return m?Object.assign({},L,((I={})[w]=_?"0":"",I[x]=V?"0":"",I.transform=(S.devicePixelRatio||1)<2?"translate("+C+"px, "+N+"px)":"translate3d("+C+"px, "+N+"px, 0)",I)):Object.assign({},L,((t={})[w]=_?N+"px":"",t[x]=V?C+"px":"",t.transform="",t))}var p={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options,o=n.gpuAcceleration,r=void 0===o||o,i=n.adaptive,a=void 0===i||i,c=n.roundOffsets,l=void 0===c||c,s={placement:(0,u["default"])(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:r};null!=t.modifiersData.popperOffsets&&(t.styles.popper=Object.assign({},t.styles.popper,f(Object.assign({},s,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:a,roundOffsets:l})))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign({},t.styles.arrow,f(Object.assign({},s,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})},data:{}};t["default"]=p},27020:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o,r=(o=n(31677))&&o.__esModule?o:{"default":o};var i={passive:!0};var a={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var t=e.state,n=e.instance,o=e.options,a=o.scroll,c=void 0===a||a,u=o.resize,l=void 0===u||u,s=(0,r["default"])(t.elements.popper),d=[].concat(t.scrollParents.reference,t.scrollParents.popper);return c&&d.forEach((function(e){e.addEventListener("scroll",n.update,i)})),l&&s.addEventListener("resize",n.update,i),function(){c&&d.forEach((function(e){e.removeEventListener("scroll",n.update,i)})),l&&s.removeEventListener("resize",n.update,i)}},data:{}};t["default"]=a},45922:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o=s(n(70045)),r=s(n(22709)),i=s(n(28916)),a=s(n(19574)),c=s(n(31565)),u=n(56728),l=s(n(45412));function s(e){return e&&e.__esModule?e:{"default":e}}var d={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,s=e.name;if(!t.modifiersData[s]._skip){for(var d=n.mainAxis,f=void 0===d||d,p=n.altAxis,m=void 0===p||p,h=n.fallbackPlacements,v=n.padding,g=n.boundary,b=n.rootBoundary,C=n.altBoundary,y=n.flipVariations,N=void 0===y||y,V=n.allowedAutoPlacements,_=t.options.placement,x=(0,r["default"])(_),w=h||(x===_||!N?[(0,o["default"])(_)]:function(e){if((0,r["default"])(e)===u.auto)return[];var t=(0,o["default"])(e);return[(0,i["default"])(e),t,(0,i["default"])(t)]}(_)),S=[_].concat(w).reduce((function(e,n){return e.concat((0,r["default"])(n)===u.auto?(0,c["default"])(t,{placement:n,boundary:g,rootBoundary:b,padding:v,flipVariations:N,allowedAutoPlacements:V}):n)}),[]),k=t.rects.reference,E=t.rects.popper,B=new Map,I=!0,L=S[0],O=0;O=0,j=P?"width":"height",F=(0,a["default"])(t,{placement:M,boundary:g,rootBoundary:b,altBoundary:C,padding:v}),R=P?T?u.right:u.left:T?u.bottom:u.top;k[j]>E[j]&&(R=(0,o["default"])(R));var D=(0,o["default"])(R),K=[];if(f&&K.push(F[A]<=0),m&&K.push(F[R]<=0,F[D]<=0),K.every((function(e){return e}))){L=M,I=!1;break}B.set(M,K)}if(I)for(var z=function(e){var t=S.find((function(t){var n=B.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return L=t,"break"},W=N?3:1;W>0;W--){if("break"===z(W))break}t.placement!==L&&(t.modifiersData[s]._skip=!0,t.placement=L,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};t["default"]=d},82860:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o,r=n(56728),i=(o=n(19574))&&o.__esModule?o:{"default":o};function a(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function c(e){return[r.top,r.right,r.bottom,r.left].some((function(t){return e[t]>=0}))}var u={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,o=t.rects.reference,r=t.rects.popper,u=t.modifiersData.preventOverflow,l=(0,i["default"])(t,{elementContext:"reference"}),s=(0,i["default"])(t,{altBoundary:!0}),d=a(l,o),f=a(s,r,u),p=c(d),m=c(f);t.modifiersData[n]={referenceClippingOffsets:d,popperEscapeOffsets:f,isReferenceHidden:p,hasPopperEscaped:m},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":m})}};t["default"]=u},18726:function(e,t,n){"use strict";t.__esModule=!0,t.preventOverflow=t.popperOffsets=t.offset=t.hide=t.flip=t.eventListeners=t.computeStyles=t.arrow=t.applyStyles=void 0;var o=f(n(34559));t.applyStyles=o["default"];var r=f(n(76340));t.arrow=r["default"];var i=f(n(11300));t.computeStyles=i["default"];var a=f(n(27020));t.eventListeners=a["default"];var c=f(n(45922));t.flip=c["default"];var u=f(n(82860));t.hide=u["default"];var l=f(n(33310));t.offset=l["default"];var s=f(n(74371));t.popperOffsets=s["default"];var d=f(n(21532));function f(e){return e&&e.__esModule?e:{"default":e}}t.preventOverflow=d["default"]},33310:function(e,t,n){"use strict";t.__esModule=!0,t.distanceAndSkiddingToXY=a,t["default"]=void 0;var o,r=(o=n(22709))&&o.__esModule?o:{"default":o},i=n(56728);function a(e,t,n){var o=(0,r["default"])(e),a=[i.left,i.top].indexOf(o)>=0?-1:1,c="function"==typeof n?n(Object.assign({},t,{placement:e})):n,u=c[0],l=c[1];return u=u||0,l=(l||0)*a,[i.left,i.right].indexOf(o)>=0?{x:l,y:u}:{x:u,y:l}}var c={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.options,o=e.name,r=n.offset,c=void 0===r?[0,0]:r,u=i.placements.reduce((function(e,n){return e[n]=a(n,t.rects,c),e}),{}),l=u[t.placement],s=l.x,d=l.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=s,t.modifiersData.popperOffsets.y+=d),t.modifiersData[o]=u}};t["default"]=c},74371:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o,r=(o=n(17175))&&o.__esModule?o:{"default":o};var i={name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state,n=e.name;t.modifiersData[n]=(0,r["default"])({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}};t["default"]=i},21532:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=void 0;var o=n(56728),r=m(n(22709)),i=m(n(16615)),a=m(n(82898)),c=m(n(52534)),u=m(n(43545)),l=m(n(32440)),s=m(n(19574)),d=m(n(45412)),f=m(n(41801)),p=n(62836);function m(e){return e&&e.__esModule?e:{"default":e}}var h={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,m=e.name,h=n.mainAxis,v=void 0===h||h,g=n.altAxis,b=void 0!==g&&g,C=n.boundary,y=n.rootBoundary,N=n.altBoundary,V=n.padding,_=n.tether,x=void 0===_||_,w=n.tetherOffset,S=void 0===w?0:w,k=(0,s["default"])(t,{boundary:C,rootBoundary:y,padding:V,altBoundary:N}),E=(0,r["default"])(t.placement),B=(0,d["default"])(t.placement),I=!B,L=(0,i["default"])(E),O=(0,a["default"])(L),M=t.modifiersData.popperOffsets,A=t.rects.reference,T=t.rects.popper,P="function"==typeof S?S(Object.assign({},t.rects,{placement:t.placement})):S,j={x:0,y:0};if(M){if(v||b){var F="y"===L?o.top:o.left,R="y"===L?o.bottom:o.right,D="y"===L?"height":"width",K=M[L],z=M[L]+k[F],W=M[L]-k[R],Y=x?-T[D]/2:0,U=B===o.start?A[D]:T[D],H=B===o.start?-T[D]:-A[D],G=t.elements.arrow,$=x&&G?(0,u["default"])(G):{width:0,height:0},q=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:(0,f["default"])(),X=q[F],Q=q[R],J=(0,c["default"])(0,A[D],$[D]),Z=I?A[D]/2-Y-J-X-P:U-J-X-P,ee=I?-A[D]/2+Y+J+Q+P:H+J+Q+P,te=t.elements.arrow&&(0,l["default"])(t.elements.arrow),ne=te?"y"===L?te.clientTop||0:te.clientLeft||0:0,oe=t.modifiersData.offset?t.modifiersData.offset[t.placement][L]:0,re=M[L]+Z-oe-ne,ie=M[L]+ee-oe;if(v){var ae=(0,c["default"])(x?(0,p.min)(z,re):z,K,x?(0,p.max)(W,ie):W);M[L]=ae,j[L]=ae-K}if(b){var ce="x"===L?o.top:o.left,ue="x"===L?o.bottom:o.right,le=M[O],se=le+k[ce],de=le-k[ue],fe=(0,c["default"])(x?(0,p.min)(se,re):se,le,x?(0,p.max)(de,ie):de);M[O]=fe,j[O]=fe-le}}t.modifiersData[m]=j}},requiresIfExists:["offset"]};t["default"]=h},39030:function(e,t,n){"use strict";t.__esModule=!0,t.defaultModifiers=t.createPopper=void 0;var o=n(92179);t.popperGenerator=o.popperGenerator,t.detectOverflow=o.detectOverflow;var r=u(n(27020)),i=u(n(74371)),a=u(n(11300)),c=u(n(34559));function u(e){return e&&e.__esModule?e:{"default":e}}var l=[r["default"],i["default"],a["default"],c["default"]];t.defaultModifiers=l;var s=(0,o.popperGenerator)({defaultModifiers:l});t.createPopper=s},48069:function(e,t,n){"use strict";t.__esModule=!0;var o={createPopper:!0,createPopperLite:!0,defaultModifiers:!0,popperGenerator:!0,detectOverflow:!0};t.defaultModifiers=t.createPopperLite=t.createPopper=void 0;var r=n(92179);t.popperGenerator=r.popperGenerator,t.detectOverflow=r.detectOverflow;var i=v(n(27020)),a=v(n(74371)),c=v(n(11300)),u=v(n(34559)),l=v(n(33310)),s=v(n(45922)),d=v(n(21532)),f=v(n(76340)),p=v(n(82860)),m=n(39030);t.createPopperLite=m.createPopper;var h=n(18726);function v(e){return e&&e.__esModule?e:{"default":e}}Object.keys(h).forEach((function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(o,e)||e in t&&t[e]===h[e]||(t[e]=h[e]))}));var g=[i["default"],a["default"],c["default"],u["default"],l["default"],s["default"],d["default"],f["default"],p["default"]];t.defaultModifiers=g;var b=(0,r.popperGenerator)({defaultModifiers:g});t.createPopperLite=t.createPopper=b},31565:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e,t){void 0===t&&(t={});var n=t,c=n.placement,u=n.boundary,l=n.rootBoundary,s=n.padding,d=n.flipVariations,f=n.allowedAutoPlacements,p=void 0===f?r.placements:f,m=(0,o["default"])(c),h=m?d?r.variationPlacements:r.variationPlacements.filter((function(e){return(0,o["default"])(e)===m})):r.basePlacements,v=h.filter((function(e){return p.indexOf(e)>=0}));0===v.length&&(v=h);var g=v.reduce((function(t,n){return t[n]=(0,i["default"])(e,{placement:n,boundary:u,rootBoundary:l,padding:s})[(0,a["default"])(n)],t}),{});return Object.keys(g).sort((function(e,t){return g[e]-g[t]}))};var o=c(n(45412)),r=n(56728),i=c(n(19574)),a=c(n(22709));function c(e){return e&&e.__esModule?e:{"default":e}}},17175:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t,n=e.reference,c=e.element,u=e.placement,l=u?(0,o["default"])(u):null,s=u?(0,r["default"])(u):null,d=n.x+n.width/2-c.width/2,f=n.y+n.height/2-c.height/2;switch(l){case a.top:t={x:d,y:n.y-c.height};break;case a.bottom:t={x:d,y:n.y+n.height};break;case a.right:t={x:n.x+n.width,y:f};break;case a.left:t={x:n.x-c.width,y:f};break;default:t={x:n.x,y:n.y}}var p=l?(0,i["default"])(l):null;if(null!=p){var m="y"===p?"height":"width";switch(s){case a.start:t[p]=t[p]-(n[m]/2-c[m]/2);break;case a.end:t[p]=t[p]+(n[m]/2-c[m]/2)}}return t};var o=c(n(22709)),r=c(n(45412)),i=c(n(16615)),a=n(56728);function c(e){return e&&e.__esModule?e:{"default":e}}},68369:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){var t;return function(){return t||(t=new Promise((function(n){Promise.resolve().then((function(){t=undefined,n(e())}))}))),t}}},19574:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e,t){void 0===t&&(t={});var n=t,f=n.placement,p=void 0===f?e.placement:f,m=n.boundary,h=void 0===m?u.clippingParents:m,v=n.rootBoundary,g=void 0===v?u.viewport:v,b=n.elementContext,C=void 0===b?u.popper:b,y=n.altBoundary,N=void 0!==y&&y,V=n.padding,_=void 0===V?0:V,x=(0,s["default"])("number"!=typeof _?_:(0,d["default"])(_,u.basePlacements)),w=C===u.popper?u.reference:u.popper,S=e.elements.reference,k=e.rects.popper,E=e.elements[N?w:C],B=(0,r["default"])((0,l.isElement)(E)?E:E.contextElement||(0,i["default"])(e.elements.popper),h,g),I=(0,o["default"])(S),L=(0,a["default"])({reference:I,element:k,strategy:"absolute",placement:p}),O=(0,c["default"])(Object.assign({},k,L)),M=C===u.popper?O:I,A={top:B.top-M.top+x.top,bottom:M.bottom-B.bottom+x.bottom,left:B.left-M.left+x.left,right:M.right-B.right+x.right},T=e.modifiersData.offset;if(C===u.popper&&T){var P=T[p];Object.keys(A).forEach((function(e){var t=[u.right,u.bottom].indexOf(e)>=0?1:-1,n=[u.top,u.bottom].indexOf(e)>=0?"y":"x";A[e]+=P[n]*t}))}return A};var o=f(n(94294)),r=f(n(48162)),i=f(n(58386)),a=f(n(17175)),c=f(n(20935)),u=n(56728),l=n(67458),s=f(n(32055)),d=f(n(76294));function f(e){return e&&e.__esModule?e:{"default":e}}},76294:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}},41434:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o=0?"x":"y"}},70045:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return e.replace(/left|right|bottom|top/g,(function(e){return n[e]}))};var n={left:"right",right:"left",bottom:"top",top:"bottom"}},28916:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return e.replace(/start|end/g,(function(e){return n[e]}))};var n={start:"end",end:"start"}},45412:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return e.split("-")[1]}},62836:function(e,t){"use strict";t.__esModule=!0,t.round=t.min=t.max=void 0;var n=Math.max;t.max=n;var o=Math.min;t.min=o;var r=Math.round;t.round=r},36284:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){var t=e.reduce((function(e,t){var n=e[t.name];return e[t.name]=n?Object.assign({},n,t,{options:Object.assign({},n.options,t.options),data:Object.assign({},n.data,t.data)}):t,e}),{});return Object.keys(t).map((function(e){return t[e]}))}},32055:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){return Object.assign({},(0,r["default"])(),e)};var o,r=(o=n(41801))&&o.__esModule?o:{"default":o}},45700:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){var t=function(e){var t=new Map,n=new Set,o=[];function r(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var o=t.get(e);o&&r(o)}})),o.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||r(e)})),o}(e);return o.modifierPhases.reduce((function(e,n){return e.concat(t.filter((function(e){return e.phase===n})))}),[])};var o=n(56728)},20935:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}},25435:function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e,t){var n=new Set;return e.filter((function(e){var o=t(e);if(!n.has(o))return n.add(o),!0}))}},38574:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e){e.forEach((function(t){Object.keys(t).forEach((function(n){switch(n){case"name":t.name;break;case"enabled":t.enabled;case"phase":r.modifierPhases.indexOf(t.phase);break;case"fn":t.fn;break;case"effect":t.effect;break;case"requires":Array.isArray(t.requires);break;case"requiresIfExists":Array.isArray(t.requiresIfExists)}t.requires&&t.requires.forEach((function(t){e.find((function(e){return e.name===t}))}))}))}))};(o=n(41434))&&o.__esModule;var o,r=n(56728)},52534:function(e,t,n){"use strict";t.__esModule=!0,t["default"]=function(e,t,n){return(0,o.max)(e,(0,o.min)(t,n))};var o=n(62836)},83923:function(e){"use strict";e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},1372:function(e,t,n){"use strict";var o=n(35611);e.exports=function(e){if(!o(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},36910:function(e,t,n){"use strict";var o=n(17657),r=n(83681),i=n(74217),a=o("unscopables"),c=Array.prototype;c[a]==undefined&&i.f(c,a,{configurable:!0,value:r(null)}),e.exports=function(e){c[a][e]=!0}},69953:function(e,t,n){"use strict";var o=n(37015).charAt;e.exports=function(e,t,n){return t+(n?o(e,t).length:1)}},50997:function(e){"use strict";e.exports=function(e,t,n){if(!(e instanceof t))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return e}},63518:function(e,t,n){"use strict";var o=n(35611);e.exports=function(e){if(!o(e))throw TypeError(String(e)+" is not an object");return e}},32977:function(e){"use strict";e.exports="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof DataView},19216:function(e,t,n){"use strict";var o,r,i,a=n(32977),c=n(75592),u=n(84253),l=n(35611),s=n(28919),d=n(47953),f=n(52188),p=n(11807),m=n(74217).f,h=n(6863),v=n(18444),g=n(17657),b=n(41080),C=u.Int8Array,y=C&&C.prototype,N=u.Uint8ClampedArray,V=N&&N.prototype,_=C&&h(C),x=y&&h(y),w=Object.prototype,S=w.isPrototypeOf,k=g("toStringTag"),E=b("TYPED_ARRAY_TAG"),B=b("TYPED_ARRAY_CONSTRUCTOR"),I=a&&!!v&&"Opera"!==d(u.opera),L=!1,O={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},M={BigInt64Array:8,BigUint64Array:8},A=function(e){if(!l(e))return!1;var t=d(e);return"DataView"===t||s(O,t)||s(M,t)},T=function(e){if(!l(e))return!1;var t=d(e);return s(O,t)||s(M,t)};for(o in O)(i=(r=u[o])&&r.prototype)?f(i,B,r):I=!1;for(o in M)(i=(r=u[o])&&r.prototype)&&f(i,B,r);if((!I||"function"!=typeof _||_===Function.prototype)&&(_=function(){throw TypeError("Incorrect invocation")},I))for(o in O)u[o]&&v(u[o],_);if((!I||!x||x===w)&&(x=_.prototype,I))for(o in O)u[o]&&v(u[o].prototype,x);if(I&&h(V)!==x&&v(V,x),c&&!s(x,k))for(o in L=!0,m(x,k,{get:function(){return l(this)?this[E]:undefined}}),O)u[o]&&f(u[o],E,o);e.exports={NATIVE_ARRAY_BUFFER_VIEWS:I,TYPED_ARRAY_CONSTRUCTOR:B,TYPED_ARRAY_TAG:L&&E,aTypedArray:function(e){if(T(e))return e;throw TypeError("Target is not a typed array")},aTypedArrayConstructor:function(e){if(v&&!S.call(_,e))throw TypeError("Target is not a typed array constructor");return e},exportTypedArrayMethod:function(e,t,n){if(c){if(n)for(var o in O){var r=u[o];if(r&&s(r.prototype,e))try{delete r.prototype[e]}catch(i){}}x[e]&&!n||p(x,e,n?t:I&&y[e]||t)}},exportTypedArrayStaticMethod:function(e,t,n){var o,r;if(c){if(v){if(n)for(o in O)if((r=u[o])&&s(r,e))try{delete r[e]}catch(i){}if(_[e]&&!n)return;try{return p(_,e,n?t:I&&_[e]||t)}catch(i){}}for(o in O)!(r=u[o])||r[e]&&!n||p(r,e,t)}},isView:A,isTypedArray:T,TypedArray:_,TypedArrayPrototype:x}},80246:function(e,t,n){"use strict";var o=n(84253),r=n(75592),i=n(32977),a=n(52188),c=n(3993),u=n(69691),l=n(50997),s=n(3997),d=n(39570),f=n(77559),p=n(16567),m=n(6863),h=n(18444),v=n(78870).f,g=n(74217).f,b=n(22051),C=n(29108),y=n(79947),N=y.get,V=y.set,_="ArrayBuffer",x="DataView",w="Wrong index",S=o.ArrayBuffer,k=S,E=o.DataView,B=E&&E.prototype,I=Object.prototype,L=o.RangeError,O=p.pack,M=p.unpack,A=function(e){return[255&e]},T=function(e){return[255&e,e>>8&255]},P=function(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]},j=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},F=function(e){return O(e,23,4)},R=function(e){return O(e,52,8)},D=function(e,t){g(e.prototype,t,{get:function(){return N(this)[t]}})},K=function(e,t,n,o){var r=f(n),i=N(e);if(r+t>i.byteLength)throw L(w);var a=N(i.buffer).bytes,c=r+i.byteOffset,u=a.slice(c,c+t);return o?u:u.reverse()},z=function(e,t,n,o,r,i){var a=f(n),c=N(e);if(a+t>c.byteLength)throw L(w);for(var u=N(c.buffer).bytes,l=a+c.byteOffset,s=o(+r),d=0;dH;)(W=U[H++])in k||a(k,W,S[W]);Y.constructor=k}h&&m(B)!==I&&h(B,I);var G=new E(new k(2)),$=B.setInt8;G.setInt8(0,2147483648),G.setInt8(1,2147483649),!G.getInt8(0)&&G.getInt8(1)||c(B,{setInt8:function(e,t){$.call(this,e,t<<24>>24)},setUint8:function(e,t){$.call(this,e,t<<24>>24)}},{unsafe:!0})}else k=function(e){l(this,k,_);var t=f(e);V(this,{bytes:b.call(new Array(t),0),byteLength:t}),r||(this.byteLength=t)},E=function(e,t,n){l(this,E,x),l(e,k,x);var o=N(e).byteLength,i=s(t);if(i<0||i>o)throw L("Wrong offset");if(i+(n=n===undefined?o-i:d(n))>o)throw L("Wrong length");V(this,{buffer:e,byteLength:n,byteOffset:i}),r||(this.buffer=e,this.byteLength=n,this.byteOffset=i)},r&&(D(k,"byteLength"),D(E,"buffer"),D(E,"byteLength"),D(E,"byteOffset")),c(E.prototype,{getInt8:function(e){return K(this,1,e)[0]<<24>>24},getUint8:function(e){return K(this,1,e)[0]},getInt16:function(e){var t=K(this,2,e,arguments.length>1?arguments[1]:undefined);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=K(this,2,e,arguments.length>1?arguments[1]:undefined);return t[1]<<8|t[0]},getInt32:function(e){return j(K(this,4,e,arguments.length>1?arguments[1]:undefined))},getUint32:function(e){return j(K(this,4,e,arguments.length>1?arguments[1]:undefined))>>>0},getFloat32:function(e){return M(K(this,4,e,arguments.length>1?arguments[1]:undefined),23)},getFloat64:function(e){return M(K(this,8,e,arguments.length>1?arguments[1]:undefined),52)},setInt8:function(e,t){z(this,1,e,A,t)},setUint8:function(e,t){z(this,1,e,A,t)},setInt16:function(e,t){z(this,2,e,T,t,arguments.length>2?arguments[2]:undefined)},setUint16:function(e,t){z(this,2,e,T,t,arguments.length>2?arguments[2]:undefined)},setInt32:function(e,t){z(this,4,e,P,t,arguments.length>2?arguments[2]:undefined)},setUint32:function(e,t){z(this,4,e,P,t,arguments.length>2?arguments[2]:undefined)},setFloat32:function(e,t){z(this,4,e,F,t,arguments.length>2?arguments[2]:undefined)},setFloat64:function(e,t){z(this,8,e,R,t,arguments.length>2?arguments[2]:undefined)}});C(k,_),C(E,x),e.exports={ArrayBuffer:k,DataView:E}},59571:function(e,t,n){"use strict";var o=n(12104),r=n(55205),i=n(39570),a=Math.min;e.exports=[].copyWithin||function(e,t){var n=o(this),c=i(n.length),u=r(e,c),l=r(t,c),s=arguments.length>2?arguments[2]:undefined,d=a((s===undefined?c:r(s,c))-l,c-u),f=1;for(l0;)l in n?n[u]=n[l]:delete n[u],u+=f,l+=f;return n}},22051:function(e,t,n){"use strict";var o=n(12104),r=n(55205),i=n(39570);e.exports=function(e){for(var t=o(this),n=i(t.length),a=arguments.length,c=r(a>1?arguments[1]:undefined,n),u=a>2?arguments[2]:undefined,l=u===undefined?n:r(u,n);l>c;)t[c++]=e;return t}},90369:function(e,t,n){"use strict";var o=n(69033).forEach,r=n(37902)("forEach");e.exports=r?[].forEach:function(e){return o(this,e,arguments.length>1?arguments[1]:undefined)}},11955:function(e){"use strict";e.exports=function(e,t){for(var n=0,o=t.length,r=new e(o);o>n;)r[n]=t[n++];return r}},28213:function(e,t,n){"use strict";var o=n(74271),r=n(12104),i=n(32648),a=n(14195),c=n(39570),u=n(39241),l=n(3170);e.exports=function(e){var t,n,s,d,f,p,m=r(e),h="function"==typeof this?this:Array,v=arguments.length,g=v>1?arguments[1]:undefined,b=g!==undefined,C=l(m),y=0;if(b&&(g=o(g,v>2?arguments[2]:undefined,2)),C==undefined||h==Array&&a(C))for(n=new h(t=c(m.length));t>y;y++)p=b?g(m[y],y):m[y],u(n,y,p);else for(f=(d=C.call(m)).next,n=new h;!(s=f.call(d)).done;y++)p=b?i(d,g,[s.value,y],!0):s.value,u(n,y,p);return n.length=y,n}},25945:function(e,t,n){"use strict";var o=n(26553),r=n(39570),i=n(55205),a=function(e){return function(t,n,a){var c,u=o(t),l=r(u.length),s=i(a,l);if(e&&n!=n){for(;l>s;)if((c=u[s++])!=c)return!0}else for(;l>s;s++)if((e||s in u)&&u[s]===n)return e||s||0;return!e&&-1}};e.exports={includes:a(!0),indexOf:a(!1)}},69033:function(e,t,n){"use strict";var o=n(74271),r=n(50990),i=n(12104),a=n(39570),c=n(77454),u=[].push,l=function(e){var t=1==e,n=2==e,l=3==e,s=4==e,d=6==e,f=7==e,p=5==e||d;return function(m,h,v,g){for(var b,C,y=i(m),N=r(y),V=o(h,v,3),_=a(N.length),x=0,w=g||c,S=t?w(m,_):n||f?w(m,0):undefined;_>x;x++)if((p||x in N)&&(C=V(b=N[x],x,y),e))if(t)S[x]=C;else if(C)switch(e){case 3:return!0;case 5:return b;case 6:return x;case 2:u.call(S,b)}else switch(e){case 4:return!1;case 7:u.call(S,b)}return d?-1:l||s?s:S}};e.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},41183:function(e,t,n){"use strict";var o=n(26553),r=n(3997),i=n(39570),a=n(37902),c=Math.min,u=[].lastIndexOf,l=!!u&&1/[1].lastIndexOf(1,-0)<0,s=a("lastIndexOf"),d=l||!s;e.exports=d?function(e){if(l)return u.apply(this,arguments)||0;var t=o(this),n=i(t.length),a=n-1;for(arguments.length>1&&(a=c(a,r(arguments[1]))),a<0&&(a=n+a);a>=0;a--)if(a in t&&t[a]===e)return a||0;return-1}:u},93537:function(e,t,n){"use strict";var o=n(69691),r=n(17657),i=n(12338),a=r("species");e.exports=function(e){return i>=51||!o((function(){var t=[];return(t.constructor={})[a]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},37902:function(e,t,n){"use strict";var o=n(69691);e.exports=function(e,t){var n=[][e];return!!n&&o((function(){n.call(null,t||function(){throw 1},1)}))}},28249:function(e,t,n){"use strict";var o=n(83923),r=n(12104),i=n(50990),a=n(39570),c=function(e){return function(t,n,c,u){o(n);var l=r(t),s=i(l),d=a(l.length),f=e?d-1:0,p=e?-1:1;if(c<2)for(;;){if(f in s){u=s[f],f+=p;break}if(f+=p,e?f<0:d<=f)throw TypeError("Reduce of empty array with no initial value")}for(;e?f>=0:d>f;f+=p)f in s&&(u=n(u,s[f],f,l));return u}};e.exports={left:c(!1),right:c(!0)}},58737:function(e){"use strict";var t=Math.floor,n=function(e,t){for(var n,o,r=e.length,i=1;i0;)e[o]=e[--o];o!==i++&&(e[o]=n)}return e},o=function(e,t,n){for(var o=e.length,r=t.length,i=0,a=0,c=[];i1?arguments[1]:undefined,3);t=t?t.next:n.first;)for(o(t.value,t.key,this);t&&t.removed;)t=t.previous},has:function(e){return!!g(this,e)}}),i(s.prototype,n?{get:function(e){var t=g(this,e);return t&&t.value},set:function(e,t){return v(this,0===e?0:e,t)}}:{add:function(e){return v(this,e=0===e?0:e,e)}}),d&&o(s.prototype,"size",{get:function(){return p(this).size}}),s},setStrong:function(e,t,n){var o=t+" Iterator",r=h(t),i=h(o);l(e,t,(function(e,t){m(this,{type:o,target:e,state:r(e),kind:t,last:undefined})}),(function(){for(var e=i(this),t=e.kind,n=e.last;n&&n.removed;)n=n.previous;return e.target&&(e.last=n=n?n.next:e.state.first)?"keys"==t?{value:n.key,done:!1}:"values"==t?{value:n.value,done:!1}:{value:[n.key,n.value],done:!1}:(e.target=undefined,{value:undefined,done:!0})}),n?"entries":"values",!n,!0),s(t)}}},57396:function(e,t,n){"use strict";var o=n(3993),r=n(40421).getWeakData,i=n(63518),a=n(35611),c=n(50997),u=n(56342),l=n(69033),s=n(28919),d=n(79947),f=d.set,p=d.getterFor,m=l.find,h=l.findIndex,v=0,g=function(e){return e.frozen||(e.frozen=new b)},b=function(){this.entries=[]},C=function(e,t){return m(e.entries,(function(e){return e[0]===t}))};b.prototype={get:function(e){var t=C(this,e);if(t)return t[1]},has:function(e){return!!C(this,e)},set:function(e,t){var n=C(this,e);n?n[1]=t:this.entries.push([e,t])},"delete":function(e){var t=h(this.entries,(function(t){return t[0]===e}));return~t&&this.entries.splice(t,1),!!~t}},e.exports={getConstructor:function(e,t,n,l){var d=e((function(e,o){c(e,d,t),f(e,{type:t,id:v++,frozen:undefined}),o!=undefined&&u(o,e[l],{that:e,AS_ENTRIES:n})})),m=p(t),h=function(e,t,n){var o=m(e),a=r(i(t),!0);return!0===a?g(o).set(t,n):a[o.id]=n,e};return o(d.prototype,{"delete":function(e){var t=m(this);if(!a(e))return!1;var n=r(e);return!0===n?g(t)["delete"](e):n&&s(n,t.id)&&delete n[t.id]},has:function(e){var t=m(this);if(!a(e))return!1;var n=r(e);return!0===n?g(t).has(e):n&&s(n,t.id)}}),o(d.prototype,n?{get:function(e){var t=m(this);if(a(e)){var n=r(e);return!0===n?g(t).get(e):n?n[t.id]:undefined}},set:function(e,t){return h(this,e,t)}}:{add:function(e){return h(this,e,!0)}}),d}}},42006:function(e,t,n){"use strict";var o=n(56174),r=n(84253),i=n(41441),a=n(11807),c=n(40421),u=n(56342),l=n(50997),s=n(35611),d=n(69691),f=n(68762),p=n(29108),m=n(22285);e.exports=function(e,t,n){var h=-1!==e.indexOf("Map"),v=-1!==e.indexOf("Weak"),g=h?"set":"add",b=r[e],C=b&&b.prototype,y=b,N={},V=function(e){var t=C[e];a(C,e,"add"==e?function(e){return t.call(this,0===e?0:e),this}:"delete"==e?function(e){return!(v&&!s(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return v&&!s(e)?undefined:t.call(this,0===e?0:e)}:"has"==e?function(e){return!(v&&!s(e))&&t.call(this,0===e?0:e)}:function(e,n){return t.call(this,0===e?0:e,n),this})};if(i(e,"function"!=typeof b||!(v||C.forEach&&!d((function(){(new b).entries().next()})))))y=n.getConstructor(t,e,h,g),c.enable();else if(i(e,!0)){var _=new y,x=_[g](v?{}:-0,1)!=_,w=d((function(){_.has(1)})),S=f((function(e){new b(e)})),k=!v&&d((function(){for(var e=new b,t=5;t--;)e[g](t,t);return!e.has(-0)}));S||((y=t((function(t,n){l(t,y,e);var o=m(new b,t,y);return n!=undefined&&u(n,o[g],{that:o,AS_ENTRIES:h}),o}))).prototype=C,C.constructor=y),(w||k)&&(V("delete"),V("has"),h&&V("get")),(k||x)&&V(g),v&&C.clear&&delete C.clear}return N[e]=y,o({global:!0,forced:y!=b},N),p(y,e),v||n.setStrong(y,e,h),y}},49957:function(e,t,n){"use strict";var o=n(28919),r=n(28482),i=n(22245),a=n(74217);e.exports=function(e,t){for(var n=r(t),c=a.f,u=i.f,l=0;l"+c+""}},38415:function(e,t,n){"use strict";var o=n(39881).IteratorPrototype,r=n(83681),i=n(39160),a=n(29108),c=n(82723),u=function(){return this};e.exports=function(e,t,n){var l=t+" Iterator";return e.prototype=r(o,{next:i(1,n)}),a(e,l,!1,!0),c[l]=u,e}},52188:function(e,t,n){"use strict";var o=n(75592),r=n(74217),i=n(39160);e.exports=o?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},39160:function(e){"use strict";e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},39241:function(e,t,n){"use strict";var o=n(14613),r=n(74217),i=n(39160);e.exports=function(e,t,n){var a=o(t);a in e?r.f(e,a,i(0,n)):e[a]=n}},79873:function(e,t,n){"use strict";var o=n(69691),r=n(47497).start,i=Math.abs,a=Date.prototype,c=a.getTime,u=a.toISOString;e.exports=o((function(){return"0385-07-25T07:06:39.999Z"!=u.call(new Date(-50000000000001))}))||!o((function(){u.call(new Date(NaN))}))?function(){if(!isFinite(c.call(this)))throw RangeError("Invalid time value");var e=this,t=e.getUTCFullYear(),n=e.getUTCMilliseconds(),o=t<0?"-":t>9999?"+":"";return o+r(i(t),o?6:4,0)+"-"+r(e.getUTCMonth()+1,2,0)+"-"+r(e.getUTCDate(),2,0)+"T"+r(e.getUTCHours(),2,0)+":"+r(e.getUTCMinutes(),2,0)+":"+r(e.getUTCSeconds(),2,0)+"."+r(n,3,0)+"Z"}:u},57763:function(e,t,n){"use strict";var o=n(63518),r=n(28734);e.exports=function(e){if(o(this),"string"===e||"default"===e)e="string";else if("number"!==e)throw TypeError("Incorrect hint");return r(this,e)}},71179:function(e,t,n){"use strict";var o=n(56174),r=n(38415),i=n(6863),a=n(18444),c=n(29108),u=n(52188),l=n(11807),s=n(17657),d=n(1986),f=n(82723),p=n(39881),m=p.IteratorPrototype,h=p.BUGGY_SAFARI_ITERATORS,v=s("iterator"),g="keys",b="values",C="entries",y=function(){return this};e.exports=function(e,t,n,s,p,N,V){r(n,t,s);var _,x,w,S=function(e){if(e===p&&L)return L;if(!h&&e in B)return B[e];switch(e){case g:case b:case C:return function(){return new n(this,e)}}return function(){return new n(this)}},k=t+" Iterator",E=!1,B=e.prototype,I=B[v]||B["@@iterator"]||p&&B[p],L=!h&&I||S(p),O="Array"==t&&B.entries||I;if(O&&(_=i(O.call(new e)),m!==Object.prototype&&_.next&&(d||i(_)===m||(a?a(_,m):"function"!=typeof _[v]&&u(_,v,y)),c(_,k,!0,!0),d&&(f[k]=y))),p==b&&I&&I.name!==b&&(E=!0,L=function(){return I.call(this)}),d&&!V||B[v]===L||u(B,v,L),f[t]=L,p)if(x={values:S(b),keys:N?L:S(g),entries:S(C)},V)for(w in x)(h||E||!(w in B))&&l(B,w,x[w]);else o({target:t,proto:!0,forced:h||E},x);return x}},55282:function(e,t,n){"use strict";var o=n(65781),r=n(28919),i=n(3444),a=n(74217).f;e.exports=function(e){var t=o.Symbol||(o.Symbol={});r(t,e)||a(t,e,{value:i.f(e)})}},75592:function(e,t,n){"use strict";var o=n(69691);e.exports=!o((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},21477:function(e,t,n){"use strict";var o=n(84253),r=n(35611),i=o.document,a=r(i)&&r(i.createElement);e.exports=function(e){return a?i.createElement(e):{}}},20967:function(e,t,n){"use strict";var o=n(72319).match(/firefox\/(\d+)/i);e.exports=!!o&&+o[1]},46392:function(e){"use strict";e.exports="object"==typeof window},85749:function(e,t,n){"use strict";var o=n(72319);e.exports=/MSIE|Trident/.test(o)},20037:function(e,t,n){"use strict";var o=n(72319),r=n(84253);e.exports=/iphone|ipod|ipad/i.test(o)&&r.Pebble!==undefined},24542:function(e,t,n){"use strict";var o=n(72319);e.exports=/(?:iphone|ipod|ipad).*applewebkit/i.test(o)},41488:function(e,t,n){"use strict";var o=n(77e3),r=n(84253);e.exports="process"==o(r.process)},47501:function(e,t,n){"use strict";var o=n(72319);e.exports=/web0s(?!.*chrome)/i.test(o)},72319:function(e,t,n){"use strict";var o=n(69808);e.exports=o("navigator","userAgent")||""},12338:function(e,t,n){"use strict";var o,r,i=n(84253),a=n(72319),c=i.process,u=i.Deno,l=c&&c.versions||u&&u.version,s=l&&l.v8;s?r=(o=s.split("."))[0]<4?1:o[0]+o[1]:a&&(!(o=a.match(/Edge\/(\d+)/))||o[1]>=74)&&(o=a.match(/Chrome\/(\d+)/))&&(r=o[1]),e.exports=r&&+r},12200:function(e,t,n){"use strict";var o=n(72319).match(/AppleWebKit\/(\d+)\./);e.exports=!!o&&+o[1]},23344:function(e){"use strict";e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},56174:function(e,t,n){"use strict";var o=n(84253),r=n(22245).f,i=n(52188),a=n(11807),c=n(30889),u=n(49957),l=n(41441);e.exports=function(e,t){var n,s,d,f,p,m=e.target,h=e.global,v=e.stat;if(n=h?o:v?o[m]||c(m,{}):(o[m]||{}).prototype)for(s in t){if(f=t[s],d=e.noTargetGet?(p=r(n,s))&&p.value:n[s],!l(h?s:m+(v?".":"#")+s,e.forced)&&d!==undefined){if(typeof f==typeof d)continue;u(f,d)}(e.sham||d&&d.sham)&&i(f,"sham",!0),a(n,s,f,e)}}},69691:function(e){"use strict";e.exports=function(e){try{return!!e()}catch(t){return!0}}},68880:function(e,t,n){"use strict";n(12654);var o=n(11807),r=n(71841),i=n(69691),a=n(17657),c=n(52188),u=a("species"),l=RegExp.prototype;e.exports=function(e,t,n,s){var d=a(e),f=!i((function(){var t={};return t[d]=function(){return 7},7!=""[e](t)})),p=f&&!i((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[u]=function(){return n},n.flags="",n[d]=/./[d]),n.exec=function(){return t=!0,null},n[d](""),!t}));if(!f||!p||n){var m=/./[d],h=t(d,""[e],(function(e,t,n,o,i){var a=t.exec;return a===r||a===l.exec?f&&!i?{done:!0,value:m.call(t,n,o)}:{done:!0,value:e.call(n,t,o)}:{done:!1}}));o(String.prototype,e,h[0]),o(l,d,h[1])}s&&c(l[d],"sham",!0)}},904:function(e,t,n){"use strict";var o=n(89999),r=n(39570),i=n(74271);e.exports=function a(e,t,n,c,u,l,s,d){for(var f,p=u,m=0,h=!!s&&i(s,d,3);m0&&o(f))p=a(e,t,f,r(f.length),p,l-1)-1;else{if(p>=9007199254740991)throw TypeError("Exceed the acceptable array length");e[p]=f}p++}m++}return p}},7056:function(e,t,n){"use strict";var o=n(69691);e.exports=!o((function(){return Object.isExtensible(Object.preventExtensions({}))}))},74271:function(e,t,n){"use strict";var o=n(83923);e.exports=function(e,t,n){if(o(e),t===undefined)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,o){return e.call(t,n,o)};case 3:return function(n,o,r){return e.call(t,n,o,r)}}return function(){return e.apply(t,arguments)}}},68719:function(e,t,n){"use strict";var o=n(83923),r=n(35611),i=[].slice,a={},c=function(e,t,n){if(!(t in a)){for(var o=[],r=0;r]*>)/g,c=/\$([$&'`]|\d{1,2})/g;e.exports=function(e,t,n,u,l,s){var d=n+e.length,f=u.length,p=c;return l!==undefined&&(l=o(l),p=a),i.call(s,p,(function(o,i){var a;switch(i.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(d);case"<":a=l[i.slice(1,-1)];break;default:var c=+i;if(0===c)return o;if(c>f){var s=r(c/10);return 0===s?o:s<=f?u[s-1]===undefined?i.charAt(1):u[s-1]+i.charAt(1):o}a=u[c-1]}return a===undefined?"":a}))}},84253:function(e,t,n){"use strict";var o=function(e){return e&&e.Math==Math&&e};e.exports=o("object"==typeof globalThis&&globalThis)||o("object"==typeof window&&window)||o("object"==typeof self&&self)||o("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},28919:function(e,t,n){"use strict";var o=n(12104),r={}.hasOwnProperty;e.exports=Object.hasOwn||function(e,t){return r.call(o(e),t)}},90311:function(e){"use strict";e.exports={}},21419:function(e,t,n){"use strict";var o=n(84253);e.exports=function(e,t){var n=o.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},2369:function(e,t,n){"use strict";var o=n(69808);e.exports=o("document","documentElement")},78251:function(e,t,n){"use strict";var o=n(75592),r=n(69691),i=n(21477);e.exports=!o&&!r((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},16567:function(e){"use strict";var t=Math.abs,n=Math.pow,o=Math.floor,r=Math.log,i=Math.LN2;e.exports={pack:function(e,a,c){var u,l,s,d=new Array(c),f=8*c-a-1,p=(1<>1,h=23===a?n(2,-24)-n(2,-77):0,v=e<0||0===e&&1/e<0?1:0,g=0;for((e=t(e))!=e||e===Infinity?(l=e!=e?1:0,u=p):(u=o(r(e)/i),e*(s=n(2,-u))<1&&(u--,s*=2),(e+=u+m>=1?h/s:h*n(2,1-m))*s>=2&&(u++,s/=2),u+m>=p?(l=0,u=p):u+m>=1?(l=(e*s-1)*n(2,a),u+=m):(l=e*n(2,m-1)*n(2,a),u=0));a>=8;d[g++]=255&l,l/=256,a-=8);for(u=u<0;d[g++]=255&u,u/=256,f-=8);return d[--g]|=128*v,d},unpack:function(e,t){var o,r=e.length,i=8*r-t-1,a=(1<>1,u=i-7,l=r-1,s=e[l--],d=127&s;for(s>>=7;u>0;d=256*d+e[l],l--,u-=8);for(o=d&(1<<-u)-1,d>>=-u,u+=t;u>0;o=256*o+e[l],l--,u-=8);if(0===d)d=1-c;else{if(d===a)return o?NaN:s?-Infinity:Infinity;o+=n(2,t),d-=c}return(s?-1:1)*o*n(2,d-t)}}},50990:function(e,t,n){"use strict";var o=n(69691),r=n(77e3),i="".split;e.exports=o((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==r(e)?i.call(e,""):Object(e)}:Object},22285:function(e,t,n){"use strict";var o=n(35611),r=n(18444);e.exports=function(e,t,n){var i,a;return r&&"function"==typeof(i=t.constructor)&&i!==n&&o(a=i.prototype)&&a!==n.prototype&&r(e,a),e}},89853:function(e,t,n){"use strict";var o=n(55935),r=Function.toString;"function"!=typeof o.inspectSource&&(o.inspectSource=function(e){return r.call(e)}),e.exports=o.inspectSource},40421:function(e,t,n){"use strict";var o=n(56174),r=n(90311),i=n(35611),a=n(28919),c=n(74217).f,u=n(78870),l=n(59995),s=n(41080),d=n(7056),f=!1,p=s("meta"),m=0,h=Object.isExtensible||function(){return!0},v=function(e){c(e,p,{value:{objectID:"O"+m++,weakData:{}}})},g=e.exports={enable:function(){g.enable=function(){},f=!0;var e=u.f,t=[].splice,n={};n[p]=1,e(n).length&&(u.f=function(n){for(var o=e(n),r=0,i=o.length;rf;f++)if((m=_(e[f]))&&m instanceof l)return m;return new l(!1)}s=d.call(e)}for(h=s.next;!(v=h.call(s)).done;){try{m=_(v.value)}catch(x){throw u(s),x}if("object"==typeof m&&m&&m instanceof l)return m}return new l(!1)}},61781:function(e,t,n){"use strict";var o=n(63518);e.exports=function(e){var t=e["return"];if(t!==undefined)return o(t.call(e)).value}},39881:function(e,t,n){"use strict";var o,r,i,a=n(69691),c=n(6863),u=n(52188),l=n(28919),s=n(17657),d=n(1986),f=s("iterator"),p=!1;[].keys&&("next"in(i=[].keys())?(r=c(c(i)))!==Object.prototype&&(o=r):p=!0);var m=o==undefined||a((function(){var e={};return o[f].call(e)!==e}));m&&(o={}),d&&!m||l(o,f)||u(o,f,(function(){return this})),e.exports={IteratorPrototype:o,BUGGY_SAFARI_ITERATORS:p}},82723:function(e){"use strict";e.exports={}},19997:function(e){"use strict";var t=Math.expm1,n=Math.exp;e.exports=!t||t(10)>22025.465794806718||t(10)<22025.465794806718||-2e-17!=t(-2e-17)?function(e){return 0==(e=+e)?e:e>-1e-6&&e<1e-6?e+e*e/2:n(e)-1}:t},43334:function(e,t,n){"use strict";var o=n(24305),r=Math.abs,i=Math.pow,a=i(2,-52),c=i(2,-23),u=i(2,127)*(2-c),l=i(2,-126);e.exports=Math.fround||function(e){var t,n,i=r(e),s=o(e);return iu||n!=n?s*Infinity:s*n}},83659:function(e){"use strict";var t=Math.log;e.exports=Math.log1p||function(e){return(e=+e)>-1e-8&&e<1e-8?e-e*e/2:t(1+e)}},24305:function(e){"use strict";e.exports=Math.sign||function(e){return 0==(e=+e)||e!=e?e:e<0?-1:1}},80909:function(e,t,n){"use strict";var o,r,i,a,c,u,l,s,d=n(84253),f=n(22245).f,p=n(33453).set,m=n(24542),h=n(20037),v=n(47501),g=n(41488),b=d.MutationObserver||d.WebKitMutationObserver,C=d.document,y=d.process,N=d.Promise,V=f(d,"queueMicrotask"),_=V&&V.value;_||(o=function(){var e,t;for(g&&(e=y.domain)&&e.exit();r;){t=r.fn,r=r.next;try{t()}catch(n){throw r?a():i=undefined,n}}i=undefined,e&&e.enter()},m||g||v||!b||!C?!h&&N&&N.resolve?((l=N.resolve(undefined)).constructor=N,s=l.then,a=function(){s.call(l,o)}):a=g?function(){y.nextTick(o)}:function(){p.call(d,o)}:(c=!0,u=C.createTextNode(""),new b(o).observe(u,{characterData:!0}),a=function(){u.data=c=!c})),e.exports=_||function(e){var t={fn:e,next:undefined};i&&(i.next=t),r||(r=t,a()),i=t}},4302:function(e,t,n){"use strict";var o=n(84253);e.exports=o.Promise},54772:function(e,t,n){"use strict";var o=n(12338),r=n(69691);e.exports=!!Object.getOwnPropertySymbols&&!r((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&o&&o<41}))},82911:function(e,t,n){"use strict";var o=n(84253),r=n(89853),i=o.WeakMap;e.exports="function"==typeof i&&/native code/.test(r(i))},82101:function(e,t,n){"use strict";var o=n(83923),r=function(e){var t,n;this.promise=new e((function(e,o){if(t!==undefined||n!==undefined)throw TypeError("Bad Promise constructor");t=e,n=o})),this.resolve=o(t),this.reject=o(n)};e.exports.f=function(e){return new r(e)}},18774:function(e,t,n){"use strict";var o=n(86133);e.exports=function(e){if(o(e))throw TypeError("The method doesn't accept regular expressions");return e}},64630:function(e,t,n){"use strict";var o=n(84253).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&o(e)}},78025:function(e,t,n){"use strict";var o=n(84253),r=n(92082),i=n(84703).trim,a=n(65181),c=o.parseFloat,u=1/c(a+"-0")!=-Infinity;e.exports=u?function(e){var t=i(r(e)),n=c(t);return 0===n&&"-"==t.charAt(0)?-0:n}:c},55092:function(e,t,n){"use strict";var o=n(84253),r=n(92082),i=n(84703).trim,a=n(65181),c=o.parseInt,u=/^[+-]?0[Xx]/,l=8!==c(a+"08")||22!==c(a+"0x16");e.exports=l?function(e,t){var n=i(r(e));return c(n,t>>>0||(u.test(n)?16:10))}:c},64905:function(e,t,n){"use strict";var o=n(75592),r=n(69691),i=n(84547),a=n(21061),c=n(77659),u=n(12104),l=n(50990),s=Object.assign,d=Object.defineProperty;e.exports=!s||r((function(){if(o&&1!==s({b:1},s(d({},"a",{enumerable:!0,get:function(){d(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol(),r="abcdefghijklmnopqrst";return e[n]=7,r.split("").forEach((function(e){t[e]=e})),7!=s({},e)[n]||i(s({},t)).join("")!=r}))?function(e,t){for(var n=u(e),r=arguments.length,s=1,d=a.f,f=c.f;r>s;)for(var p,m=l(arguments[s++]),h=d?i(m).concat(d(m)):i(m),v=h.length,g=0;v>g;)p=h[g++],o&&!f.call(m,p)||(n[p]=m[p]);return n}:s},83681:function(e,t,n){"use strict";var o,r=n(63518),i=n(91543),a=n(23344),c=n(90311),u=n(2369),l=n(21477),s=n(85152),d=s("IE_PROTO"),f=function(){},p=function(e){return"