Merge pull request #13699 from silicons/nanite_updates

nanite updates: permanent nanites, hostile lockdown, anti-virus, resistance tweaking
This commit is contained in:
DeltaFire
2020-12-14 05:56:48 +01:00
committed by GitHub
12 changed files with 268 additions and 45 deletions

View File

@@ -490,6 +490,17 @@
#define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful #define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
#define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites #define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
#define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component #define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
/// Checks if a nanite component is able to be controlled by console
#define COMSIG_NANITE_CHECK_CONSOLE_LOCK "is_console_locked"
/// Checks if a nanite component is able to be interfaced with by a host with innate nanite control
#define COMSIG_NANITE_CHECK_HOST_LOCK "is_host_locked"
/// Checks if a nanite component is able to be overwritten by viral replica
#define COMSIG_NANITE_CHECK_VIRAL_PREVENTION "is_virus_locked"
#define NANITE_CHANGES_LOCKED 1
// Internal signals that programs register to and respond with to not require for loops
#define COMSIG_NANITE_INTERNAL_CONSOLE_LOCK_CHECK "naniteiconsolelocked"
#define COMSIG_NANITE_INTERNAL_HOST_LOCK_CHECK "naniteihostlocked"
#define COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK "naniteiviruslocked"
// /datum/component/storage signals // /datum/component/storage signals
#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool. #define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.

View File

@@ -48,6 +48,8 @@
#define MOB_EPIC (1 << 7) // Megafauna #define MOB_EPIC (1 << 7) // Megafauna
#define MOB_REPTILE (1 << 8) #define MOB_REPTILE (1 << 8)
#define MOB_SPIRIT (1 << 9) #define MOB_SPIRIT (1 << 9)
/// Mobs that otherwise support nanites
#define MOB_NANITES (1 << 10)
// Organ defines for carbon mobs // Organ defines for carbon mobs
#define ORGAN_ORGANIC 1 #define ORGAN_ORGANIC 1
@@ -56,6 +58,7 @@
#define BODYPART_ORGANIC 1 #define BODYPART_ORGANIC 1
#define BODYPART_ROBOTIC 2 #define BODYPART_ROBOTIC 2
#define BODYPART_HYBRID 3 #define BODYPART_HYBRID 3
#define BODYPART_NANITES 4
#define HYBRID_BODYPART_DAMAGE_THRESHHOLD 25 //How much damage has to be suffered until the damage threshhold counts as passed #define HYBRID_BODYPART_DAMAGE_THRESHHOLD 25 //How much damage has to be suffered until the damage threshhold counts as passed
#define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 15 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage. #define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 15 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage.

View File

