diff --git a/code/datums/hud.dm b/code/datums/hud.dm index 39d63400ddb..f3315d1cfd6 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -20,6 +20,8 @@ var/datum/atom_hud/huds = list( \ var/list/hud_icons = list() //these will be the indexes for the atom's hud_list /datum/atom_hud/proc/remove_hud_from(var/mob/M) + if(src in M.permanent_huds) + return for(var/atom/A in hudatoms) remove_from_single_hud(M, A) hudusers -= M diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm index b47386d60df..01c7fc430ec 100644 --- a/code/datums/mutations.dm +++ b/code/datums/mutations.dm @@ -182,6 +182,8 @@ /datum/mutation/human/x_ray/on_losing(mob/living/carbon/human/owner) if(..()) return + if((SEE_MOBS in owner.permanent_sight_flags) && (SEE_OBJS in owner.permanent_sight_flags) && (SEE_TURFS in owner.permanent_sight_flags)) //Xray flag combo + return owner.see_in_dark = initial(owner.see_in_dark) owner.sight = initial(owner.sight) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index d7654b8b583..244071e4a7a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -190,6 +190,12 @@ if(prob(20)) src << "Something bright flashes in the corner of your vision!" +/mob/living/carbon/proc/eyecheck() + var/obj/item/cybernetic_implant/eyes/EFP = locate() in src + if(EFP) + return EFP.flash_protect + return 0 + /mob/living/carbon/proc/tintcheck() return 0 diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 71327284c39..f20afceaaa3 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -266,7 +266,8 @@ if(istype(user, /mob/living/carbon/human)) var/mob/living/carbon/human/H = user - if(istype(H.glasses, /obj/item/clothing/glasses/hud)) + var/obj/item/cybernetic_implant/eyes/hud/CIH = locate(/obj/item/cybernetic_implant/eyes/hud) in internal_organs + if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH) var/perpname = get_face_name(get_id_name("")) if(perpname) var/datum/data/record/R = find_record("name", perpname, data_core.general) @@ -274,7 +275,7 @@ msg += "Rank: [R.fields["rank"]]
" msg += "\[Front photo\] " msg += "\[Side photo\]
" - if(istype(H.glasses, /obj/item/clothing/glasses/hud/health)) + if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/cybernetic_implant/eyes/hud/medical)) if(R) var/health = R.fields["p_stat"] msg += "\[[health]\]" @@ -284,7 +285,8 @@ if(R) msg += "\[Medical evaluation\]
" - if(istype(H.glasses, /obj/item/clothing/glasses/hud/security)) + + if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH,/obj/item/cybernetic_implant/eyes/hud/security)) if(!user.stat && user != src) //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at. var/criminal = "None" diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index f622ed76642..902cce6896a 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -88,6 +88,9 @@ if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask var/obj/item/clothing/mask/MFP = src.wear_mask number += MFP.flash_protect + var/obj/item/cybernetic_implant/eyes/EFP = locate() in src + if(EFP) + number += EFP.flash_protect return number /mob/living/carbon/human/check_ear_prot() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 9ede33a4c9b..85f650b29cc 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -510,10 +510,16 @@ H.see_in_dark = 8 if(!H.druggy) H.see_invisible = SEE_INVISIBLE_LEVEL_TWO else - H.sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) + if(!(SEE_TURFS in H.permanent_sight_flags)) + H.sight &= ~SEE_TURFS + if(!(SEE_MOBS in H.permanent_sight_flags)) + H.sight &= ~SEE_MOBS + if(!(SEE_OBJS in H.permanent_sight_flags)) + H.sight &= ~SEE_OBJS + + H.see_in_dark = (H.sight == SEE_TURFS|SEE_MOBS|SEE_OBJS) ? 8 : darksight var/see_temp = H.see_invisible H.see_invisible = invis_sight - H.see_in_dark = darksight if(H.seer) H.see_invisible = SEE_INVISIBLE_OBSERVER diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 0c61438f787..1cd2baff929 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -558,10 +558,14 @@ see_in_dark = 8 see_invisible = SEE_INVISIBLE_LEVEL_TWO else - sight &= ~SEE_TURFS - sight &= ~SEE_MOBS - sight &= ~SEE_OBJS - see_in_dark = 2 + if(!(SEE_TURFS in permanent_sight_flags)) + sight &= ~SEE_TURFS + if(!(SEE_MOBS in permanent_sight_flags)) + sight &= ~SEE_MOBS + if(!(SEE_OBJS in permanent_sight_flags)) + sight &= ~SEE_OBJS + + see_in_dark = (sight == SEE_TURFS|SEE_MOBS|SEE_OBJS) ? 8 : 2 //Xray flag combo see_invisible = SEE_INVISIBLE_LIVING if(see_override) see_invisible = see_override diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index a86b5609bee..8010d5eefd1 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -148,4 +148,7 @@ var/obj/control_object //Used by admins to possess objects. All mobs should have this var var/atom/movable/remote_control //Calls relaymove() to whatever it is - var/turf/listed_turf = null //the current turf being examined in the stat panel \ No newline at end of file + var/turf/listed_turf = null //the current turf being examined in the stat panel + + var/list/permanent_huds = list() + var/list/permanent_sight_flags = list() \ 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 1e8e50a3be1..2c7ae702d64 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -92,3 +92,68 @@ datum/design/bluespacebodybag reliability = 76 build_path = /obj/item/bodybag/bluespace category = list("Medical Designs") + + +///////////////////////////////////////// +//////////Cybernetic Implants//////////// +///////////////////////////////////////// + +/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." + id = "ci-medhud" + req_tech = list("materials" = 5, "programming" = 4, "biotech" = 4) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 100) + build_path = /obj/item/cybernetic_implant/eyes/hud/medical + category = list("Medical Designs") + +/datum/design/cyberimp_security_hud + name = "Security HUD implant" + desc = "These cybernetic eyes will display a security HUD over everything you see. Wiggle eyes to control." + id = "ci-sechud" + req_tech = list("materials" = 5, "programming" = 5, "biotech" = 5, "combat" = 2) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 300, "$gold" = 300) + build_path = /obj/item/cybernetic_implant/eyes/hud/security + category = list("Medical Designs") + +/datum/design/cyberimp_xray + name = "X-Ray implant" + desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile." + id = "ci-xray" + req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5, "magnets" = 5, "plasmatech" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 200, "$plasma" = 200, "$diamond" = 500) + build_path = /obj/item/cybernetic_implant/eyes/xray + category = list("Medical Designs") + +/datum/design/cyberimb_thermals + name = "Thermals implant" + desc = "These cybernetic eyes will give you Thermal vision. Vertical slit pupil included." + id = "ci-thermals" + req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5, "magnets" = 5, "plasmatech" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 200, "$plasma" = 200, "$diamond" = 500) + build_path = /obj/item/cybernetic_implant/eyes/thermals + category = list("Medical Designs") + +/datum/design/cyberimb_antidrop + 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." + id = "ci-antidrop" + req_tech = list("materials" = 6, "programming" = 5, "biotech" = 5) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 400, "$gold" = 400) + build_path = /obj/item/cybernetic_implant/brain/anti_drop + category = list("Medical Designs") + +/datum/design/cyberimb_antistun + name = "CNS Rebooter implant" + desc = "This implant will automatically give you back control over your central nervous system, reducing downtime when stunned." + id = "ci-antistun" + req_tech = list("materials" = 6, "programming" = 5, "biotech" = 5) + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 200, "$glass" = 200, "$silver" = 400, "$gold" = 600) + build_path = /obj/item/cybernetic_implant/brain/anti_stun + category = list("Medical Designs") \ No newline at end of file diff --git a/code/modules/surgery/cybernetic_implants.dm b/code/modules/surgery/cybernetic_implants.dm new file mode 100644 index 00000000000..6d289144127 --- /dev/null +++ b/code/modules/surgery/cybernetic_implants.dm @@ -0,0 +1,56 @@ +#define MAX_BRAIN_IMPLANT 2 + +/datum/surgery/eye_cybernetic_implant/eyes + name = "eye cybernetic implant" + steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/cybernetic_implant/eyes, /datum/surgery_step/fix_eyes, /datum/surgery_step/close) + location = "eyes" + +/datum/surgery/eye_cybernetic_implant/brain + name = "brain cybernetic implant" + steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/cybernetic_implant/brain, /datum/surgery_step/close) + location = "head" + +/datum/surgery_step/cybernetic_implant/eyes + implements = list(/obj/item/cybernetic_implant/eyes = 100) + time = 32 + +/datum/surgery_step/cybernetic_implant/brain + implements = list(/obj/item/cybernetic_implant/brain = 100) + time = 32 + +/datum/surgery_step/cybernetic_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/implant, datum/surgery/surgery) + user.visible_message("[user] begins to implant [target] with [implant].") + +/datum/surgery_step/cybernetic_implant/eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/eyes/implant, datum/surgery/surgery) + if(implant) + var/full = 0 + if(locate(/obj/item/cybernetic_implant/eyes,target.internal_organs)) + full = 1 + + insert(user,target,implant,target_zone,full) + return 1 + +/datum/surgery_step/cybernetic_implant/brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/brain/implant, datum/surgery/surgery) + if(implant) + var/full = 0 + for(var/obj/item/I in target.contents) + if(istype(I,/obj/item/cybernetic_implant/brain)) + full++ + + if(full < MAX_BRAIN_IMPLANT) + full = 0 + + insert(user,target,implant,target_zone,full) + return 1 + + +/datum/surgery_step/cybernetic_implant/proc/insert(mob/user, mob/living/carbon/target, obj/item/cybernetic_implant/implant,target_zone,full) + if(full) + user.visible_message("[user] can't seem to implant anything else into the [target]'s [target_zone].") + else + user.visible_message("[user] inserts [implant] into the [target]'s [target_zone == "head" ? "brain" : target_zone]!") + implant.owner = target + implant.function() + user.drop_item() + implant.loc = target + target.internal_organs |= implant \ No newline at end of file diff --git a/code/modules/surgery/organs/cybernetic_implants.dm b/code/modules/surgery/organs/cybernetic_implants.dm new file mode 100644 index 00000000000..5b5a928148b --- /dev/null +++ b/code/modules/surgery/organs/cybernetic_implants.dm @@ -0,0 +1,236 @@ +#define STUN_SET_AMOUNT 2 + +/obj/item/cybernetic_implant + name = "cybernetic implant" + desc = "a state-of-the-art implant that improves a baseline's functionality" + icon = 'icons/obj/surgery.dmi' + var/mob/living/carbon/owner = null + var/implant_color = "#FFFFFF" + +/obj/item/cybernetic_implant/New(var/mob/M = null) + if(M) + owner = M + return ..() + +/obj/item/cybernetic_implant/proc/function() + return + + +//[[[[EYES]]]] + +/obj/item/cybernetic_implant/eyes + name = "cybernetic eyes" + desc = "artificial photoreceptors with specialized functionality" + icon_state = "eye_implant" + var/eye_color = "fff" + var/flash_protect = 0 + +/obj/item/cybernetic_implant/eyes/New() + var/icon/overlay = new /icon('icons/obj/surgery.dmi',"eye_implant_overlay") + overlay.ColorTone(implant_color) + overlays |= overlay + ..() + +/obj/item/cybernetic_implant/eyes/proc/update_eye_color(fluff_message) + if(istype(owner,/mob/living/carbon/human)) + var/mob/living/carbon/human/HMN = owner + HMN.eye_color = eye_color + HMN.regenerate_icons() + if(fluff_message) + owner << "[fluff_message]" + +/obj/item/cybernetic_implant/eyes/hud/medical + name = "medical hud implant" + desc = "These cybernetic eyes will display a medical HUD over everything you see. Wiggle eyes to control." + eye_color = "0ff" + implant_color = "#00FFFF" + +/obj/item/cybernetic_implant/eyes/hud/medical/function() + if(!owner) + return + + var/datum/atom_hud/H = huds[DATA_HUD_MEDICAL_ADVANCED] + H.add_hud_to(owner) + owner.permanent_huds |= H + update_eye_color("You suddenly see health bars floating above people's heads...") + +/obj/item/cybernetic_implant/eyes/hud/security + name = "security hud implant" + desc = "These cybernetic eyes will display a security HUD over everything you see. Wiggle eyes to control." + eye_color = "d00" + implant_color = "#CC0000" + +/obj/item/cybernetic_implant/eyes/hud/security/function() + if(!owner) + return + + var/datum/atom_hud/H = huds[DATA_HUD_SECURITY_ADVANCED] + H.add_hud_to(owner) + owner.permanent_huds |= H + update_eye_color("Job indicator icons pop up in your vision. That is not a certified surgeon...") + +/obj/item/cybernetic_implant/eyes/xray + name = "xray implant" + desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile." + eye_color = "000" + implant_color = "#000000" + +/obj/item/cybernetic_implant/eyes/xray/function() + if(!owner) + return + + owner.sight |= SEE_MOBS + owner.sight |= SEE_OBJS + owner.sight |= SEE_TURFS + owner.permanent_sight_flags |= SEE_MOBS + owner.permanent_sight_flags |= SEE_OBJS + owner.permanent_sight_flags |= SEE_TURFS + update_eye_color("Your vision is augmented!") + +/obj/item/cybernetic_implant/eyes/thermals + name = "thermals implant" + desc = "These cybernetic eyes will give you Thermal vision. Vertical slit pupil included." + eye_color = "FC0" + implant_color = "#FFCC00" + flash_protect = -1 + +/obj/item/cybernetic_implant/eyes/thermals/function() + if(!owner) + return + + owner.sight |= SEE_MOBS + owner.permanent_sight_flags |= SEE_MOBS + update_eye_color("You see prey everywhere you look...") + +/obj/item/cybernetic_implant/eyes/emp_act(severity) + if(severity > 1) + if(prob(5)) + return + var/save_sight = owner.sight + owner.sight &= 0 + owner.disabilities |= BLIND + owner << "Static obfuscates your vision!" + spawn(50) + owner.sight |= save_sight + owner.disabilities ^= BLIND + + +//[[[[BRAIN]]]] + +/obj/item/cybernetic_implant/brain + name = "cybernetic brain implant" + desc = "injectors of extra sub-routines for the brain" + icon_state = "brain_implant" + +/obj/item/cybernetic_implant/brain/New() + var/icon/overlay = new /icon('icons/obj/surgery.dmi',"brain_implant_overlay") + overlay.ColorTone(implant_color) + overlays |= overlay + ..() + +/obj/item/cybernetic_implant/brain/emp_act(severity) + var/stun_amount = 5 + (severity-1 ? 0 : 5) + owner.Stun(stun_amount) + owner << "Your body seizes up!" + return stun_amount + +/obj/item/cybernetic_implant/brain/anti_drop + 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 + var/r_hand_ignore = 0 + var/obj/item/l_hand_obj = null + var/obj/item/r_hand_obj = null + implant_color = "#DE7E00" + +/obj/item/cybernetic_implant/brain/anti_drop/function() + action_button_name = "Toggle Anti-Drop" + +/obj/item/cybernetic_implant/brain/anti_drop/ui_action_click() + active = !active + if(active) + l_hand_obj = owner.l_hand + r_hand_obj = owner.r_hand + if(l_hand_obj) + if(owner.l_hand.flags & NODROP) + l_hand_ignore = 1 + else + owner.l_hand.flags |= NODROP + l_hand_ignore = 0 + + if(r_hand_obj) + if(owner.r_hand.flags & NODROP) + r_hand_ignore = 1 + else + owner.r_hand.flags |= NODROP + r_hand_ignore = 0 + + if(!l_hand_obj && !r_hand_obj) + owner << "You are not holding any items, your hands relax..." + active = 0 + else + var/msg = 0 + msg += !l_hand_ignore && l_hand_obj ? 1 : 0 + msg += !r_hand_ignore && r_hand_obj ? 2 : 0 + switch(msg) + if(1) + owner << "Your left hand's grip tightens." + if(2) + owner << "Your right hand's grip tightens." + if(3) + owner << "Both of your hand's grips tighten." + else + release_items() + owner << "Your hands relax..." + l_hand_obj = null + r_hand_obj = null + +/obj/item/cybernetic_implant/brain/anti_drop/emp_act(severity) + var/range = severity ? 10 : 5 + var/atom/A + var/obj/item/L_item = owner.l_hand + var/obj/item/R_item = owner.r_hand + + release_items() + ..() + 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]!" + 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]!" + +/obj/item/cybernetic_implant/brain/anti_drop/proc/release_items() + if(!l_hand_ignore && l_hand_obj in owner.contents) + l_hand_obj.flags ^= NODROP + if(!r_hand_ignore && r_hand_obj in owner.contents) + r_hand_obj.flags ^= NODROP + +/obj/item/cybernetic_implant/brain/anti_stun + name = "CNS Rebooter implant" + desc = "This implant will automatically give you back control over your central nervous system, reducing downtime when stunned." + implant_color = "#FFFF00" + +/obj/item/cybernetic_implant/brain/anti_stun/function() + SSobj.processing |= src + +/obj/item/cybernetic_implant/brain/anti_stun/process() + if(!owner) + SSobj.processing.Remove(src) + qdel(src) + return + if(owner.stat == DEAD) + return + + if(owner.stunned > STUN_SET_AMOUNT) + owner.stunned = STUN_SET_AMOUNT + if(owner.weakened > STUN_SET_AMOUNT) + owner.weakened = STUN_SET_AMOUNT + +/obj/item/cybernetic_implant/brain/anti_stun/emp_act(severity) + SSobj.processing.Remove(src) + spawn(..() * 10) + SSobj.processing |= src \ No newline at end of file diff --git a/html/changelogs/xxalpha-cyberimplants.yml b/html/changelogs/xxalpha-cyberimplants.yml new file mode 100644 index 00000000000..8ec9422fd54 --- /dev/null +++ b/html/changelogs/xxalpha-cyberimplants.yml @@ -0,0 +1,6 @@ +author: xxalpha + +delete-after: True + +changes: + - rscadd: "Added Cybernetic Implants: Security HUD, Medical HUD, X-Ray, Thermals, Anti-Drop, Anti-Stun. All implants are researchable and produceable by R&D and Robotics." \ No newline at end of file diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 28390abff25..93ebade829d 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 66ef8f08b42..8d9ffe9653d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1415,6 +1415,7 @@ #include "code\modules\surgery\brain_removal.dm" #include "code\modules\surgery\cavity_implant.dm" #include "code\modules\surgery\core_removal.dm" +#include "code\modules\surgery\cybernetic_implants.dm" #include "code\modules\surgery\eye_surgery.dm" #include "code\modules\surgery\gender_reassignment.dm" #include "code\modules\surgery\generic_steps.dm" @@ -1429,6 +1430,7 @@ #include "code\modules\surgery\tools.dm" #include "code\modules\surgery\xenomorph_removal.dm" #include "code\modules\surgery\organs\augments.dm" +#include "code\modules\surgery\organs\cybernetic_implants.dm" #include "code\modules\surgery\organs\helpers.dm" #include "code\modules\surgery\organs\organ.dm" #include "code\modules\telesci\bscrystal.dm"