mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 09:54:52 +00:00
Merge pull request #13699 from silicons/nanite_updates
nanite updates: permanent nanites, hostile lockdown, anti-virus, resistance tweaking
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user