@@ -17,6 +17,44 @@
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
/// Delete ourselves when we're depleted.
var/qdel_self_on_depletion = TRUE
/// Allow deletion
var/can_be_deleted = TRUE
/// Whether or not we can survive no cloud syncing without errors
var/requires_cloud_sync = TRUE
/// Permanent programs - can never be deleted. does not count towards max_programs.
var/list/datum/nanite_program/permanent_programs = list()
// Vulnerabilities
/// EMP flat deletion upper
var/emp_flat_deletion_upper = 35
/// EMP flat deletion lower
var/emp_flat_deletion_lower = 20
/// EMP percent deletion upper
var/emp_percent_deletion_upper = 0.35
/// EMP percent deletion lower
var/emp_percent_deletion_lower = 0.30
/// EMP severity multiplier, capping to 0 to 100
var/emp_severity_mod = 1
/// EMP severity div for cloudsync reset chance
var/emp_desync_mod = 0.25
/// Shock flat deletion upper
var/shock_flat_deletion_upper = 45
/// Shock flat deletion lower
var/shock_flat_deletion_lower = 25
/// Shock percent deletion upper
var/shock_percent_deletion_upper = 0.25
/// Shock percent deletion lower
var/shock_percent_deletion_lower = 0.20
/// minor shock deletion lower
var/minor_shock_deletion_lower = 5
/// minor shock deletion upper
var/minor_shock_deletion_upper = 15
/datum/component/nanites/Initialize(amount = 100, cloud = 0) /datum/component/nanites/Initialize(amount = 100, cloud = 0)
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup)) if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
return COMPONENT_INCOMPATIBLE return COMPONENT_INCOMPATIBLE
@@ -55,6 +93,9 @@
RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program) RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program)
RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan) RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan)
RegisterSignal(parent, COMSIG_NANITE_SYNC, .proc/sync) RegisterSignal(parent, COMSIG_NANITE_SYNC, .proc/sync)
RegisterSignal(parent, COMSIG_NANITE_CHECK_CONSOLE_LOCK, .proc/check_console_locking)
RegisterSignal(parent, COMSIG_NANITE_CHECK_HOST_LOCK, .proc/check_host_lockout)
RegisterSignal(parent, COMSIG_NANITE_CHECK_VIRAL_PREVENTION, .proc/check_viral_prevention)
if(isliving(parent)) if(isliving(parent))
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
@@ -118,13 +159,63 @@
next_sync = world.time + NANITE_SYNC_DELAY next_sync = world.time + NANITE_SYNC_DELAY
set_nanite_bar() set_nanite_bar()
/**
* Called when nanites are depleted.
* Deletes ourselves by default.
*/
/datum/component/nanites/proc/nanites_depleted()
if(qdel_self_on_depletion)
delete_nanites()
/**
* Used to rid ourselves
*/
/datum/component/nanites/proc/delete_nanites() /datum/component/nanites/proc/delete_nanites()
if(can_be_deleted)
qdel(src) qdel(src)
/**
* Adds permanent programs
*
* WARNING: Has no sanity checks. Make sure you know what you are doing! (make sure programs do not conflict)
*/
/datum/component/nanites/proc/add_permanent_program(list/program, immutable = FALSE)
if(!islist(program))
program = list(program)
for(var/i in program)
if(i in permanent_programs)
continue
var/datum/nanite_program/P = i
permanent_programs += P
if(immutable)
P.immutable = TRUE
for(var/e in programs)
var/datum/nanite_program/E = e
if(E.unique && (E.type == P.type))
qdel(e)
programs += P
/**
* Checks if we can block out console modification
*/
/datum/component/nanites/proc/check_console_locking()
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_CONSOLE_LOCK_CHECK)
/**
* Checks if we can lock out host internal conscious modification
*/
/datum/component/nanites/proc/check_host_lockout()
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_HOST_LOCK_CHECK)
/**
* Checks if we can block out viral replica
*/
/datum/component/nanites/proc/check_viral_prevention()
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK)
//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status) //Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
/datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE) /datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
var/list/programs_to_remove = programs.Copy() var/list/programs_to_remove = programs.Copy() - permanent_programs
var/list/programs_to_add = source.programs.Copy() var/list/programs_to_add = source.programs.Copy()
for(var/X in programs) for(var/X in programs)
var/datum/nanite_program/NP = X var/datum/nanite_program/NP = X
@@ -151,7 +242,7 @@
sync(null, cloud_copy) sync(null, cloud_copy)
return return
//Without cloud syncing nanites can accumulate errors and/or defects //Without cloud syncing nanites can accumulate errors and/or defects
if(prob(8) && programs.len) if(prob(8) && programs.len && requires_cloud_sync)
var/datum/nanite_program/NP = pick(programs) var/datum/nanite_program/NP = pick(programs)
NP.software_error() NP.software_error()
@@ -159,8 +250,11 @@
for(var/X in programs) for(var/X in programs)
var/datum/nanite_program/NP = X var/datum/nanite_program/NP = X
if(NP.unique && NP.type == new_program.type) if(NP.unique && NP.type == new_program.type)
if(NP in permanent_programs)
return COMPONENT_PROGRAM_NOT_INSTALLED
else
qdel(NP) qdel(NP)
if(programs.len >= max_programs) if((programs.len - length(permanent_programs)) >= max_programs)
return COMPONENT_PROGRAM_NOT_INSTALLED return COMPONENT_PROGRAM_NOT_INSTALLED
if(source_program) if(source_program)
source_program.copy_programming(new_program) source_program.copy_programming(new_program)
@@ -177,7 +271,7 @@
/datum/component/nanites/proc/adjust_nanites(datum/source, amount) /datum/component/nanites/proc/adjust_nanites(datum/source, amount)
nanite_volume = clamp(nanite_volume + amount, 0, max_nanites) nanite_volume = clamp(nanite_volume + amount, 0, max_nanites)
if(nanite_volume <= 0) //oops we ran out if(nanite_volume <= 0) //oops we ran out
qdel(src) nanites_depleted()
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE) /datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD] var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
@@ -191,28 +285,28 @@
holder.icon_state = "nanites[nanite_percent]" holder.icon_state = "nanites[nanite_percent]"
/datum/component/nanites/proc/on_emp(datum/source, severity) /datum/component/nanites/proc/on_emp(datum/source, severity)
nanite_volume *= (rand(60, 90) * 0.01) //Lose 10-40% of nanites severity *= emp_severity_mod
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume var/loss = (severity / 100) * (rand(emp_percent_deletion_lower, emp_percent_deletion_upper) * nanite_volume) + rand(emp_flat_deletion_lower, emp_flat_deletion_upper)
if(prob(40/severity)) adjust_nanites(null, -loss)
if(prob(severity * emp_desync_mod))
cloud_id = 0 cloud_id = 0
for(var/X in programs) for(var/X in programs)
var/datum/nanite_program/NP = X var/datum/nanite_program/NP = X
NP.on_emp(severity) NP.on_emp(severity)
/datum/component/nanites/proc/on_shock(datum/source, shock_damage, siemens_coeff = 1, flags = NONE) /datum/component/nanites/proc/on_shock(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
if(shock_damage < 1) if(shock_damage < 1)
return return
if(!HAS_TRAIT_NOT_FROM(host_mob, TRAIT_SHOCKIMMUNE, "nanites"))//Another shock protection must protect nanites too, but nanites protect only host if(!HAS_TRAIT_NOT_FROM(host_mob, TRAIT_SHOCKIMMUNE, "nanites"))//Another shock protection must protect nanites too, but nanites protect only host
nanite_volume *= (rand(45, 80) * 0.01) //Lose 20-55% of nanites var/loss = (rand(shock_percent_deletion_lower, shock_percent_deletion_upper) * nanite_volume) + rand(shock_flat_deletion_lower, shock_flat_deletion_upper)
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume adjust_nanites(null, -loss)
for(var/X in programs) for(var/X in programs)
var/datum/nanite_program/NP = X var/datum/nanite_program/NP = X
NP.on_shock(shock_damage) NP.on_shock(shock_damage)
/datum/component/nanites/proc/on_minor_shock(datum/source) /datum/component/nanites/proc/on_minor_shock(datum/source)
adjust_nanites(null, -(rand(5, 15))) //Lose 5-15 flat nanite volume adjust_nanites(null, -(rand(minor_shock_deletion_lower, minor_shock_deletion_upper))) //Lose 5-15 flat nanite volume
for(var/X in programs) for(var/X in programs)
var/datum/nanite_program/NP = X var/datum/nanite_program/NP = X
NP.on_minor_shock() NP.on_minor_shock()
@@ -237,7 +331,7 @@
NP.receive_comm_signal(comm_code, comm_message, comm_source) NP.receive_comm_signal(comm_code, comm_message, comm_source)
/datum/component/nanites/proc/check_viable_biotype() /datum/component/nanites/proc/check_viable_biotype()
if(!(host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) if(!(host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD|MOB_NANITES)))
qdel(src) //bodytype no longer sustains nanites qdel(src) //bodytype no longer sustains nanites
/datum/component/nanites/proc/check_access(datum/source, obj/O) /datum/component/nanites/proc/check_access(datum/source, obj/O)
@@ -378,3 +472,10 @@
id++ id++
mob_programs += list(mob_program) mob_programs += list(mob_program)
data["mob_programs"] = mob_programs data["mob_programs"] = mob_programs
/**
* Subtype that doesn't erase itself from running out
*/
/datum/component/nanites/permanent
qdel_self_on_depletion = FALSE
can_be_deleted = FALSE

View File

@@ -113,7 +113,7 @@
/datum/design/nanites/spreading /datum/design/nanites/spreading
name = "Infective Exo-Locomotion" name = "Infective Exo-Locomotion"
desc = "The nanites gain the ability to survive for brief periods outside of the human body, as well as the ability to start new colonies without an integration process; \ desc = "The nanites gain the ability to survive for brief periods outside of the human body, as well as the ability to start new colonies without an integration process; \
resulting in an extremely infective strain of nanites." resulting in an extremely infective strain of nanites. Bypasses antiviral defense"
id = "spreading_nanites" id = "spreading_nanites"
program_type = /datum/nanite_program/spreading program_type = /datum/nanite_program/spreading
category = list("Utility Nanites") category = list("Utility Nanites")
@@ -133,6 +133,21 @@
program_type = /datum/nanite_program/mitosis program_type = /datum/nanite_program/mitosis
category = list("Utility Nanites") category = list("Utility Nanites")
/datum/design/nanites/antiviral
name = "Enhanced Error Correction"
desc = "The nanites self-propagate and replicate their program storage memory, preventing viral takeovers."
id = "antiviral_nanites"
program_type = /datum/nanite_program/lockout/antiviral
category = list("Utility Nanites")
/datum/design/nanites/hostile_lockdown
name = "Hostile Lockdown"
desc = "The nanites constantly encrypt and scramble their own control sectors, preventing consoles from controlling them. Furthermore, \
if the host happens to be a synthetic organism with innate control over nanite strains, this will prevent them from acting on the nanites as well."
id = "hostile_lockdown"
program_type = /datum/nanite_program/lockout/hostile_lockdown
category = list("Utility Nanites")
////////////////////MEDICAL NANITES////////////////////////////////////// ////////////////////MEDICAL NANITES//////////////////////////////////////
/datum/design/nanites/regenerative /datum/design/nanites/regenerative
name = "Accelerated Regeneration" name = "Accelerated Regeneration"

View File

@@ -41,12 +41,12 @@
update_icon() update_icon()
/obj/machinery/nanite_chamber/proc/set_safety(threshold) /obj/machinery/nanite_chamber/proc/set_safety(threshold)
if(!occupant) if(!occupant || SEND_SIGNAL(occupant, COMSIG_NANITE_CHECK_CONSOLE_LOCK))
return return
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_SAFETY, threshold) SEND_SIGNAL(occupant, COMSIG_NANITE_SET_SAFETY, threshold)
/obj/machinery/nanite_chamber/proc/set_cloud(cloud_id) /obj/machinery/nanite_chamber/proc/set_cloud(cloud_id)
if(!occupant) if(!occupant || SEND_SIGNAL(occupant, COMSIG_NANITE_CHECK_CONSOLE_LOCK))
return return
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id) SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id)
@@ -82,7 +82,7 @@
return return
if((stat & MAINT) || panel_open) if((stat & MAINT) || panel_open)
return return
if(!occupant || busy) if(!occupant || busy || SEND_SIGNAL(occupant, COMSIG_NANITE_CHECK_CONSOLE_LOCK))
return return
var/locked_state = locked var/locked_state = locked
@@ -173,7 +173,6 @@
return FALSE return FALSE
..() ..()
return TRUE return TRUE
/obj/machinery/nanite_chamber/relaymove(mob/user as mob) /obj/machinery/nanite_chamber/relaymove(mob/user as mob)

