diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm index acee6a8b65..1f7ed8c04a 100644 --- a/code/ZAS/Phoron.dm +++ b/code/ZAS/Phoron.dm @@ -117,6 +117,10 @@ obj/var/phoronproof = 0 if(burn_eyes && head && (head.body_parts_covered & EYES) && (head.item_flags & AIRTIGHT)) burn_eyes = 0 + //VOREStation Edit - NIF Support + if(nif && nif.flag_check(NIF_V_UVFILTER,NIF_FLAGS_VISION)) + burn_eyes = 0 + //If we still need to, burn their eyes if(burn_eyes) burn_eyes() diff --git a/code/__defines/nifsoft.dm b/code/__defines/nifsoft.dm new file mode 100644 index 0000000000..e4d4f12293 --- /dev/null +++ b/code/__defines/nifsoft.dm @@ -0,0 +1,103 @@ +// List indexes for software datum references on mobs +// This also controls the order they are displayed in the NIF stat panel +//AR Overlays +#define NIF_CIVILIAN_AR 1 +#define NIF_MEDICAL_AR 2 +#define NIF_SECURITY_AR 3 +#define NIF_ENGINE_AR 4 +#define NIF_SCIENCE_AR 5 +#define NIF_OMNI_AR 6 +//Misc Vision +#define NIF_CORRECTIVE_GLASS 7 +#define NIF_MESONS 8 +#define NIF_MATERIAL 9 +#define NIF_THERMALS 10 +#define NIF_NIGHTVIS 11 +#define NIF_UVFILTER 12 +#define NIF_FLASHPROT 13 +//Health-related +#define NIF_ORGANIC_HEAL 14 +#define NIF_SYNTH_HEAL 15 +#define NIF_AUTOSTASIS 16 //These two are just part of +#define NIF_MED_ALARM 17 //medichines right now +#define NIF_TOXHEAL 18 +#define NIF_SPAREBREATH 19 +//Combat Related +#define NIF_BRUTEARMOR 20 +#define NIF_BURNARMOR 21 +#define NIF_PAINKILLERS 22 +#define NIF_HARDCLAWS 23 +#define NIF_HIDDENLASER 24 +//Other +#define NIF_COMMLINK 25 +#define NIF_SUITSENSORS 26 +#define NIF_APCCHARGE 27 +#define NIF_PRESSURE 28 +#define NIF_HEATSINK 29 + +// Must be equal to the highest number above +#define TOTAL_NIF_SOFTWARE 29 + +////////////////////// +// NIF flag list hints +#define NIF_FLAGS_VISION 1 +#define NIF_FLAGS_HEALTH 2 +#define NIF_FLAGS_COMBAT 3 +#define NIF_FLAGS_OTHER 4 + +// NIF flags +//Vision +#define NIF_V_AR_CIVILIAN 0x1 +#define NIF_V_AR_MEDICAL 0x2 +#define NIF_V_AR_SECURITY 0x4 +#define NIF_V_AR_ENGINE 0x8 +#define NIF_V_AR_SCIENCE 0x10 +#define NIF_V_AR_OMNI 0x20 +#define NIF_V_CORRECTIVE 0x40 +#define NIF_V_MESONS 0x80 +#define NIF_V_MATERIAL 0x100 +#define NIF_V_THERMALS 0x200 +#define NIF_V_NIGHTVIS 0x400 +#define NIF_V_UVFILTER 0x800 +#define NIF_V_FLASHPROT 0x1000 + +//Health +#define NIF_H_ORGREPAIR 0x1 +#define NIF_H_SYNTHREPAIR 0x2 +#define NIF_H_AUTOSTASIS 0x4 //These two are just part of +#define NIF_H_ALERTMED 0x8 //medichines right now +#define NIF_H_TOXREGEN 0x10 +#define NIF_H_SPAREBREATH 0x20 + +//Combat +#define NIF_C_BRUTEARMOR 0x1 +#define NIF_C_BURNARMOR 0x2 +#define NIF_C_PAINKILLERS 0x4 +#define NIF_C_HARDCLAWS 0x8 +#define NIF_C_HIDELASER 0x10 + +//Other +#define NIF_O_COMMLINK 0x1 +#define NIF_O_SENSORS 0x2 +#define NIF_O_APCCHARGE 0x4 +#define NIF_O_PRESSURESEAL 0x8 +#define NIF_O_HEATSINKS 0x10 + +/////////////////// +// applies_to flags +#define NIF_ORGANIC 0x1 +#define NIF_SYNTHETIC 0x2 + +///////////// +// stat flags +#define NIF_WORKING 0 +#define NIF_POWFAIL 1 +#define NIF_TEMPFAIL 2 +#define NIF_INSTALLING 3 +#define NIF_PREINSTALL 4 + +/////////////////// +// tick_flags flags +#define NIF_NEVERTICK 0 +#define NIF_ALWAYSTICK 1 +#define NIF_ACTIVETICK 2 diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 632f9afdfd..758678bed9 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -81,7 +81,15 @@ playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) var/flashfail = 0 - if(iscarbon(M)) + //VOREStation Add - NIF + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.nif && H.nif.flag_check(NIF_V_FLASHPROT,NIF_FLAGS_VISION)) + flashfail = 1 + H.nif.notify("High intensity light detected, and blocked!",TRUE) + //VOREStation Add End + + if(iscarbon(M) && !flashfail) //VOREStation Add - NIF var/mob/living/carbon/C = M if(C.stat != DEAD) var/safety = C.eyecheck() diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 8c4067187f..555488cd89 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -376,6 +376,7 @@ var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES] if(!E) return + if(H.nif && H.nif.flag_check(NIF_V_UVFILTER,NIF_FLAGS_VISION)) return //VOREStation Add - NIF switch(safety) if(1) usr << "Your eyes sting a little." diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm index 354a26221c..403088dc4b 100644 --- a/code/modules/mob/living/carbon/breathe.dm +++ b/code/modules/mob/living/carbon/breathe.dm @@ -22,6 +22,13 @@ else //Okay, we can breathe, now check if we can get air breath = get_breath_from_internal() //First, check for air from internals + //VOREStation Add - Respirocytes as a NIF implant + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(H.nif && H.nif.flag_check(NIF_H_SPAREBREATH,NIF_FLAGS_HEALTH)) + var/datum/nifsoft/spare_breath/SB = H.nif.imp_check(NIF_SPAREBREATH) + breath = SB.resp_breath() + //VOREStation Add End if(!breath) breath = get_breath_from_environment() //No breath from internals so let's try to get air from our location if(!breath) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 47da8c88f8..47e12f3f6d 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -254,6 +254,7 @@ src.sleeping = max(0,src.sleeping-5) if(src.sleeping == 0) src.resting = 0 + if(H) H.in_stasis = 0 //VOREStation Add - Just In Case M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ "You shake [src] trying to wake [t_him] up!") else diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 4fa6ae1117..4331b05407 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -32,7 +32,7 @@ if(force_process) bad_external_organs.Cut() for(var/obj/item/organ/external/Ex in organs) - bad_external_organs |= Ex + bad_external_organs += Ex //VOREStation Edit - Silly and slow to |= this //processing internal organs is pretty cheap, do that first. for(var/obj/item/organ/I in internal_organs) @@ -44,6 +44,7 @@ if(!force_process && !bad_external_organs.len) return + number_wounds = 0 //VOREStation Add - You have to reduce this at some point... for(var/obj/item/organ/external/E in bad_external_organs) if(!E) continue diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 753cf3255e..75d598fb69 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1267,7 +1267,7 @@ var/obj/item/clothing/glasses/G = glasses if(!G.prescription) set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - else + else if (!nif || !nif.flag_check(NIF_V_CORRECTIVE,NIF_FLAGS_VISION)) //VOREStation Edit - NIF set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) @@ -1282,6 +1282,7 @@ var/obj/item/clothing/glasses/welding/O = glasses if(!O.up) found_welder = 1 + if(!found_welder && nif && nif.flag_check(NIF_V_UVFILTER,NIF_FLAGS_VISION)) found_welder = 1 //VOREStation Add - NIF if(!found_welder && istype(head, /obj/item/clothing/head/welding)) var/obj/item/clothing/head/welding/O = head if(!O.up) diff --git a/code/modules/mob/living/carbon/human/life_vr.dm b/code/modules/mob/living/carbon/human/life_vr.dm index a04232c401..0a3d2fcb3f 100644 --- a/code/modules/mob/living/carbon/human/life_vr.dm +++ b/code/modules/mob/living/carbon/human/life_vr.dm @@ -44,8 +44,9 @@ else vantag.icon_state = "hudblank" +//Our call for the NIF to do whatever /mob/living/carbon/human/proc/handle_nif() if(!nif) return //Process regular life stuff - nif.life() \ No newline at end of file + nif.life() diff --git a/code/modules/nifsoft/nif.dm b/code/modules/nifsoft/nif.dm new file mode 100644 index 0000000000..b4ef9eafd7 --- /dev/null +++ b/code/modules/nifsoft/nif.dm @@ -0,0 +1,481 @@ +//Holder on humans to prevent having to 'find' it every time +/mob/living/carbon/human/var/obj/item/device/nif/nif + +//Nanotech Implant Foundation +/obj/item/device/nif + name = "nanotech implant foundation" + desc = "A somewhat degraded copy of a Kitsuhana working surface, in a box. Can print new \ + implants inside living hosts on the fly based on software uploads. Must be surgically \ + implanted in the head to work. May eventually wear out and break." + + icon = 'icons/obj/device_alt.dmi' + icon_state = "nif_0" + + w_class = ITEMSIZE_TINY + + var/durability = 100 // Durability remaining + var/burn_factor = 100 // Divisor for power charge from nutrition (efficiency basically) + + var/tmp/power_usage = 0 // Nifsoft adds to this + var/tmp/mob/living/carbon/human/human // Our owner! + var/tmp/list/nifsofts[TOTAL_NIF_SOFTWARE] // All our nifsofts + var/tmp/list/nifsofts_life = list() // Ones that want to be talked to on life() + var/owner // Owner character name + + var/tmp/vision_flags = 0 // Flags implants set for faster lookups + var/tmp/health_flags = 0 + var/tmp/combat_flags = 0 + var/tmp/other_flags = 0 + + var/tmp/stat = NIF_PREINSTALL // Status of the NIF + var/tmp/install_done // Time when install will finish + var/tmp/open = FALSE // If it's open for maintenance (1-3) + + var/obj/item/clothing/glasses/hud/nif_hud/nif_hud + + var/global/icon/big_icon + var/global/click_sound = 'sound/effects/pop.ogg' + +//Constructor comes with a free AR HUD +/obj/item/device/nif/New(var/newloc,var/wear) + ..(newloc) + new /datum/nifsoft/ar_civ(src) + nif_hud = new(src) + + if(!big_icon) + big_icon = new(icon,icon_state = "nif_full") + + //Probably loading from a save + if(ishuman(newloc)) + var/mob/living/carbon/human/H = newloc + implant(H) + owner = H.mind.name + name = initial(name) + " ([owner])" + stat = NIF_WORKING + + if(wear) + durability = wear + + update_icon() + +//Destructor cleans up references +/obj/item/device/nif/Destroy() + if(human) + human.nif = null + human = null + for(var/S in nifsofts) + if(S) + qdel(S) + nifsofts.Cut() + ..() + +//Being implanted in some mob +/obj/item/device/nif/proc/implant(var/mob/living/carbon/human/H) + if(istype(H) && !H.nif && H.species && !(H.species.flags & NO_SCAN) && (loc == H.get_organ(BP_HEAD))) //NO_SCAN is the default 'too complicated' flag. + human = H + human.nif = src + stat = NIF_INSTALLING + return TRUE + + return FALSE + +//For debug or antag purposes +/obj/item/device/nif/proc/quick_implant(var/mob/living/carbon/human/H) + if(istype(H)) + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + if(!head) + return FALSE + src.forceMove(head) + head.implants += src + owner = H.real_name + return implant(H) + + return FALSE + +//Being implanted in some mob +/obj/item/device/nif/proc/unimplant(var/mob/living/carbon/human/H) + human = null + stat = NIF_PREINSTALL + install_done = null + if(istype(H)) + H.nif = null + update_icon() + +//EMP adds wear and disables all nifsoft +/obj/item/device/nif/emp_act(var/severity) + notify("Danger! Significant electromagnetic interference!",TRUE) + for(var/nifsoft in nifsofts) + if(nifsoft) + var/datum/nifsoft/NS = nifsoft + NS.deactivate() + + switch (severity) + if (1) + wear(rand(30,40)) + if (2) + wear(rand(15,25)) + if (3) + wear(rand(8,15)) + if (4) + wear(rand(1,8)) + +//Wear update/check proc +/obj/item/device/nif/proc/wear(var/wear = 0) + if(wear) + durability -= wear * rand(0.85,1.15) // Also +/- 15% + + if(durability <= 0) + stat = NIF_TEMPFAIL + update_icon() + notify("Danger! General system insta#^!($",TRUE) + to_chat(human,"Your NIF vision overlays disappear and your head suddenly seems very quiet...") + +//Attackby proc, for maintenance +/obj/item/device/nif/attackby(obj/item/weapon/W, mob/user as mob) + if(open == 0 && istype(W,/obj/item/weapon/screwdriver)) + if(do_after(user, 4 SECONDS, src) && open == 0) + user.visible_message("[user] unscrews and pries open \the [src].","You unscrew and pry open \the [src].") + playsound(user, 'sound/items/Screwdriver.ogg', 50, 1) + open = 1 + update_icon() + else if(open == 1 && istype(W,/obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if(C.get_amount() < 3) + to_chat(user,"You need at least three coils of wire to add them to \the [src].") + return + if(do_after(user, 6 SECONDS, src) && open == 1 && C.use(3)) + user.visible_message("[user] replaces some wiring in \the [src].","You replace any burned out wiring in \the [src].") + playsound(user, 'sound/items/Deconstruct.ogg', 50, 1) + open = 2 + update_icon() + else if(open == 2 && istype(W,/obj/item/device/multitool)) + if(do_after(user, 8 SECONDS, src) && open == 2) + user.visible_message("[user] resets several circuits in \the [src].","You find and repair any faulty circuits in \the [src].") + open = 3 + update_icon() + else if(open == 3 && istype(W,/obj/item/weapon/screwdriver)) + if(do_after(user, 3 SECONDS, src) && open == 3) + user.visible_message("[user] closes up \the [src].","You re-seal \the [src] for use once more.") + playsound(user, 'sound/items/Screwdriver.ogg', 50, 1) + open = FALSE + durability = initial(durability) + stat = NIF_PREINSTALL + update_icon() + +//Wear update/check proc +/obj/item/device/nif/update_icon() + if(open) + icon_state = "nif_open[open]" + else + switch(stat) + if(NIF_PREINSTALL) + icon_state = "nif_1" + if(NIF_INSTALLING) + icon_state = "nif_0" + if(NIF_WORKING) + icon_state = "nif_0" + if(NIF_TEMPFAIL) + icon_state = "nif_2" + else + icon_state = "nif_2" + +//The (dramatic) install process +/obj/item/device/nif/proc/handle_install() + if(human.stat) //No stuff while KO. Sleeping it off is viable, and doesn't start until you wake up from surgery + return FALSE + + //Firsties + if(!install_done) + if(human.real_name == owner) + install_done = world.time + 1 MINUTE + notify("Welcome back, [owner]! Performing quick-calibration...") + else + install_done = world.time + 30 MINUTES + notify("Adapting to new user...") + sleep(5 SECONDS) + notify("Adjoining optic [human.isSynthetic() ? "interface" : "nerve"], please be patient.",TRUE) + + var/percent_done = (world.time - (install_done - (30 MINUTES))) / (30 MINUTES) + + human.client.screen.Add(global_hud.whitense) + + switch(percent_done) //This is 0.0 to 1.0 kinda percent. + //Connecting to optical nerves + if(0.0 to 0.1) + human.eye_blind = 5 + + //Mapping brain + if(0.2 to 0.9) + if(prob(99)) return TRUE + var/incident = rand(1,3) + switch(incident) + if(1) + var/message = pick(list( + "Your head throbs around your new implant.", + "The skin around your recent surgery itches.", + "A wave of nausea overtakes you as the world seems to spin.", + "The floor suddenly seems to come up at you.", + "There's a throbbing lump of ice behind your eyes.", + "A wave of pain shoots down your neck." + )) + to_chat(human,"[message]") + if(2) + human.Weaken(5) + to_chat(human,"A wave of weakness rolls over you.") + if(3) + human.Sleeping(5) + to_chat(human,"You suddenly black out!") + + //Finishing up + if(1.0 to INFINITY) + stat = NIF_WORKING + owner = human.real_name + name = initial(name) + " ([owner])" + notify("Calibration complete! User data stored!") + +//Called each life() tick on the mob +/obj/item/device/nif/proc/life() + if(!human || loc != human.get_organ(BP_HEAD)) + unimplant(human) + return FALSE + + switch(stat) + if(NIF_WORKING) + //Perform our passive drain + if(!use_charge(power_usage)) + stat = NIF_POWFAIL + notify("Insufficient energy!",TRUE) + return FALSE + + //HUD update! + nif_hud.process_hud(human,1) + + //Process all the ones that want that + for(var/S in nifsofts_life) + var/datum/nifsoft/nifsoft = S + nifsoft.life(human) + + if(NIF_POWFAIL) + if(human && human.nutrition < 100) + return FALSE + else + stat = NIF_WORKING + notify("System Reboot Complete.") + + if(NIF_TEMPFAIL) + //Something else has to take us out of tempfail + return FALSE + + if(NIF_INSTALLING) + handle_install() + return FALSE + +//Prints 'AR' messages to the user +/obj/item/device/nif/proc/notify(var/message,var/alert = 0) + if(!human) return + + to_chat(human,"\[\icon[src.big_icon]NIF\] displays, \"[message]\"") + +//Called to spend nutrition, returns 1 if it was able to +/obj/item/device/nif/proc/use_charge(var/use_charge) + //You don't want us to take any? Well okay. + if(!use_charge) + return TRUE + + //Not enough nutrition/charge left. + if(!human || human.nutrition < use_charge) + return FALSE + + //Was enough, reduce and return. + human.nutrition -= use_charge + return TRUE + +//Install a piece of software +/obj/item/device/nif/proc/install(var/datum/nifsoft/new_soft) + if(nifsofts[new_soft.list_pos]) + return FALSE + + if(human) + var/applies_to = new_soft.applies_to + var/synth = human.isSynthetic() + if(synth && !(applies_to & NIF_SYNTHETIC)) + notify("The software \"[new_soft]\" is not supported on your chassis type.",TRUE) + return FALSE + if(!synth && !(applies_to & NIF_ORGANIC)) + notify("The software \"[new_soft]\" is not supported in organic life.",TRUE) + return FALSE + + nifsofts[new_soft.list_pos] = new_soft + power_usage += new_soft.p_drain + + if(new_soft.tick_flags == NIF_ALWAYSTICK) + nifsofts_life += new_soft + + if(new_soft.vision_flags) + vision_flags |= new_soft.vision_flags + if(new_soft.health_flags) + health_flags |= new_soft.health_flags + if(new_soft.combat_flags) + combat_flags |= new_soft.combat_flags + if(new_soft.other_flags) + other_flags |= new_soft.other_flags + + wear(new_soft.wear) + return TRUE + +//Uninstall a piece of software +/obj/item/device/nif/proc/uninstall(var/datum/nifsoft/old_soft) + var/datum/nifsoft/NS = old_soft.list_pos + if(!NS || NS != old_soft) + return FALSE //what?? + + nifsofts[old_soft.list_pos] = null + power_usage -= old_soft.p_drain + + if(old_soft.tick_flags == NIF_ALWAYSTICK) + nifsofts_life -= old_soft + + if(old_soft.active) + power_usage -= old_soft.a_drain + if(old_soft.tick_flags == NIF_ACTIVETICK) + nifsofts_life -= old_soft + + if(old_soft.vision_flags) + vision_flags &= ~old_soft.vision_flags + if(old_soft.health_flags) + health_flags &= ~old_soft.health_flags + if(old_soft.combat_flags) + combat_flags &= ~old_soft.combat_flags + if(old_soft.other_flags) + other_flags &= ~old_soft.other_flags + + return TRUE + +//Activate a nifsoft +/obj/item/device/nif/proc/activate(var/datum/nifsoft/soft) + if(human) + var/applies_to = soft.applies_to + var/synth = human.isSynthetic() + if(synth && !(applies_to & NIF_SYNTHETIC)) + notify("The software \"[soft]\" is not supported on your chassis type and will be uninstalled.",TRUE) + uninstall(soft) + return FALSE + if(!synth && !(applies_to & NIF_ORGANIC)) + notify("The software \"[soft]\" is not supported in organic life and will be uninstalled.",TRUE) + uninstall(soft) + return FALSE + + if(!use_charge(soft.a_drain)) + return FALSE + + if(soft.tick_flags == NIF_ACTIVETICK) + nifsofts_life += soft + + power_usage += soft.a_drain + human << click_sound + + return TRUE + +//Deactivate a nifsoft +/obj/item/device/nif/proc/deactivate(var/datum/nifsoft/soft) + if(soft.tick_flags == NIF_ACTIVETICK) + nifsofts_life -= soft + + power_usage -= soft.a_drain + human << click_sound + + return TRUE + +//Deactivate several nifsofts +/obj/item/device/nif/proc/deactivate_these(var/list/turn_off) + for(var/N in turn_off) + var/datum/nifsoft/NS = nifsofts[N] + if(NS) + NS.deactivate() + +//Add a flag to one of the holders +/obj/item/device/nif/proc/set_flag(var/flag,var/hint) + ASSERT(flag && hint) + + switch(hint) + if(NIF_FLAGS_VISION) + vision_flags |= flag + if(NIF_FLAGS_HEALTH) + health_flags |= flag + if(NIF_FLAGS_COMBAT) + combat_flags |= flag + if(NIF_FLAGS_OTHER) + other_flags |= flag + else + CRASH("Not a valid NIF flag hint: [hint]") + +//Clear a flag from one of the holders +/obj/item/device/nif/proc/clear_flag(var/flag,var/hint) + ASSERT(flag && hint) + + switch(hint) + if(NIF_FLAGS_VISION) + vision_flags &= ~flag + if(NIF_FLAGS_HEALTH) + health_flags &= ~flag + if(NIF_FLAGS_COMBAT) + combat_flags &= ~flag + if(NIF_FLAGS_OTHER) + other_flags &= ~flag + else + CRASH("Not a valid NIF flag hint: [hint]") + +//Check for an installed implant +/obj/item/device/nif/proc/imp_check(var/soft) + if(!stat == NIF_WORKING) return FALSE + ASSERT(soft) + + if(ispath(soft)) + var/datum/nifsoft/path = soft + soft = initial(path.list_pos) + var/entry = nifsofts[soft] + if(entry) + return entry + +//Check for a set flag +/obj/item/device/nif/proc/flag_check(var/flag,var/hint) + if(!stat == NIF_WORKING) return FALSE + ASSERT(flag && hint) + + var/result = FALSE + switch(hint) + if(NIF_FLAGS_VISION) + if(flag & vision_flags) result = TRUE + if(NIF_FLAGS_HEALTH) + if(flag & health_flags) result = TRUE + if(NIF_FLAGS_COMBAT) + if(flag & combat_flags) result = TRUE + if(NIF_FLAGS_OTHER) + if(flag & other_flags) result = TRUE + else + CRASH("Not a valid NIF flag hint: [hint]") + + return result + +//NIF HUD object becasue HUD handling is trash and should be rewritten +/obj/item/clothing/glasses/hud/nif_hud/var/obj/item/device/nif/nif + +/obj/item/clothing/glasses/hud/nif_hud/New(var/newloc) + ..(newloc) + nif = newloc + +/obj/item/clothing/glasses/hud/nif_hud/process_hud(M,var/thing) + //Faster checking with local var, and this is called often so I want fast. + var/visflags = nif.vision_flags + if(NIF_V_AR_OMNI & visflags) + process_omni_hud(nif.human, "best") + else if(NIF_V_AR_SECURITY & visflags) + process_omni_hud(nif.human, "sec") + else if(NIF_V_AR_MEDICAL & visflags) + process_omni_hud(nif.human, "med") + else if(NIF_V_AR_ENGINE & visflags) + process_omni_hud(nif.human, "eng") + else if(NIF_V_AR_SCIENCE & visflags) + process_omni_hud(nif.human, "sci") + else if(NIF_V_AR_CIVILIAN & visflags) + process_omni_hud(nif.human, "civ") diff --git a/code/modules/nifsoft/nif_softshop.dm b/code/modules/nifsoft/nif_softshop.dm new file mode 100644 index 0000000000..3680b47786 --- /dev/null +++ b/code/modules/nifsoft/nif_softshop.dm @@ -0,0 +1,111 @@ +//Custom vendors +/obj/machinery/vending/nifsoft_shop + name = "NIFSoft Shop" + desc = "For all your mindware and mindware accessories." + product_ads = "Let us get into your head!;Looking for an upgrade?;Surpass Humanity!;Why be normal when you can be SUPERnormal?;Jack in with NIFSoft!" + icon_state = "nifsoft" + icon_vend = "nifsoft-purchase" + icon_deny = "nifsoft-problem" + products = list() + contraband = list() + premium = list() + var/global/list/starting_legal_nifsoft + var/global/list/starting_illegal_nifsoft + +// Special Treatment! +/obj/machinery/vending/nifsoft_shop/build_inventory() + //Firsties + if(!starting_legal_nifsoft) + starting_legal_nifsoft = list() + starting_illegal_nifsoft = list() + for(var/P in subtypesof(/datum/nifsoft) - /datum/nifsoft/package) + var/datum/nifsoft/NS = P + if(initial(NS.initial)) + switch(initial(NS.illegal)) + if(TRUE) + starting_illegal_nifsoft += NS + if(FALSE) + starting_legal_nifsoft += NS + + products = starting_legal_nifsoft.Copy() + contraband = starting_illegal_nifsoft.Copy() + + var/list/all_products = list( + list(products, CAT_NORMAL), + list(contraband, CAT_HIDDEN), + list(premium, CAT_COIN)) + + for(var/current_list in all_products) + var/category = current_list[2] + + for(var/entry in current_list[1]) + var/datum/nifsoft/NS = entry + var/name = initial(NS.name) + var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry, name) + + product.price = initial(NS.cost) + product.amount = 10 + product.category = category + + product_records.Add(product) + +/obj/machinery/vending/nifsoft_shop/allowed(mob/user) + if(!ishuman(user)) + return FALSE + + var/mob/living/carbon/human/H = user + if(!H.nif || !H.nif.stat == NIF_WORKING) + to_chat(H,"[src] seems unable to connect to your NIF...") + flick(icon_deny,src) + return FALSE + + return ..() + +// Also special treatment! +/obj/machinery/vending/nifsoft_shop/vend(datum/stored_item/vending_product/R, mob/user) + var/mob/living/carbon/human/H = user + if((!allowed(usr)) && !emagged && scan_id && istype(H)) //For SECURE VENDING MACHINES YEAH + usr << "Purchase not allowed." //Unless emagged of course + flick(icon_deny,src) + return + vend_ready = 0 //One thing at a time!! + status_message = "Installing..." + status_error = 0 + nanomanager.update_uis(src) + + if(R.category & CAT_COIN) + if(!coin) + user << "You need to insert a coin to get this item." + return + if(coin.string_attached) + if(prob(50)) + user << "You successfully pull the coin out before \the [src] could swallow it." + else + user << "You weren't able to pull the coin out fast enough, the machine ate it, string and all." + qdel(coin) + coin = null + categories &= ~CAT_COIN + else + qdel(coin) + coin = null + categories &= ~CAT_COIN + + if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) + spawn(0) + speak(vend_reply) + last_reply = world.time + + use_power(vend_power_usage) //actuators and stuff + spawn(vend_delay) + R.amount-- + new R.item_path(H.nif) + flick(icon_vend,src) + if(has_logs) + do_logging(R, user, 1) + + status_message = "" + status_error = 0 + vend_ready = 1 + currently_vending = null + nanomanager.update_uis(src) + return 1 diff --git a/code/modules/nifsoft/nif_statpanel.dm b/code/modules/nifsoft/nif_statpanel.dm new file mode 100644 index 0000000000..990bf43565 --- /dev/null +++ b/code/modules/nifsoft/nif_statpanel.dm @@ -0,0 +1,77 @@ +/mob/living/carbon/human/Stat() + . = ..() + if(nif && statpanel("NIF")) + SetupNifStat() + +/mob/living/carbon/human/proc/SetupNifStat() + var/nif_status + switch(nif.stat) + if(NIF_WORKING) + nif_status = "Operating Normally" + if(NIF_POWFAIL) + nif_status = "Insufficient Energy!" + if(NIF_TEMPFAIL) + nif_status = "Needs Maintenance!" + if(NIF_INSTALLING) + nif_status = "Adapting To User" + else + nif_status = "Unknown - Error" + stat("NIF Status", nif_status) + + if(!nif.stat) + stat("- Modules -", "LMB: Toggle, Shift+LMB: Info/Uninstall") + for(var/nifsoft in nif.nifsofts) + if(!nifsoft) continue + var/datum/nifsoft/NS = nifsoft + var/obj/effect/nif_stat/stat_line = NS.stat_line + stat("[stat_line.nifsoft_name]",stat_line.atom_button_text()) + +/////////////////// +// Stat Line Object +/obj/effect/nif_stat + name = "" + var/nifsoft_name //Prevents deeper lookups, and the name won't change + var/datum/nifsoft/nifsoft //Reference to our nifsoft + var/toggleable = FALSE //Won't change, prevents looking it up deeper + +/obj/effect/nif_stat/New(var/datum/nifsoft/new_soft) + ..() + nifsoft = new_soft + nifsoft_name = new_soft.name + name = new_soft.name + toggleable = new_soft.activates + +/obj/effect/nif_stat/Destroy() + nifsoft = null + ..() + +/obj/effect/nif_stat/proc/atom_button_text() + if(!toggleable) + name = "Always On" + else + name = "[nifsoft.active ? "Active" : "Disabled"]" + return src + +/obj/effect/nif_stat/Click(var/location, var/control, var/params) + if(usr != nifsoft.nif.human) return + + var/list/clickprops = params2list(params) + var/opts = clickprops["shift"] + + if(opts) + var/choice = alert("Select an option","[nifsoft_name]","Display Info","Cancel","Uninstall") + switch(choice) + if("Display Info") + nifsoft.nif.notify("[nifsoft_name]: [nifsoft.desc] - It consumes [nifsoft.p_drain] energy units \ + while installed, and [nifsoft.a_drain] additionally while active. It is [nifsoft.illegal ? "NOT " : ""]\ + a legal software package. The MSRP of the package is [nifsoft.cost] Thalers. The difficulty to construct \ + the associated implant is Rating [nifsoft.wear].") + if("Uninstall") + var/confirm = alert("Really uninstall [nifsoft_name]?","Are you sure?","Cancel","Uninstall","Cancel") + if(confirm == "Uninstall") + nifsoft.uninstall() + else if(nifsoft.activates) + if(nifsoft.active) + nifsoft.deactivate() + else + nifsoft.activate() diff --git a/code/modules/nifsoft/nifsoft.dm b/code/modules/nifsoft/nifsoft.dm new file mode 100644 index 0000000000..453e00d79b --- /dev/null +++ b/code/modules/nifsoft/nifsoft.dm @@ -0,0 +1,110 @@ +//A single piece of NIF software +/datum/nifsoft + var/name = "Prototype" + var/desc = "Contact a dev!" + + var/obj/item/device/nif/nif //The NIF that the software is stored in + + var/list_pos // List position in the nifsoft list + + var/cost = 1000 // Cost in cash of buying this software from a terminal + //TODO - While coding + var/initial = TRUE // This is available in NIFSoft Shops at the start of the game + var/wear = 1 // The wear (+/- 10% when applied) that this causes to the NIF + var/list/req_one_access // What access they need to buy it + var/illegal = FALSE // If this is a black-market nifsoft (emag option) + + var/active = FALSE // Whether the active mode of this implant is on + var/p_drain = 0 // Passive power drain, can be used in various ways from the software + var/a_drain = 0 // Active power drain, same purpose as above, software can treat however + var/activates = TRUE // Whether or not this has an active power consumption mode + var/tick_flags = 0 // Flags to tell when we'd like to be ticked + + var/empable = TRUE // If the implant can be destroyed via EMP attack + + var/expiring = FALSE // Trial software! Or self-deleting illegal ones! + var/expires_at // World.time for when they expire + + var/applies_to = (NIF_ORGANIC|NIF_SYNTHETIC) // Who this software is useful for + + var/vision_flags = 0 // Various flags for fast lookups that are settable on the NIF + var/health_flags = 0 // These are added as soon as the implant is installed + var/combat_flags = 0 // Otherwise use set_flag on the nif in your activate/deactivate + var/other_flags = 0 + + var/obj/effect/nif_stat/stat_line + + +//Constructor accepts the NIF it's being loaded into +/datum/nifsoft/New(var/obj/item/device/nif/nif_load) + ASSERT(nif_load) + + nif = nif_load + stat_line = new(src) + if(!install(nif)) + qdel(src) + +//Destructor cleans up the software and nif reference +/datum/nifsoft/Destroy() + if(nif) + uninstall(nif) + nif = null + qdel(stat_line) + stat_line = null + ..() + +//Called when the software is installed in the NIF +/datum/nifsoft/proc/install() + return nif.install(src) + +//Called when the software is removed from the NIF +/datum/nifsoft/proc/uninstall() + if(active) + deactivate() + if(nif) + . = nif.uninstall(src) + qdel(src) + +//Called every life() tick on a mob on active implants +/datum/nifsoft/proc/life(var/mob/living/carbon/human/human) + return TRUE + +//Called when attempting to activate an implant (could be a 'pulse' activation or toggling it on) +/datum/nifsoft/proc/activate() + var/nif_result = nif.activate(src) + if(nif_result) + active = TRUE + return nif_result + +//Called when attempting to deactivate an implant +/datum/nifsoft/proc/deactivate() + var/nif_result = nif.deactivate(src) + if(nif_result) + active = FALSE + return nif_result + +//Called when an implant expires +/datum/nifsoft/proc/expire() + uninstall() + return + +////////////////////// +//A package of NIF software +/datum/nifsoft/package + var/list/software = list() + wear = 0 //Packages don't cause wear themselves, the software does + +//Constructor accepts a NIF and loads all the software +/datum/nifsoft/package/New(var/obj/item/device/nif/nif_load) + ASSERT(nif_load) + + for(var/P in software) + new P(nif_load) + + qdel(src) + +//Clean self up +/datum/nifsoft/package/Destroy() + software.Cut() + software = null + ..() diff --git a/code/modules/nifsoft/software/01_vision.dm b/code/modules/nifsoft/software/01_vision.dm new file mode 100644 index 0000000000..15f253d9b2 --- /dev/null +++ b/code/modules/nifsoft/software/01_vision.dm @@ -0,0 +1,253 @@ +////////////////// +// AR HUD Overlays +/datum/nifsoft/ar_civ + name = "AR Overlay (Civ)" + desc = "Provides a general identification and health status overlay on your vision with no frills." + list_pos = NIF_CIVILIAN_AR + cost = 500 + initial = TRUE + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR) + nif.set_flag(NIF_V_AR_CIVILIAN,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_CIVILIAN,NIF_FLAGS_VISION) + +/datum/nifsoft/ar_med + name = "AR Overlay (Med)" + desc = "Like the civilian model, but provides medical records access and virus database lookup." + list_pos = NIF_MEDICAL_AR + cost = 750 + initial = TRUE + req_one_access = list(access_medical) + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_CIVILIAN_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR) + nif.set_flag(NIF_V_AR_MEDICAL,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_MEDICAL,NIF_FLAGS_VISION) + +/datum/nifsoft/ar_sec + name = "AR Overlay (Sec)" + desc = "Like the civilian model, but provides access to arrest status and security records." + list_pos = NIF_SECURITY_AR + cost = 750 + initial = TRUE + req_one_access = list(access_security) + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR) + nif.set_flag(NIF_V_AR_SECURITY,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_SECURITY,NIF_FLAGS_VISION) + +/datum/nifsoft/ar_eng + name = "AR Overlay (Eng)" + desc = "Like the civilian model, but provides station alert notices." + list_pos = NIF_ENGINE_AR + cost = 750 + initial = TRUE + req_one_access = list(access_engine) + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_SCIENCE_AR,NIF_OMNI_AR) + nif.set_flag(NIF_V_AR_ENGINE,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_ENGINE,NIF_FLAGS_VISION) + +/datum/nifsoft/ar_science + name = "AR Overlay (Sci)" + desc = "Like the civilian model, but provides ... well, nothing. For now." + list_pos = NIF_SCIENCE_AR + cost = 750 + initial = TRUE + req_one_access = list(access_research) + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_OMNI_AR) + nif.set_flag(NIF_V_AR_SCIENCE,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_SCIENCE,NIF_FLAGS_VISION) + +/datum/nifsoft/ar_omni + name = "AR Overlay (Omni)" + desc = "Like the civilian model, but provides most of the features of the medical and security overlays as well." + list_pos = NIF_OMNI_AR + cost = 750 + initial = TRUE + req_one_access = list(access_captain) + a_drain = 0.05 + + activate() + if(..()) + nif.deactivate_these(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR) + nif.set_flag(NIF_V_AR_OMNI,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_AR_OMNI,NIF_FLAGS_VISION) + +////////////// +// Misc Vision +/datum/nifsoft/corrective + name = "Corrective AR" + desc = "Subtly alters perception to compensate for cataracts and retinal misalignment, among other common disabilities." + list_pos = NIF_CORRECTIVE_GLASS + cost = 200 + a_drain = 0.025 + + activate() + if(..()) + nif.set_flag(NIF_V_CORRECTIVE,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_CORRECTIVE,NIF_FLAGS_VISION) + +/datum/nifsoft/uvblocker + name = "Nictating Membrane" + desc = "A synthetic nictating membrane (aka 'third eyelid') that protects the eyes from UV or hostile atmospheres. Does not protect from photonic stun weapons." + list_pos = NIF_UVFILTER + cost = 450 + a_drain = 0.2 + + activate() + if(..()) + nif.set_flag(NIF_V_UVFILTER,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_UVFILTER,NIF_FLAGS_VISION) + +/datum/nifsoft/flashprot + name = "Responsive Filter" + desc = "Enables a high-speed shielding response to intense light, such as flashes, to block them." + list_pos = NIF_FLASHPROT + cost = 600 + req_one_access = list(access_security) + a_drain = 0.05 + + activate() + if(..()) + nif.set_flag(NIF_V_FLASHPROT,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_FLASHPROT,NIF_FLAGS_VISION) + +//////////////// +// Goggle-alikes +/datum/nifsoft/mesons + name = "Meson Scanner" + desc = "Similar to the worn Optical Meson Scanner Goggles, these allow you to see the base structure and terrain through walls." + list_pos = NIF_MESONS + cost = 1000 + a_drain = 0.1 + tick_flags = NIF_ACTIVETICK + + activate() + if(..()) + nif.deactivate_these(NIF_MATERIAL,NIF_THERMALS,NIF_NIGHTVIS) + nif.set_flag(NIF_V_MESONS,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_MESONS,NIF_FLAGS_VISION) + + life() + if(..()) + var/mob/living/carbon/human/H = nif.human + H.client.screen |= global_hud.meson + H.sight |= SEE_TURFS + +/datum/nifsoft/material + name = "Material Scanner" + desc = "Similar to the worn Optical Material Scanner Goggles, these allow you to see objects through walls." + list_pos = NIF_MATERIAL + cost = 1000 + a_drain = 0.1 + tick_flags = NIF_ACTIVETICK + + activate() + if(..()) + nif.deactivate_these(NIF_MESONS,NIF_THERMALS,NIF_NIGHTVIS) + nif.set_flag(NIF_V_MATERIAL,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_MATERIAL,NIF_FLAGS_VISION) + + life() + if(..()) + nif.human.sight |= SEE_OBJS + +/datum/nifsoft/thermals + name = "Thermal Scanner" + desc = "Similar to the worn Thermal Goggles, these allow you to see heat-emitting creatures through walls." + list_pos = NIF_THERMALS + cost = 1000 + req_one_access = list(access_security) + a_drain = 0.1 + tick_flags = NIF_ACTIVETICK + + activate() + if(..()) + nif.deactivate_these(NIF_MESONS,NIF_MATERIAL,NIF_NIGHTVIS) + nif.set_flag(NIF_V_THERMALS,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_THERMALS,NIF_FLAGS_VISION) + + life() + if(..()) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_MOBS + H.client.screen |= global_hud.thermal + H.see_invisible = SEE_INVISIBLE_NOLIGHTING + +/datum/nifsoft/nightvis + name = "Low-Light Amp" + desc = "Similar to the worn Night Vision Goggles, these allow you to see in complete darkness." + list_pos = NIF_NIGHTVIS + cost = 1000 + req_one_access = list(access_security) + a_drain = 0.1 + tick_flags = NIF_ACTIVETICK + + activate() + if(..()) + nif.deactivate_these(NIF_MESONS,NIF_MATERIAL,NIF_THERMALS) + nif.set_flag(NIF_V_NIGHTVIS,NIF_FLAGS_VISION) + + deactivate() + if(..()) + nif.clear_flag(NIF_V_NIGHTVIS,NIF_FLAGS_VISION) + + life() + if(..()) + var/mob/living/carbon/human/H = nif.human + H.see_in_dark += 7 + H.client.screen |= global_hud.nvg + H.see_invisible = SEE_INVISIBLE_NOLIGHTING + diff --git a/code/modules/nifsoft/software/05_health.dm b/code/modules/nifsoft/software/05_health.dm new file mode 100644 index 0000000000..4bc83c407f --- /dev/null +++ b/code/modules/nifsoft/software/05_health.dm @@ -0,0 +1,184 @@ +/* +#define NIF_SPAREBREATH 17 +*/ + +/datum/nifsoft/medichines_org + name = "Medichines (Org)" + desc = "An internal swarm of nanites to make sure you stay in good shape and to promote healing, or to preserve you if you are critically injured." + list_pos = NIF_ORGANIC_HEAL + cost = 2500 + p_drain = 0.05 + a_drain = 0.1 //This is messed with manually below. + activates = FALSE //It is automatic in emergencies, not manually controllable. + tick_flags = NIF_ALWAYSTICK + applies_to = NIF_ORGANIC + var/mode = 0 + + //These self-activate on their own, these aren't user-settable to on/off. + activate() + if(..()) + nif.set_flag(NIF_H_ORGREPAIR,NIF_FLAGS_HEALTH) + mode = 1 + + deactivate() + if(..()) + nif.clear_flag(NIF_H_ORGREPAIR,NIF_FLAGS_HEALTH) + a_drain = initial(a_drain) + mode = initial(mode) + nif.human.in_stasis = 0 + + life() + if(..()) + var/mob/living/carbon/human/H = nif.human + var/HP_percent = H.health/H.getMaxHealth() + + //Mode changing state machine + if(HP_percent >= 0.9) + if(mode) + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() + return TRUE + else if(!mode && HP_percent < 0.8) + nif.notify("User Status: INJURED. Commencing medichine routines.",TRUE) + activate() + else if(mode == 1 && HP_percent < 0.2) + nif.notify("User Status: DANGER. Seek medical attention!",TRUE) + mode = 2 + else if(mode == 2 && HP_percent < -0.4) + nif.notify("User Status: CRITICAL. Notifying medical, and starting emergency stasis!",TRUE) + mode = 3 + if(!ishuman(H.loc)) //Not notified in case of vore, for gameplay purposes. + var/turf/T = get_turf(H) + var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) + a.autosay("[H.real_name] has been put in emergency stasis, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical") + qdel(a) + + //Handle the actions in each mode + + //Injured but not critical + if(mode) + H.adjustToxLoss(-0.1 * mode) + H.adjustBruteLoss(-0.1 * mode) + H.adjustFireLoss(-0.1 * mode) + + if(mode >= 2) + nif.use_charge(a_drain) //A second drain if we're in level 2+ + + //Patient critical - emergency stasis + if(mode >= 3) + if(HP_percent <= 0) + H.in_stasis = 3 + if(HP_percent > 0.2) + H.in_stasis = 0 + nif.notify("Ending emergency stasis.",TRUE) + mode = 2 + + return TRUE + +/datum/nifsoft/medichines_syn + name = "Medichines (Syn)" + desc = "A swarm of mechanical repair nanites, able to repair relatively minor damage to synthetic bodies. Large repairs must still be performed manually." + list_pos = NIF_SYNTH_HEAL + cost = 2500 + p_drain = 0.05 + a_drain = 0.00 //This is manually drained below. + activates = FALSE //It is automatic in emergencies, not manually controllable. + tick_flags = NIF_ALWAYSTICK + applies_to = NIF_SYNTHETIC + var/mode = 0 + + //These self-activate on their own, these aren't user-settable to on/off. + activate() + if(..()) + nif.set_flag(NIF_H_SYNTHREPAIR,NIF_FLAGS_HEALTH) + mode = 1 + + deactivate() + if(..()) + nif.clear_flag(NIF_H_SYNTHREPAIR,NIF_FLAGS_HEALTH) + mode = 0 + + life() + if(..()) + //We're good! + if(!nif.human.bad_external_organs.len) + if(mode || active) + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() + return TRUE + + if(!mode && !active) + nif.notify("User Status: DAMAGED. Medichines performing minor repairs.",TRUE) + activate() + + for(var/eo in nif.human.bad_external_organs) + var/obj/item/organ/external/EO = eo + for(var/w in EO.wounds) + var/datum/wound/W = w + if(W.damage <= 5) + W.heal_damage(0.1) + EO.update_damages() + if(EO.update_icon()) + nif.human.UpdateDamageIcon(1) + nif.use_charge(0.1) + return TRUE //Return entirely, we only heal one at a time. + else if(mode == 1) + mode = 2 + nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE) + + return TRUE + +/datum/nifsoft/spare_breath + name = "Respirocytes" + desc = "Nanites simulating red blood cells will filter and recycle oxygen for a short time, preventing suffocation in hostile environments. NOTE: Only capable of supplying OXYGEN." + list_pos = NIF_SPAREBREATH + cost = 650 + p_drain = 0.05 + a_drain = 0.1 + tick_flags = NIF_ALWAYSTICK + applies_to = NIF_ORGANIC + var/filled = 100 //Tracks the internal tank 'refilling', which still uses power + + activate() + if(!(filled > 50)) + nif.notify("Respirocytes not saturated!",TRUE) + return FALSE + if(..()) + nif.set_flag(NIF_H_SPAREBREATH,NIF_FLAGS_HEALTH) + nif.notify("Now taking air from reserves.") + + deactivate() + if(..()) + nif.clear_flag(NIF_H_SPAREBREATH,NIF_FLAGS_HEALTH) + nif.notify("Now taking air from environment and refilling reserves.") + + life() + if(..()) + if(active) //Supplying air, not recharging it + switch(filled) //Text warnings + if(75) + nif.notify("Respirocytes at 75% saturation.",TRUE) + if(50) + nif.notify("Respirocytes at 50% saturation!",TRUE) + if(25) + nif.notify("Respirocytes at 25% saturation, seek a habitable environment!",TRUE) + if(5) + nif.notify("Respirocytes at 5% saturation! Failure imminent!",TRUE) + + if(filled == 0) //Ran out + deactivate() + else //Drain a little + filled-- + + else //Recharging air, not supplying it + if(filled == 100) + return TRUE + else if(nif.use_charge(0.1) && ++filled == 100) + nif.notify("Respirocytes now fully saturated.") + + proc/resp_breath() + if(!active) return null + var/datum/gas_mixture/breath = new() + breath.adjust_gas("oxygen", 300) + breath.temperature = T20C + return breath diff --git a/code/modules/nifsoft/software/10_combat.dm b/code/modules/nifsoft/software/10_combat.dm new file mode 100644 index 0000000000..64f3ae9a25 --- /dev/null +++ b/code/modules/nifsoft/software/10_combat.dm @@ -0,0 +1,7 @@ +/* +#define NIF_BRUTEARMOR 18 +#define NIF_BURNARMOR 19 +#define NIF_PAINKILLERS 20 +#define NIF_HARDCLAWS 21 +#define NIF_HIDDENLASER 22 +*/ \ No newline at end of file diff --git a/code/modules/nifsoft/software/15_misc.dm b/code/modules/nifsoft/software/15_misc.dm new file mode 100644 index 0000000000..a20e26c3a6 --- /dev/null +++ b/code/modules/nifsoft/software/15_misc.dm @@ -0,0 +1,9 @@ +/* +#define NIF_COMMLINK 23 +#define NIF_SUITSENSORS 24 +#define NIF_APCCHARGE 25 +#define NIF_PRESSURE 26 +#define NIF_HEATSINK 27 +#define NIF_UVFILTER 28 +#define NIF_FLASHPROT 29 +*/ \ No newline at end of file diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 583b56921d..63a1d2ff50 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -546,7 +546,7 @@ This function completely restores a damaged organ to perfect condition. /obj/item/organ/external/proc/need_process() if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_DEAD|ORGAN_MUTATED)) return 1 - if((brute_dam || burn_dam) && (robotic < ORGAN_ROBOT)) //Robot limbs don't autoheal and thus don't need to process when damaged + if(brute_dam || burn_dam)//VOREStation Edit - But they do for medichines! ---&& (robotic < ORGAN_ROBOT)) //Robot limbs don't autoheal and thus don't need to process when damaged return 1 if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. last_dam = brute_dam + burn_dam diff --git a/icons/obj/device_alt.dmi b/icons/obj/device_alt.dmi index e434cfb7ac..1a256c07b0 100644 Binary files a/icons/obj/device_alt.dmi and b/icons/obj/device_alt.dmi differ diff --git a/icons/obj/vending_vr.dmi b/icons/obj/vending_vr.dmi index 7d71132986..b6c7cbb8e6 100644 Binary files a/icons/obj/vending_vr.dmi and b/icons/obj/vending_vr.dmi differ diff --git a/vorestation.dme b/vorestation.dme index 43703a8306..86ab4afd95 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1965,11 +1965,13 @@ #include "code\modules\nano\modules\power_monitor.dm" #include "code\modules\nano\modules\rcon.dm" #include "code\modules\nifsoft\nif.dm" -#include "code\modules\nifsoft\nif_interface.dm" #include "code\modules\nifsoft\nif_softshop.dm" #include "code\modules\nifsoft\nif_statpanel.dm" #include "code\modules\nifsoft\nifsoft.dm" -#include "code\modules\nifsoft\software\vision.dm" +#include "code\modules\nifsoft\software\01_vision.dm" +#include "code\modules\nifsoft\software\05_health.dm" +#include "code\modules\nifsoft\software\10_combat.dm" +#include "code\modules\nifsoft\software\15_misc.dm" #include "code\modules\organs\blood.dm" #include "code\modules\organs\misc.dm" #include "code\modules\organs\organ.dm"