This commit is contained in:
silicons
2020-11-22 14:16:14 -07:00
parent 8f7289036d
commit 37e26833a6
4 changed files with 167 additions and 29 deletions
+11
View File
@@ -490,6 +490,17 @@
#define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
#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
/// 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
#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.
+2
View File
@@ -48,6 +48,8 @@
#define MOB_EPIC (1 << 7) // Megafauna
#define MOB_REPTILE (1 << 8)
#define MOB_SPIRIT (1 << 9)
/// Mobs that otherwise support nanites
#define MOB_NANITES (1 << 10)
// Organ defines for carbon mobs
#define ORGAN_ORGANIC 1
+112 -14
View File
@@ -17,6 +17,44 @@
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
/// 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.25
/// 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.15
/// 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)
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
return COMPONENT_INCOMPATIBLE
@@ -55,6 +93,9 @@
RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program)
RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan)
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))
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
@@ -118,13 +159,60 @@
next_sync = world.time + NANITE_SYNC_DELAY
set_nanite_bar()
/**
* Called when nanites are depleted.
* Deletes ourselves by default.
*/
/datum/component/nanites/proc/nanites_depleted()
if(qdel_self_on_depletion)
delete_nantes()
/**
* Used to rid ourselves
*/
/datum/component/nanites/proc/delete_nanites()
qdel(src)
if(can_be_deleted)
qdel(src)
/**
* Adds permanent programs
*/
/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/i in programs)
if(P.collision_check(i))
qdel(i)
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_LOCK_CHECK)
//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)
var/list/programs_to_remove = programs.Copy()
var/list/programs_to_remove = programs.Copy() - permanent_programs
var/list/programs_to_add = source.programs.Copy()
for(var/X in programs)
var/datum/nanite_program/NP = X
@@ -151,7 +239,7 @@
sync(null, cloud_copy)
return
//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)
NP.software_error()
@@ -159,8 +247,11 @@
for(var/X in programs)
var/datum/nanite_program/NP = X
if(NP.unique && NP.type == new_program.type)
qdel(NP)
if(programs.len >= max_programs)
if(NP in permanent_programs)
return COMPONENT_PROGRAM_NOT_INSTALLED
else
qdel(NP)
if((programs.len - length(permanent_programs)) >= max_programs)
return COMPONENT_PROGRAM_NOT_INSTALLED
if(source_program)
source_program.copy_programming(new_program)
@@ -177,7 +268,7 @@
/datum/component/nanites/proc/adjust_nanites(datum/source, amount)
nanite_volume = clamp(nanite_volume + amount, 0, max_nanites)
if(nanite_volume <= 0) //oops we ran out
qdel(src)
nanites_depleted()
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
@@ -191,28 +282,28 @@
holder.icon_state = "nanites[nanite_percent]"
/datum/component/nanites/proc/on_emp(datum/source, severity)
nanite_volume *= (rand(60, 90) * 0.01) //Lose 10-40% of nanites
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
if(prob(40/severity))
severity *= emp_severity_mod
var/loss = (severity / 100) * (rand(emp_percent_deletion_lower, emp_percent_deletion_upper) * nanite_volume) + rand(emp_flat_deletion_lower, emp_flat_deletion_upper)
adjust_nanites(null, -loss)
if(prob(severity / emp_desync_mod))
cloud_id = 0
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_emp(severity)
/datum/component/nanites/proc/on_shock(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
if(shock_damage < 1)
return
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
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
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, -loss)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_shock(shock_damage)
/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(miner_shock_deletion_lower, miner_shock_deletion_uppper))) //Lose 5-15 flat nanite volume
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_minor_shock()
@@ -237,7 +328,7 @@
NP.receive_comm_signal(comm_code, comm_message, comm_source)
/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
/datum/component/nanites/proc/check_access(datum/source, obj/O)
@@ -378,3 +469,10 @@
id++
mob_programs += list(mob_program)
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
@@ -54,6 +54,13 @@
//Rules that automatically manage if the program's active without requiring separate sensor programs
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()
. = ..()
register_extra_settings()
@@ -68,8 +75,15 @@
on_mob_remove()
if(nanites)
nanites.programs -= src
nanites.permanent_programs -= src
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()
var/datum/nanite_program/new_program = new type()
copy_programming(new_program, TRUE)
@@ -77,6 +91,8 @@
return new_program
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
if(target.immutable)
return
if(copy_activated)
target.activated = activated
target.timer_restart = timer_restart
@@ -234,7 +250,7 @@
/datum/nanite_program/proc/on_emp(severity)
if(program_flags & NANITE_EMP_IMMUNE)
return
if(prob(80 / severity))
if(prob(severity / 2))
software_error()
/datum/nanite_program/proc/on_shock(shock_damage)
@@ -242,7 +258,7 @@
if(prob(10))
software_error()
else if(prob(33))
qdel(src)
self_destruct()
/datum/nanite_program/proc/on_minor_shock()
if(!program_flags & NANITE_SHOCK_IMMUNE)
@@ -254,26 +270,29 @@
/datum/nanite_program/proc/software_error(type)
if(!type)
type = rand(1,5)
type = rand(1,is_permanent()? 4 : 5)
switch(type)
if(1)
qdel(src) //kill switch
self_destruct() //kill switch
return
if(2) //deprogram codes
activation_code = 0
deactivation_code = 0
kill_code = 0
trigger_code = 0
if(corruptable)
activation_code = 0
deactivation_code = 0
kill_code = 0
trigger_code = 0
if(3)
toggle() //enable/disable
if(error_flicking)
toggle() //enable/disable
if(4)
if(can_trigger)
if(error_flicking && can_trigger)
trigger()
if(5) //Program is scrambled and does something different
var/rogue_type = pick(rogue_types)
var/datum/nanite_program/rogue = new rogue_type
nanites.add_program(null, rogue, src)
qdel(src)
if(corruptable)
var/rogue_type = pick(rogue_types)
var/datum/nanite_program/rogue = new rogue_type
nanites.add_program(null, rogue, src)
self_destruct()
/datum/nanite_program/proc/receive_signal(code, source)
if(activation_code && code == activation_code && !activated)
@@ -285,10 +304,18 @@
if(can_trigger && trigger_code && code == trigger_code)
trigger()
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)
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.
//Moved to being 'normally' researched due to lack of B.E.P.I.S.
/datum/nanite_program/protocol