View File

@@ -50,6 +50,10 @@
data["status_msg"] = chamber.busy_message data["status_msg"] = chamber.busy_message
return data return data
if(SEND_SIGNAL(L, COMSIG_NANITE_CHECK_CONSOLE_LOCK))
data["status_msg"] = "Error: Nanite keycodes scrambled. Unable to operate."
return data
data["status_msg"] = null data["status_msg"] = null
data["scan_level"] = chamber.scan_level data["scan_level"] = chamber.scan_level
data["locked"] = chamber.locked data["locked"] = chamber.locked

View File

@@ -54,6 +54,13 @@
//Rules that automatically manage if the program's active without requiring separate sensor programs //Rules that automatically manage if the program's active without requiring separate sensor programs
var/list/datum/nanite_rule/rules = list() var/list/datum/nanite_rule/rules = list()
/// Corruptable - able to have code/configuration changed
var/corruptable = TRUE
/// error flicking - able to be randomly toggled by errors
var/error_flicking = TRUE
/// immutable - cannot be overwritten by other programs
var/immutable = FALSE
/datum/nanite_program/New() /datum/nanite_program/New()
. = ..() . = ..()
register_extra_settings() register_extra_settings()
@@ -68,8 +75,15 @@
on_mob_remove() on_mob_remove()
if(nanites) if(nanites)
nanites.programs -= src nanites.programs -= src
nanites.permanent_programs -= src
return ..() return ..()
/**
* Checks if we're a permanent program
*/
/datum/nanite_program/proc/is_permanent()
return nanites && (src in nanites.permanent_programs)
/datum/nanite_program/proc/copy() /datum/nanite_program/proc/copy()
var/datum/nanite_program/new_program = new type() var/datum/nanite_program/new_program = new type()
copy_programming(new_program, TRUE) copy_programming(new_program, TRUE)
@@ -77,6 +91,8 @@
return new_program return new_program
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE) /datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
if(target.immutable)
return
if(copy_activated) if(copy_activated)
target.activated = activated target.activated = activated
target.timer_restart = timer_restart target.timer_restart = timer_restart
@@ -234,7 +250,7 @@
/datum/nanite_program/proc/on_emp(severity) /datum/nanite_program/proc/on_emp(severity)
if(program_flags & NANITE_EMP_IMMUNE) if(program_flags & NANITE_EMP_IMMUNE)
return return
if(prob(80 / severity)) if(prob(severity / 2))
software_error() software_error()
/datum/nanite_program/proc/on_shock(shock_damage) /datum/nanite_program/proc/on_shock(shock_damage)
@@ -242,7 +258,7 @@
if(prob(10)) if(prob(10))
software_error() software_error()
else if(prob(33)) else if(prob(33))
qdel(src) self_destruct()
/datum/nanite_program/proc/on_minor_shock() /datum/nanite_program/proc/on_minor_shock()
if(!program_flags & NANITE_SHOCK_IMMUNE) if(!program_flags & NANITE_SHOCK_IMMUNE)
@@ -254,26 +270,29 @@
/datum/nanite_program/proc/software_error(type) /datum/nanite_program/proc/software_error(type)
if(!type) if(!type)
type = rand(1,5) type = rand(1,is_permanent()? 4 : 5)
switch(type) switch(type)
if(1) if(1)
qdel(src) //kill switch self_destruct() //kill switch
return return
if(2) //deprogram codes if(2) //deprogram codes
if(corruptable)
activation_code = 0 activation_code = 0
deactivation_code = 0 deactivation_code = 0
kill_code = 0 kill_code = 0
trigger_code = 0 trigger_code = 0
if(3) if(3)
if(error_flicking)
toggle() //enable/disable toggle() //enable/disable
if(4) if(4)
if(can_trigger) if(error_flicking && can_trigger)
trigger() trigger()
if(5) //Program is scrambled and does something different if(5) //Program is scrambled and does something different
if(corruptable)
var/rogue_type = pick(rogue_types) var/rogue_type = pick(rogue_types)
var/datum/nanite_program/rogue = new rogue_type var/datum/nanite_program/rogue = new rogue_type
nanites.add_program(null, rogue, src) nanites.add_program(null, rogue, src)
qdel(src) self_destruct()
/datum/nanite_program/proc/receive_signal(code, source) /datum/nanite_program/proc/receive_signal(code, source)
if(activation_code && code == activation_code && !activated) if(activation_code && code == activation_code && !activated)
@@ -285,10 +304,18 @@
if(can_trigger && trigger_code && code == trigger_code) if(can_trigger && trigger_code && code == trigger_code)
trigger() trigger()
host_mob.investigate_log("'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES) host_mob.investigate_log("'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
if(kill_code && code == kill_code) if((kill_code && code == kill_code) && !is_permanent())
host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES) host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
qdel(src) qdel(src)
/**
* Attempts to destroy ourselves
*/
/datum/nanite_program/proc/self_destruct()
if(is_permanent())
return
qdel(src)
///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once. ///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once.
//Moved to being 'normally' researched due to lack of B.E.P.I.S. //Moved to being 'normally' researched due to lack of B.E.P.I.S.
/datum/nanite_program/protocol /datum/nanite_program/protocol

