diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index fd3bc349f4c..54f015fdf44 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -117,47 +117,49 @@ C << "You are no longer running on internals." icon_state = "internal0" else - if(!istype(C.wear_mask, /obj/item/clothing/mask)) - C << "You are not wearing an internals mask!" - return 1 - else - var/obj/item/clothing/mask/M = C.wear_mask - if(M.mask_adjusted) // if mask on face but pushed down - M.adjustmask(C) // adjust it back - if( !(M.flags & MASKINTERNALS) ) + if(!C.getorganslot("breathing_tube")) + if(!istype(C.wear_mask, /obj/item/clothing/mask)) C << "You are not wearing an internals mask!" - return - if(istype(C.l_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.l_hand] on your left hand." - C.internal = C.l_hand - else if(istype(C.r_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.r_hand] on your right hand." - C.internal = C.r_hand - else if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(istype(H.s_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]." - H.internal = H.s_store - else if(istype(H.belt, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.belt] on your belt." - H.internal = H.belt - else if(istype(H.l_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.l_store] in your left pocket." - H.internal = H.l_store - else if(istype(H.r_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.r_store] in your right pocket." - H.internal = H.r_store - - //Seperate so CO2 jetpacks are a little less cumbersome. - if(!C.internal && istype(C.back, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.back] on your back." - C.internal = C.back - - if(C.internal) - icon_state = "internal1" + return 1 else - C << "You don't have an oxygen tank!" - return + var/obj/item/clothing/mask/M = C.wear_mask + if(M.mask_adjusted) // if mask on face but pushed down + M.adjustmask(C) // adjust it back + if( !(M.flags & MASKINTERNALS) ) + C << "You are not wearing an internals mask!" + return + + if(istype(C.l_hand, /obj/item/weapon/tank)) + C << "You are now running on internals from the [C.l_hand] on your left hand." + C.internal = C.l_hand + else if(istype(C.r_hand, /obj/item/weapon/tank)) + C << "You are now running on internals from the [C.r_hand] on your right hand." + C.internal = C.r_hand + else if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(istype(H.s_store, /obj/item/weapon/tank)) + H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]." + H.internal = H.s_store + else if(istype(H.belt, /obj/item/weapon/tank)) + H << "You are now running on internals from the [H.belt] on your belt." + H.internal = H.belt + else if(istype(H.l_store, /obj/item/weapon/tank)) + H << "You are now running on internals from the [H.l_store] in your left pocket." + H.internal = H.l_store + else if(istype(H.r_store, /obj/item/weapon/tank)) + H << "You are now running on internals from the [H.r_store] in your right pocket." + H.internal = H.r_store + + //Seperate so CO2 jetpacks are a little less cumbersome. + if(!C.internal && istype(C.back, /obj/item/weapon/tank)) + C << "You are now running on internals from the [C.back] on your back." + C.internal = C.back + + if(C.internal) + icon_state = "internal1" + else + C << "You don't have an oxygen tank!" + return C.update_action_buttons_icon() /obj/screen/mov_intent diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index 684ee437c89..e17f41445d0 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -112,3 +112,6 @@ ..() if(M.mind) M.mind.remove_spell(/obj/effect/proc_holder/spell/bloodcrawl) + +/obj/item/organ/internal/heart/demon/Stop() + return 0 // Always beating. diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index d5d116a4392..7b935abfdb5 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -63,3 +63,11 @@ track_delay = world.time + 10 // 1 second return + + + +/obj/item/device/multitool/cyborg + name = "multitool" + desc = "Optimised and stripped-down version of a regular multitool." + icon = 'icons/obj/items_cyborg.dmi' + toolspeed = 2 \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index ae8d23b9ecb..68052b14958 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -129,7 +129,7 @@ MASS SPECTROMETER if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.heart_attack) + if(H.heart_attack && H.stat != DEAD) user << "Subject suffering from heart attack: Apply defibrillator immediately!" user << "Analyzing results for [M]:\n\tOverall status: [mob_status]" diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 0152f03c41d..88c1ab6393c 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -548,7 +548,7 @@ /obj/item/weapon/twohanded/shockpaddles/syndicate name = "syndicate defibrillator paddles" - desc = "A pair of paddles used to revive deceased operatives. It possesses both the ability to penetrate armor and todeliver powerful shocks offensively." + desc = "A pair of paddles used to revive deceased operatives. It possesses both the ability to penetrate armor and to deliver powerful shocks offensively." combat = 1 icon = 'icons/obj/weapons.dmi' icon_state = "defibpaddles0" diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm index f92335d09d0..640a14dec73 100644 --- a/code/game/objects/items/weapons/kitchen.dm +++ b/code/game/objects/items/weapons/kitchen.dm @@ -98,6 +98,12 @@ origin_tech = "materials=2;combat=4" attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut") +/obj/item/weapon/kitchen/knife/combat/cyborg + name = "cyborg knife" + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "knife" + desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable." + /obj/item/weapon/kitchen/knife/carrotshiv name = "carrot shiv" icon_state = "carrotshiv" @@ -118,4 +124,4 @@ w_class = 3 attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked") -/* Trays moved to /obj/item/weapon/storage/bag */ +/* Trays moved to /obj/item/weapon/storage/bag */ diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 58b230917d2..f62985f47f3 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -28,14 +28,15 @@ H.internal = null H.update_internals_hud_icon(0) else - if(!H.wear_mask) - H << "You need a mask!" - return - if(H.wear_mask.mask_adjusted) - H.wear_mask.adjustmask(H) - if(!(H.wear_mask.flags & MASKINTERNALS)) - H << "[H.wear_mask] can't use [src]!" - return + if(!H.getorganslot("breathing_tube")) + if(!H.wear_mask) + H << "You need a mask!" + return + if(H.wear_mask.mask_adjusted) + H.wear_mask.adjustmask(H) + if(!(H.wear_mask.flags & MASKINTERNALS)) + H << "[H.wear_mask] can't use [src]!" + return if(H.internal) H << "You switch your internals to [src]." diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 67696207645..3c546350790 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -34,6 +34,12 @@ playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) return (BRUTELOSS) +/obj/item/weapon/wrench/cyborg + name = "automatic wrench" + desc = "An advanced robotic wrench. Can be found in construction cyborgs." + icon = 'icons/obj/items_cyborg.dmi' + toolspeed = 2 + /* * Screwdriver */ @@ -99,6 +105,17 @@ M = user return eyestab(M,user) +/obj/item/weapon/screwdriver/cyborg + name = "powered screwdriver" + desc = "An electrical screwdriver, designed to be both precise and quick." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "screwdriver" + item_state = "screwdriver_brown" + toolspeed = 2 + +/obj/item/weapon/screwdriver/cyborg/New(loc, var/param_color = null) + return ..(loc, "cyborg") + /* * Wirecutters */ @@ -142,6 +159,16 @@ playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1, -1) return (BRUTELOSS) + +/obj/item/weapon/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/items_cyborg.dmi' + toolspeed = 2 + +/obj/item/weapon/wirecutters/cyborg/New(loc, var/param_color = null) + return ..(loc, "cyborg") + /* * Welding Tool */ @@ -396,6 +423,11 @@ origin_tech = "engineering=2" /obj/item/weapon/weldingtool/largetank/cyborg + name = "integrated welding tool" + desc = "An advanced welder designed to be used in robotic systems." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "indwelder" + toolspeed = 2 /obj/item/weapon/weldingtool/largetank/flamethrower_screwdriver() return @@ -494,3 +526,10 @@ materials = list(MAT_METAL=70) icon_state = "crowbar_large" toolspeed = 2 + +/obj/item/weapon/crowbar/cyborg + name = "hydraulic crowbar" + desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs." + icon = 'icons/obj/items_cyborg.dmi' + force = 10 + toolspeed = 2 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b6b13b41669..458e37c3901 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -323,9 +323,10 @@ if(internal) internal = null update_internals_hud_icon(0) - else if(ITEM && istype(ITEM, /obj/item/weapon/tank) && wear_mask && (wear_mask.flags & MASKINTERNALS)) - internal = ITEM - update_internals_hud_icon(1) + else if(ITEM && istype(ITEM, /obj/item/weapon/tank)) + if((wear_mask && (wear_mask.flags & MASKINTERNALS)) || getorganslot("breathing_tube")) + internal = ITEM + update_internals_hud_icon(1) visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM].", \ "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM].") diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 665ca0422be..544a023160b 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -1,8 +1,9 @@ /mob/living/carbon gender = MALE hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD) - var/list/stomach_contents = list() - var/list/internal_organs = list() //List of /obj/item/organ/internal in the mob. They don't go in the contents for some reason I don't want to know. + var/list/stomach_contents = list() + var/list/internal_organs = list() //List of /obj/item/organ/internal in the mob. They don't go in the contents for some reason I don't want to know. + var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access. var/silent = 0 //Can't talk. Value goes down every life proc. //NOTE TO FUTURE CODERS: DO NOT INITIALIZE NUMERICAL VARS AS NULL OR I WILL MURDER YOU. diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index c7e5f8174fe..3e0ad9b5b3c 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -173,7 +173,7 @@ /mob/living/carbon/human/wear_mask_update(obj/item/clothing/C, toggle_off = 1) if((C.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(C.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR))) update_hair() - if(toggle_off && internal) + if(toggle_off && internal && !getorganslot("breathing_tube")) update_internals_hud_icon(0) internal = null if(C.flags_inv & HIDEEYES) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index ada5f67baf6..0c1bc7cf192 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -199,6 +199,9 @@ if(internal.loc != src) internal = null update_internals_hud_icon(0) + else if ((!wear_mask || !(wear_mask.flags & MASKINTERNALS)) && !getorganslot("breathing_tube")) + internal = null + update_internals_hud_icon(0) else update_internals_hud_icon(1) return internal.remove_air_volume(volume_needed) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index fb2e6646e18..de11726345d 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -453,7 +453,7 @@ if (WT.remove_fuel(0, user)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. if(src == user) user << "You start fixing youself..." - if(!do_after(user, 50/W.toolspeed, target = src)) + if(!do_after(user, 50, target = src)) return adjustBruteLoss(-30) diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 4517dea695e..a29cc3b29fd 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -100,15 +100,18 @@ if(!affecting.buckled) affecting.loc = assailant.loc + var/breathing_tube = affecting.getorganslot("breathing_tube") + if(state >= GRAB_NECK) affecting.Stun(5) //It will hamper your voice, being choked and all. - if(isliving(affecting)) + if(isliving(affecting) && !breathing_tube) var/mob/living/L = affecting L.adjustOxyLoss(1) if(state >= GRAB_KILL) affecting.Weaken(5) //Should keep you down unless you get help. - affecting.losebreath = min(affecting.losebreath + 2, 3) + if(!breathing_tube) + affecting.losebreath = min(affecting.losebreath + 2, 3) /obj/item/weapon/grab/attack_self(mob/user) s_click(hud) @@ -165,7 +168,8 @@ add_logs(assailant, affecting, "strangled") assailant.changeNext_move(CLICK_CD_TKSTRANGLE) - affecting.losebreath += 1 + if(!affecting.getorganslot("breathing_tube")) + affecting.losebreath += 1 else if(assailant) assailant.visible_message("[assailant] is unable to tighten \his grip on [affecting]'s neck!") diff --git a/code/modules/projectiles/guns/mounted.dm b/code/modules/projectiles/guns/mounted.dm index 84549c8e09f..177445f3b43 100644 --- a/code/modules/projectiles/guns/mounted.dm +++ b/code/modules/projectiles/guns/mounted.dm @@ -1,12 +1,11 @@ /obj/item/weapon/gun/energy/gun/advtaser/mounted name = "mounted taser" desc = "An arm mounted dual-mode weapon that fires electrodes and disabler shots." - icon_state = "armcannon" + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "taser" + item_state = "armcannonstun4" force = 5 selfcharge = 1 - flags = NODROP - slot_flags = null - w_class = 5 can_flashlight = 0 /obj/item/weapon/gun/energy/gun/advtaser/mounted/dropped()//if somebody manages to drop this somehow... @@ -15,16 +14,13 @@ /obj/item/weapon/gun/energy/laser/mounted name = "mounted laser" - desc = "An arm mounted cannon that fires lethal lasers. Doesn't come with a charge beam." - icon_state = "armcannon" + desc = "An arm mounted cannon that fires lethal lasers." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "laser" item_state = "armcannonlase" force = 5 selfcharge = 1 - flags = NODROP - slot_flags = null - w_class = 5 - materials = null /obj/item/weapon/gun/energy/laser/mounted/dropped() ..() - src.loc = null + src.loc = null \ No newline at end of file diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index aaa5d9df810..028bc09f8ae 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -121,6 +121,17 @@ build_path = /obj/item/organ/internal/cyberimp/eyes/shield category = list("Misc", "Medical Designs") +/datum/design/cyberimp_breather + name = "Breathing Tube implant" + desc = "This simple implant adds an internals connector to your back, allowing you to use internals without a mask and protecting you from being choked." + id = "ci-breather" + req_tech = list("materials" = 3, "biotech" = 3) + build_type = PROTOLATHE | MECHFAB + construction_time = 35 + materials = list(MAT_METAL = 200, MAT_GLASS = 250) + build_path = /obj/item/organ/internal/cyberimp/mouth/breathing_tube + category = list("Misc", "Medical Designs") + /datum/design/cyberimp_medical_hud name = "Medical HUD implant" desc = "These cybernetic eyes will display a medical HUD over everything you see. Wiggle eyes to control." @@ -174,7 +185,7 @@ construction_time = 60 materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 400, MAT_GOLD = 400) build_path = /obj/item/organ/internal/cyberimp/brain/anti_drop - category = list("Medical Designs") + category = list("Misc", "Medical Designs") /datum/design/cyberimp_antistun name = "CNS Rebooter implant" @@ -185,7 +196,7 @@ construction_time = 60 materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 500, MAT_GOLD = 1000) build_path = /obj/item/organ/internal/cyberimp/brain/anti_stun - category = list("Medical Designs") + category = list("Misc", "Medical Designs") /datum/design/cyberimp_nutriment name = "Nutriment pump implant" @@ -196,7 +207,7 @@ construction_time = 40 materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_GOLD = 500, MAT_URANIUM = 500) build_path = /obj/item/organ/internal/cyberimp/chest/nutriment - category = list("Medical Designs") + category = list("Misc", "Medical Designs") /datum/design/cyberimp_nutriment_plus name = "Nutriment pump implant PLUS" @@ -207,7 +218,7 @@ construction_time = 50 materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_GOLD = 500, MAT_URANIUM = 750) build_path = /obj/item/organ/internal/cyberimp/chest/nutriment/plus - category = list("Medical Designs") + category = list("Misc", "Medical Designs") /datum/design/cyberimp_reviver name = "Reviver implant" @@ -237,7 +248,7 @@ /datum/design/implantcase name = "Implant Case" - desc = "A glass case containing an implant." + desc = "A glass case for containing an implant." id = "implantcase" req_tech = list("materials" = 1, "biotech" = 2) build_type = PROTOLATHE diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 26de8b0b6a5..b0cc38c8dc8 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -7,13 +7,13 @@ requires_organic_bodypart = 0 /datum/surgery/organ_manipulation/soft - possible_locs = list("groin", "eyes", "mouth") + possible_locs = list("groin", "eyes", "mouth", "l_arm", "r_arm") steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/incise, /datum/surgery_step/manipulate_organs) /datum/surgery/organ_manipulation/alien name = "alien organ manipulation" - possible_locs = list("chest", "head", "groin", "eyes", "mouth") + possible_locs = list("chest", "head", "groin", "eyes", "mouth", "l_arm", "r_arm") species = list(/mob/living/carbon/alien/humanoid) steps = list(/datum/surgery_step/saw, /datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/manipulate_organs) diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm new file mode 100644 index 00000000000..247bf322e02 --- /dev/null +++ b/code/modules/surgery/organs/augments_arms.dm @@ -0,0 +1,182 @@ +/obj/item/organ/internal/cyberimp/arm + name = "arm-mounted implant" + desc = "You shouldn't see this! Adminhelp and report this as an issue on github!" + zone = "r_arm" + slot = "r_arm_device" + icon_state = "implant-toolkit" + w_class = 3 + actions_types = list(/datum/action/item_action/organ_action/toggle) + + var/list/items_list = list() + // Used to store a list of all items inside, for multi-item implants. + // I would use contents, but they shuffle on every activation/deactivation leading to interface inconsistencies. + + var/obj/item/holder = null + // You can use this var for item path, it would be converted into an item on New() + +/obj/item/organ/internal/cyberimp/arm/New() + ..() + if(ispath(holder)) + holder = new holder(src) + + update_icon() + slot = zone + "_device" + items_list = contents.Copy() + +/obj/item/organ/internal/cyberimp/arm/update_icon() + if(zone == "r_arm") + transform = null + else // Mirroring the icon + transform = matrix(-1, 0, 0, 0, 1, 0) + +/obj/item/organ/internal/cyberimp/arm/examine(mob/user) + ..() + user << "[src] is assembled in the [zone == "r_arm" ? "right" : "left"] arm configuration. You can use a screwdriver to reassemble it." + +/obj/item/organ/internal/cyberimp/arm/attackby(obj/item/weapon/W, mob/user, params) + ..() + if(istype(W, /obj/item/weapon/screwdriver)) + if(zone == "r_arm") + zone = "l_arm" + else + zone = "r_arm" + slot = zone + "_device" + user << "You modify [src] to be installed on the [zone == "r_arm" ? "right" : "left"] arm." + update_icon() + else if(istype(W, /obj/item/weapon/card/emag)) + emag_act() + +/obj/item/organ/internal/cyberimp/arm/Remove(mob/living/carbon/M, special = 0) + Retract() + ..() + +/obj/item/organ/internal/cyberimp/arm/emag_act() + return 0 + +/obj/item/organ/internal/cyberimp/arm/gun/emp_act(severity) + if(prob(15/severity)) + owner << "[src] is hit by EMP!" + // give the owner an idea about why his implant is glitching + Retract() + ..() + +/obj/item/organ/internal/cyberimp/arm/proc/Retract() + if(!holder || (holder in src)) + return + + owner.visible_message("[owner] retracts [holder] back into \his [zone == "r_arm" ? "right" : "left"] arm.", + "[holder] snaps back into your [zone == "r_arm" ? "right" : "left"] arm.", + "You hear a short mechanical noise.") + + owner.unEquip(holder, 1) + holder.loc = src + holder = null + playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1) + +/obj/item/organ/internal/cyberimp/arm/proc/Extend(var/obj/item/item) + if(!(item in src)) + return + + holder = item + + holder.flags |= NODROP + holder.unacidable = 1 + holder.slot_flags = null + holder.w_class = 5 + holder.materials = null + + var/arm_slot = (zone == "r_arm" ? slot_r_hand : slot_l_hand) + var/obj/item/arm_item = owner.get_item_by_slot(arm_slot) + + if(arm_item) + if(!owner.unEquip(arm_item)) + owner << "Your [arm_item] interferes with [src]!" + return + else + owner << "You drop [arm_item] to activate [src]!" + + if(zone == "r_arm" ? !owner.put_in_r_hand(holder) : !owner.put_in_l_hand(holder)) + owner << "Your [src] fails to activate!" + return + + // Activate the hand that now holds our item. + if(zone == "r_arm" ? owner.hand : !owner.hand) + owner.swap_hand() + + owner.visible_message("[owner] extends [holder] from \his [zone == "r_arm" ? "right" : "left"] arm.", + "You extend [holder] from your [zone == "r_arm" ? "right" : "left"] arm.", + "You hear a short mechanical noise.") + playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1) + +/obj/item/organ/internal/cyberimp/arm/ui_action_click() + if(crit_fail || (!holder && !contents.len)) + owner << "The implant doesn't respond. It seems to be broken..." + return + + // You can emag the arm-mounted implant by activating it while holding emag in it's hand. + var/arm_slot = (zone == "r_arm" ? slot_r_hand : slot_l_hand) + if(istype(owner.get_item_by_slot(arm_slot), /obj/item/weapon/card/emag) && emag_act()) + return + + if(!holder || (holder in src)) + holder = null + if(contents.len == 1) + Extend(contents[1]) + else // TODO: make it similar to borg's storage-like module selection + var/obj/item/choise = input("Activate which item?", "Arm Implant", null, null) as null|anything in items_list + if(owner && owner == usr && owner.stat != DEAD && (src in owner.internal_organs) && !holder && istype(choise) && (choise in contents)) + // This monster sanity check is a nice example of how bad input() is. + Extend(choise) + else + Retract() + + +/obj/item/organ/internal/cyberimp/arm/gun/emp_act(severity) + if(prob(30/severity) && owner && !crit_fail) + Retract() + owner.visible_message("A loud bang comes from [owner]\'s [zone == "r_arm" ? "right" : "left"] arm!") + playsound(get_turf(owner), 'sound/weapons/flashbang.ogg', 100, 1) + owner << "You feel an explosion erupt inside your [zone == "r_arm" ? "right" : "left"] arm as your implant breaks!" + owner.adjust_fire_stacks(20) + owner.IgniteMob() + owner.adjustFireLoss(25) + crit_fail = 1 + else // The gun will still discharge anyway. + ..() + + +/obj/item/organ/internal/cyberimp/arm/gun/laser + name = "arm-mounted laser implant" + desc = "A variant of the arm cannon implant that fires lethal laser beams. The cannon emerges from the subject's arm and remains inside when not in use." + icon_state = "arm_laser" + origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4;syndicate=5"//this is kinda nutty and i might lower it + holder = /obj/item/weapon/gun/energy/laser/mounted + +/obj/item/organ/internal/cyberimp/arm/gun/laser/l/zone = "l_arm" + + +/obj/item/organ/internal/cyberimp/arm/gun/taser + name = "arm-mounted taser implant" + desc = "A variant of the arm cannon implant that fires electrodes and disabler shots. The cannon emerges from the subject's arm and remains inside when not in use." + icon_state = "arm_taser" + origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4" + holder = /obj/item/weapon/gun/energy/gun/advtaser/mounted + +/obj/item/organ/internal/cyberimp/arm/gun/taser/l/zone = "l_arm" + + +/obj/item/organ/internal/cyberimp/arm/toolset + name = "integrated toolset implant" + desc = "A stripped-down version of engineering cyborg toolset, designed to be installed on subject's arm. Contains all neccessary tools." + origin_tech = "materials=5;engineering=5;biotech=4;powerstorage=3" + contents = newlist(/obj/item/weapon/screwdriver/cyborg, /obj/item/weapon/wrench/cyborg, /obj/item/weapon/weldingtool/largetank/cyborg, + /obj/item/weapon/crowbar/cyborg, /obj/item/weapon/wirecutters/cyborg, /obj/item/device/multitool/cyborg) + +/obj/item/organ/internal/cyberimp/arm/toolset/l/zone = "l_arm" + +/obj/item/organ/internal/cyberimp/arm/toolset/emag_act() + if(!(locate(/obj/item/weapon/kitchen/knife/combat/cyborg) in items_list)) + owner << "You unlock [src]'s integrated knife!" + items_list += new /obj/item/weapon/kitchen/knife/combat/cyborg(src) + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm new file mode 100644 index 00000000000..916051d133c --- /dev/null +++ b/code/modules/surgery/organs/augments_chest.dm @@ -0,0 +1,106 @@ +/obj/item/organ/internal/cyberimp/chest + name = "cybernetic torso implant" + desc = "implants for the organs in your torso" + icon_state = "chest_implant" + implant_overlay = "chest_implant_overlay" + zone = "chest" + +/obj/item/organ/internal/cyberimp/chest/nutriment + name = "Nutriment pump implant" + desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving." + icon_state = "chest_implant" + implant_color = "#00AA00" + var/hunger_threshold = NUTRITION_LEVEL_STARVING + var/synthesizing = 0 + var/poison_amount = 5 + slot = "stomach" + origin_tech = "materials=5;programming=3;biotech=4" + +/obj/item/organ/internal/cyberimp/chest/nutriment/on_life() + if(synthesizing) + return + + if(owner.nutrition <= hunger_threshold) + synthesizing = 1 + owner << "You feel less hungry..." + owner.nutrition += 50 + spawn(50) + synthesizing = 0 + +/obj/item/organ/internal/cyberimp/chest/nutriment/emp_act(severity) + if(!owner) + return + owner.reagents.add_reagent("????",poison_amount / severity) //food poisoning + owner << "You feel like your insides are burning." + + +/obj/item/organ/internal/cyberimp/chest/nutriment/plus + name = "Nutriment pump implant PLUS" + desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry." + icon_state = "chest_implant" + implant_color = "#006607" + hunger_threshold = NUTRITION_LEVEL_HUNGRY + poison_amount = 10 + origin_tech = "materials=5;programming=3;biotech=5" + + + +/obj/item/organ/internal/cyberimp/chest/reviver + name = "Reviver implant" + desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!" + icon_state = "chest_implant" + implant_color = "#AD0000" + origin_tech = "materials=6;programming=3;biotech=6;syndicate=4" + slot = "heartdrive" + var/revive_cost = 0 + var/reviving = 0 + var/cooldown = 0 + +/obj/item/organ/internal/cyberimp/chest/reviver/on_life() + if(reviving) + if(owner.stat == UNCONSCIOUS) + spawn(30) + if(prob(90) && owner.getOxyLoss()) + owner.adjustOxyLoss(-3) + revive_cost += 5 + if(prob(75) && owner.getBruteLoss()) + owner.adjustBruteLoss(-1) + revive_cost += 20 + if(prob(75) && owner.getFireLoss()) + owner.adjustFireLoss(-1) + revive_cost += 20 + if(prob(40) && owner.getToxLoss()) + owner.adjustToxLoss(-1) + revive_cost += 50 + else + cooldown = revive_cost + world.time + reviving = 0 + return + + if(cooldown > world.time) + return + if(owner.stat != UNCONSCIOUS) + return + if(owner.suiciding) + return + + revive_cost = 0 + reviving = 1 + +/obj/item/organ/internal/cyberimp/chest/reviver/emp_act(severity) + if(!owner) + return + + if(reviving) + revive_cost += 200 + else + cooldown += 200 + + if(istype(owner, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = owner + if(H.stat != DEAD && prob(50 / severity)) + H.heart_attack = 1 + spawn(600 / severity) + H.heart_attack = 0 + if(H.stat == CONSCIOUS) + H << "You feel your heart beating again!" \ No newline at end of file diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm index 279f912ef06..1693d217906 100644 --- a/code/modules/surgery/organs/augments_eyes.dm +++ b/code/modules/surgery/organs/augments_eyes.dm @@ -116,7 +116,7 @@ implant_color = "#101010" flash_protect = 2 aug_message = null - eye_color = "fff" + eye_color = null /obj/item/organ/internal/cyberimp/eyes/shield/emp_act(severity) return \ No newline at end of file diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index b793fd05fc8..8a3776cce8e 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -26,6 +26,7 @@ icon_state = "brain_implant" implant_overlay = "brain_implant_overlay" zone = "head" + w_class = 1 /obj/item/organ/internal/cyberimp/brain/emp_act(severity) if(!owner) @@ -37,7 +38,7 @@ /obj/item/organ/internal/cyberimp/brain/anti_drop - name = "Anti-drop implant" + name = "anti-drop implant" desc = "This cybernetic brain implant will allow you to force your hand muscles to contract, preventing item dropping. Twitch ear to toggle." var/active = 0 var/l_hand_ignore = 0 @@ -101,11 +102,11 @@ if(L_item) A = pick(oview(range)) L_item.throw_at(A, range, 2) - owner << "Your left arm spasms and throws the [L_item.name]!" + owner << "Your left arm spasms and throws the [L_item.name]!" if(R_item) A = pick(oview(range)) R_item.throw_at(A, range, 2) - owner << "Your right arm spasms and throws the [R_item.name]!" + owner << "Your right arm spasms and throws the [R_item.name]!" /obj/item/organ/internal/cyberimp/brain/anti_drop/proc/release_items() if(!l_hand_ignore && l_hand_obj in owner.contents) @@ -144,185 +145,24 @@ crit_fail = 0 -//[[[[CHEST]]]] +//[[[[MOUTH]]]] +/obj/item/organ/internal/cyberimp/mouth + zone = "mouth" -/obj/item/organ/internal/cyberimp/chest - name = "cybernetic torso implant" - desc = "implants for the organs in your torso" - icon_state = "chest_implant" - implant_overlay = "chest_implant_overlay" - zone = "chest" +/obj/item/organ/internal/cyberimp/mouth/breathing_tube + name = "breathing tube implant" + desc = "This simple implant adds an internals connector to your back, allowing you to use internals without a mask and protecting you from being choked." + icon_state = "breathing_tube" + slot = "breathing_tube" + w_class = 1 + origin_tech = "materials=2;biotech=3" -/obj/item/organ/internal/cyberimp/chest/nutriment - name = "Nutriment pump implant" - desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving." - icon_state = "chest_implant" - implant_color = "#00AA00" - var/hunger_threshold = NUTRITION_LEVEL_STARVING - var/synthesizing = 0 - var/poison_amount = 5 - slot = "stomach" - origin_tech = "materials=5;programming=3;biotech=4" - -/obj/item/organ/internal/cyberimp/chest/nutriment/on_life() - if(synthesizing) - return - - if(owner.nutrition <= hunger_threshold) - synthesizing = 1 - owner << "You feel less hungry..." - owner.nutrition += 50 - spawn(50) - synthesizing = 0 - -/obj/item/organ/internal/cyberimp/chest/nutriment/emp_act(severity) - if(!owner) - return - owner.reagents.add_reagent("????",poison_amount / severity) //food poisoning - owner << "You feel like your insides are burning." +/obj/item/organ/internal/cyberimp/mouth/breathing_tube/emp_act(severity) + if(prob(60/severity)) + owner << "Your breathing tube suddenly closes!" + owner.losebreath += 2 -/obj/item/organ/internal/cyberimp/chest/nutriment/plus - name = "Nutriment pump implant PLUS" - desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry." - icon_state = "chest_implant" - implant_color = "#006607" - hunger_threshold = NUTRITION_LEVEL_HUNGRY - poison_amount = 10 - origin_tech = "materials=5;programming=3;biotech=5" - - - -/obj/item/organ/internal/cyberimp/chest/reviver - name = "Reviver implant" - desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!" - icon_state = "chest_implant" - implant_color = "#AD0000" - origin_tech = "materials=6;programming=3;biotech=6;syndicate=4" - slot = "heartdrive" - var/revive_cost = 0 - var/reviving = 0 - var/cooldown = 0 - -/obj/item/organ/internal/cyberimp/chest/reviver/on_life() - if(reviving) - if(owner.stat == UNCONSCIOUS) - spawn(30) - if(prob(90) && owner.getOxyLoss()) - owner.adjustOxyLoss(-3) - revive_cost += 5 - if(prob(75) && owner.getBruteLoss()) - owner.adjustBruteLoss(-1) - revive_cost += 20 - if(prob(75) && owner.getFireLoss()) - owner.adjustFireLoss(-1) - revive_cost += 20 - if(prob(40) && owner.getToxLoss()) - owner.adjustToxLoss(-1) - revive_cost += 50 - else - cooldown = revive_cost + world.time - reviving = 0 - return - - if(cooldown > world.time) - return - if(owner.stat != UNCONSCIOUS) - return - if(owner.suiciding) - return - - revive_cost = 0 - reviving = 1 - -/obj/item/organ/internal/cyberimp/chest/reviver/emp_act(severity) - if(!owner) - return - - if(reviving) - revive_cost += 200 - else - cooldown += 200 - - if(istype(owner, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = owner - if(H.stat != DEAD && prob(50 / severity)) - H.heart_attack = 1 - spawn(600 / severity) - H.heart_attack = 0 - if(H.stat == CONSCIOUS) - H << "You feel your heart beating again!" - -/obj/item/organ/internal/cyberimp/chest/arm_mod//dummy parent item for making arm-mod implants. works best with nodrop items that are sent to nullspace upon being dropped. - name = "Arm-mounted item implant" - desc = "You shouldn't see this! Adminhelp and report this as an issue on github!" - icon_state = "chest_implant" - implant_color = "#007ACC" - slot = "shoulders" - origin_tech = "materials=5;biotech=4;powerstorage=4" - actions_types = list(/datum/action/item_action/organ_action/toggle) - var/obj/holder//is defined as the retractable item itself. ensure this is defined somewhere! - var/out = 0//determines if the item is in the owner's hand or not - var/overloaded = 0//is set to 1 when owner gets EMPed. if set to 1, implant doesn't work. - -/obj/item/organ/internal/cyberimp/chest/arm_mod/ui_action_click() - if(overloaded)//ensure the implant isn't broken - owner << "The implant doesn't respond. It seems to be broken..." - return - if(holder == null) - owner << "You should not be attempting to use this implant, as it is a dummy item that should never appear. Please adminhelp and report this as an issue on github." - return - if(out)//check if the owner has the item out already - owner.unEquip(holder, 1)//if he does, take it away. then, - holder.loc = null//stash it in nullspace - out = 0//and set this to clarify the item isn't out. - owner << "You retract [holder]." - playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1) - else//if he doesn't have the item out - if(owner.put_in_hands(holder))//put it in his hands. - out = 1 - owner << "You extend [holder]!" - playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1) - else//if this fails to put the item in his hands, - holder.loc = null//keep it in nullspace - owner << "You can't extend [holder] if you can't use your hands!" - -/obj/item/organ/internal/cyberimp/chest/arm_mod/emp_act(severity)//if the implant gets EMPed... - if(!owner || overloaded)//ensure that it's in an owner and that it's not already EMPed, then... - return - if(out)//check if he has the item out... - owner.unEquip(holder, 1)//if he does, take it away. - holder.loc = null - out = 0 - owner << "[holder] forcibly retracts into your arm." - owner.visible_message("A loud bang comes from [owner]...") - playsound(get_turf(owner), 'sound/weapons/flashbang.ogg', 100, 1) - owner << "You feel an explosion erupt inside you as your chest implant breaks. Is it hot in here?" - owner.adjust_fire_stacks(20) - owner.IgniteMob()//ignite the owner, as well as - owner.say("AUUUUUUUUUUUUUUUUUUGH!!") - owner.adjustFireLoss(25)//severely injure him! - overloaded = 1//then make sure this can't happen again by breaking the implant. - -/obj/item/organ/internal/cyberimp/chest/arm_mod/tase//mounted, self-charging taser! - name = "Arm-cannon taser implant" - desc = "A variant of the arm cannon implant that fires electrodes and disabler shots. The cannon emerges from the subject's arms and remains in the shoulders when not in use." - icon_state = "armcannon_tase_implant" - origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4" - actions_types = list(/datum/action/item_action/organ_action/toggle) - -/obj/item/organ/internal/cyberimp/chest/arm_mod/tase/New()//when the implant is created... - holder = new /obj/item/weapon/gun/energy/gun/advtaser/mounted(src)//assign a brand new item to it. (in this case, a gun) - -/obj/item/organ/internal/cyberimp/chest/arm_mod/lase//mounted, self-charging laser! - name = "Arm-cannon laser implant" - desc = "A variant of the arm cannon implant that fires lethal laser beams. The cannon emerges from the subject's arms and remains in the shoulders when not in use." - icon_state = "armcannon_lase_implant" - origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4;syndicate=5"//this is kinda nutty and i might lower it - actions_types = list(/datum/action/item_action/organ_action/toggle) - -/obj/item/organ/internal/cyberimp/chest/arm_mod/lase/New() - holder = new /obj/item/weapon/gun/energy/laser/mounted(src) //BOX O' IMPLANTS diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm index 5fa8b0811be..b25f792f336 100644 --- a/code/modules/surgery/organs/helpers.dm +++ b/code/modules/surgery/organs/helpers.dm @@ -26,9 +26,7 @@ mob/living/carbon/getorganszone(zone, var/subzones = 0) return returnorg mob/living/carbon/getorganslot(slot) - for(var/obj/item/organ/internal/O in internal_organs) - if(slot == O.slot) - return O + return internal_organs_slot[slot] mob/proc/getlimb() return diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 4bfb4eb9c21..5ead35d2677 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -5,6 +5,7 @@ throwforce = 0 var/zone = "chest" var/slot + // DO NOT add slots with matching names to different zones - it will break internal_organs_slot list! var/vital = 0 @@ -18,6 +19,7 @@ owner = M M.internal_organs |= src + M.internal_organs_slot[slot] = src loc = null for(var/X in actions) var/datum/action/A = X @@ -28,6 +30,8 @@ owner = null if(M) M.internal_organs -= src + if(M.internal_organs_slot[slot] == src) + M.internal_organs_slot.Remove(slot) if(vital && !special) M.death() for(var/X in actions) @@ -41,6 +45,12 @@ /obj/item/organ/internal/proc/on_life() return +/obj/item/organ/internal/examine(mob/user) + ..() + if(status == ORGAN_ROBOTIC && crit_fail) + user << "[src] seems to be broken!" + + /obj/item/organ/internal/proc/prepare_eat() var/obj/item/weapon/reagent_containers/food/snacks/organ/S = new S.name = name @@ -56,7 +66,6 @@ name = "appendix" icon_state = "appendix" icon = 'icons/obj/surgery.dmi' - list_reagents = list("nutriment" = 5) @@ -92,7 +101,6 @@ zone = "chest" slot = "heart" origin_tech = "biotech=3" - vital = 1 var/beating = 1 var/icon_base = "heart" @@ -102,16 +110,46 @@ else icon_state = "[icon_base]-off" -/obj/item/organ/internal/heart/Insert(mob/living/carbon/M, special = 0) - ..() - beating = 1 - update_icon() - /obj/item/organ/internal/heart/Remove(mob/living/carbon/M, special = 0) ..() + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.stat == DEAD || H.heart_attack) + Stop() + return + if(!special) + H.heart_attack = 1 + spawn(120) - beating = 0 - update_icon() + if(!owner) + Stop() + +/obj/item/organ/internal/heart/attack_self(mob/user) + ..() + if(!beating) + Restart() + spawn(80) + if(!owner) + Stop() + + +/obj/item/organ/internal/heart/Insert(mob/living/carbon/M, special = 0) + ..() + if(ishuman(M) && beating) + var/mob/living/carbon/human/H = M + if(H.heart_attack) + H.heart_attack = 0 + return + +/obj/item/organ/internal/heart/proc/Stop() + beating = 0 + update_icon() + return 1 + +/obj/item/organ/internal/heart/proc/Restart() + beating = 1 + update_icon() + return 1 /obj/item/organ/internal/heart/prepare_eat() var/obj/S = ..() diff --git a/icons/obj/items_cyborg.dmi b/icons/obj/items_cyborg.dmi new file mode 100644 index 00000000000..dfdd3114194 Binary files /dev/null and b/icons/obj/items_cyborg.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 0d2b1166c19..9252dbf89f6 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/tgstation.dme b/tgstation.dme index fcee4ede946..53979542c99 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1598,6 +1598,8 @@ #include "code\modules\surgery\surgery_step.dm" #include "code\modules\surgery\tail_modification.dm" #include "code\modules\surgery\tools.dm" +#include "code\modules\surgery\organs\augments_arms.dm" +#include "code\modules\surgery\organs\augments_chest.dm" #include "code\modules\surgery\organs\augments_external.dm" #include "code\modules\surgery\organs\augments_eyes.dm" #include "code\modules\surgery\organs\augments_internal.dm"