diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm
index acee6a8b65b..1f7ed8c04a1 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 00000000000..e4d4f122932
--- /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 632f9afdfd9..758678bed97 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 8c4067187fe..555488cd898 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 354a26221c4..403088dc4bd 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 47da8c88f8a..47e12f3f6da 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 4fa6ae11176..4331b05407e 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 753cf3255e7..75d598fb696 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 a04232c401a..0a3d2fcb3fb 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 00000000000..b4ef9eafd70
--- /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 00000000000..3680b47786a
--- /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 00000000000..990bf435656
--- /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 00000000000..453e00d79b1
--- /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 00000000000..15f253d9b28
--- /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 00000000000..4bc83c407f1
--- /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 00000000000..64f3ae9a252
--- /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 00000000000..a20e26c3a6a
--- /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 583b56921dc..63a1d2ff50f 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 e434cfb7ac0..1a256c07b06 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 7d71132986f..b6c7cbb8e6c 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 43703a8306b..86ab4afd95c 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"