View File

@@ -11,7 +11,7 @@
return FALSE return FALSE
if(iscarbon(host_mob)) if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob var/mob/living/carbon/C = host_mob
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC)) var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC, BODYPART_NANITES))
if(!parts.len) if(!parts.len)
return FALSE return FALSE
return ..() return ..()
@@ -19,7 +19,7 @@
/datum/nanite_program/regenerative/active_effect() /datum/nanite_program/regenerative/active_effect()
if(iscarbon(host_mob)) if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob var/mob/living/carbon/C = host_mob
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC)) var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC, BODYPART_NANITES))
if(!parts.len) if(!parts.len)
return return
for(var/obj/item/bodypart/L in parts) for(var/obj/item/bodypart/L in parts)
@@ -121,7 +121,7 @@
if(iscarbon(host_mob)) if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob var/mob/living/carbon/C = host_mob
var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = list(BODYPART_ROBOTIC, BODYPART_HYBRID)) var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = list(BODYPART_ROBOTIC, BODYPART_HYBRID, BODYPART_NANITES))
if(!parts.len) if(!parts.len)
return FALSE return FALSE
else else
@@ -132,7 +132,7 @@
/datum/nanite_program/repairing/active_effect(mob/living/M) /datum/nanite_program/repairing/active_effect(mob/living/M)
if(iscarbon(host_mob)) if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob var/mob/living/carbon/C = host_mob
var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = list(BODYPART_ROBOTIC, BODYPART_HYBRID)) var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = list(BODYPART_ROBOTIC, BODYPART_HYBRID, BODYPART_NANITES))
if(!parts.len) if(!parts.len)
return return
var/update = FALSE var/update = FALSE
@@ -176,12 +176,12 @@
/datum/nanite_program/regenerative_advanced/active_effect() /datum/nanite_program/regenerative_advanced/active_effect()
if(iscarbon(host_mob)) if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob var/mob/living/carbon/C = host_mob
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC)) var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC, BODYPART_NANITES))
if(!parts.len) if(!parts.len)
return return
var/update = FALSE var/update = FALSE
for(var/obj/item/bodypart/L in parts) for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(3/parts.len, 3/parts.len, FALSE)) if(L.heal_damage(3/parts.len, 3/parts.len, 0))
update = TRUE update = TRUE
if(update) if(update)
host_mob.update_damage_overlays() host_mob.update_damage_overlays()

View File

@@ -16,7 +16,7 @@
var/datum/nanite_extra_setting/program = extra_settings[NES_PROGRAM_OVERWRITE] var/datum/nanite_extra_setting/program = extra_settings[NES_PROGRAM_OVERWRITE]
var/datum/nanite_extra_setting/cloud = extra_settings[NES_CLOUD_OVERWRITE] var/datum/nanite_extra_setting/cloud = extra_settings[NES_CLOUD_OVERWRITE]
for(var/mob/M in orange(host_mob, 5)) for(var/mob/M in orange(host_mob, 5))
if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY)) if(SEND_SIGNAL(M, COMSIG_NANITE_CHECK_VIRAL_PREVENTION))
continue continue
switch(program.get_value()) switch(program.get_value())
if("Overwrite") if("Overwrite")
@@ -350,3 +350,66 @@
/datum/action/innate/nanite_button/Activate() /datum/action/innate/nanite_button/Activate()
program.press() program.press()
/datum/nanite_program/lockout
unique = TRUE
var/emp_disable_time = 0
var/shock_disable_time = 0
var/minor_shock_disable_time = 0
var/disable_time = 0
var/lock_console = FALSE
var/lock_virus = FALSE
var/lock_host = FALSE
/datum/nanite_program/lockout/enable_passive_effect()
. = ..()
if(lock_console)
RegisterSignal(src, COMSIG_NANITE_INTERNAL_CONSOLE_LOCK_CHECK, .proc/check_antivirus)
if(lock_host)
RegisterSignal(src, COMSIG_NANITE_INTERNAL_HOST_LOCK_CHECK, .proc/check_antivirus)
if(lock_virus)
RegisterSignal(src, COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK, .proc/check_antivirus)
/datum/nanite_program/lockout/disable_passive_effect()
. = ..()
UnregisterSignal(src, list(
COMSIG_NANITE_INTERNAL_HOST_LOCK_CHECK,
COMSIG_NANITE_INTERNAL_CONSOLE_LOCK_CHECK,
COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK
))
/datum/nanite_program/lockout/on_emp(severity)
// no parent call on purpose
disable_time = max(disable_time, world.time + emp_disable_time)
/datum/nanite_program/lockout/on_shock(shock_damage)
// no parent call on purpose
disable_time = max(disable_time, world.time + shock_disable_time)
/datum/nanite_program/lockout/on_minor_shock()
// no parent call on purpose
disable_time = max(disable_time, world.time + minor_shock_disable_time)
/datum/nanite_program/lockout/proc/check_antivirus()
return (world.time <= disable_time)? NANITE_CHANGES_LOCKED : NONE
/datum/nanite_program/lockout/antiviral
name = "Enhanced Error Correction"
desc = "Through expensive CRC checking and replication, prevents viral takeover of the nanite strain's control sectors. \
Temporarily disabled by EMPs and shocks."
use_rate = 0.5
emp_disable_time = 3 MINUTES
shock_disable_time = 45 SECONDS
minor_shock_disable_time = 10 SECONDS
lock_virus = TRUE
/datum/nanite_program/lockout/hostile_lockdown
name = "Hostile Lockdown"
desc = "Constantly encrypts and scrambles the nanites' control memory, preventing consoles from modifying them and also locking out conscious host control of the nanite strain, if the host happens to be capable of that. \
Temporarily disabled by EMPs and shocks."
use_rate = 0.5
emp_disable_time = 3 MINUTES
shock_disable_time = 1 MINUTES
minor_shock_disable_time = 15 SECONDS
lock_host = TRUE
lock_console = TRUE

View File

@@ -91,7 +91,7 @@
var/heavy_range = FLOOR(nanite_amount/100, 1) - 1 var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
var/light_range = FLOOR(nanite_amount/50, 1) - 1 var/light_range = FLOOR(nanite_amount/50, 1) - 1
explosion(host_mob, 0, heavy_range, light_range) explosion(host_mob, 0, heavy_range, light_range)
qdel(nanites) nanites.delete_nanites()
//TODO make it defuse if triggered again //TODO make it defuse if triggered again

View File

@@ -23,7 +23,7 @@
display_name = "Mesh Nanite Programming" display_name = "Mesh Nanite Programming"
description = "Nanite programs that require static structures and membranes." description = "Nanite programs that require static structures and membranes."
prereq_ids = list("nanite_base","engineering") prereq_ids = list("nanite_base","engineering")
design_ids = list("hardening_nanites", "dermal_button_nanites", "refractive_nanites", "cryo_nanites", "conductive_nanites", "shock_nanites", "emp_nanites", "temperature_nanites") design_ids = list("hardening_nanites", "dermal_button_nanites", "refractive_nanites", "cryo_nanites", "conductive_nanites", "shock_nanites", "emp_nanites", "temperature_nanites", "antiviral_nanites", "hostile_lockdown")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/nanite_bio /datum/techweb_node/nanite_bio

View File

@@ -212,7 +212,7 @@
return ..() return ..()
if(HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM)) if(HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM))
C.adjustToxLoss(1, toxins_type = TOX_SYSCORRUPT) //Interferes with robots. Rare chem, so, pretty good at that too. C.adjustToxLoss(1, toxins_type = TOX_SYSCORRUPT) //Interferes with robots. Rare chem, so, pretty good at that too.
N.nanite_volume += -cached_purity*5//0.5 seems to be the default to me, so it'll neuter them. N.adjust_nanites(-cached_purity*5) //0.5 seems to be the default to me, so it'll neuter them.
..() ..()
/datum/reagent/fermi/nanite_b_gone/overdose_process(mob/living/carbon/C) /datum/reagent/fermi/nanite_b_gone/overdose_process(mob/living/carbon/C)
@@ -227,7 +227,7 @@
to_chat(C, "<span class='warning'>You feel a strange tingling sensation come from your core.</b></span>") to_chat(C, "<span class='warning'>You feel a strange tingling sensation come from your core.</b></span>")
if(isnull(N)) if(isnull(N))
return ..() return ..()
N.nanite_volume += -10*cached_purity N.adjust_nanites(-10*cached_purity)
..() ..()
datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume) datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)