Adds the nanite remote for some programs

Adds a new remote function from tg
This commit is contained in:
keronshb
2020-01-06 15:17:26 -05:00
parent d204c0044c
commit 35cd77d433
11 changed files with 1712 additions and 1490 deletions

View File

@@ -300,6 +300,7 @@
#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" //(amount) Sets safety threshold to the given amount
#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" //(amount) Sets regeneration rate to the given amount
#define COMSIG_NANITE_SIGNAL "nanite_signal" //(code(1-9999)) Called when sending a nanite signal to a mob.
#define COMSIG_NANITE_COMM_SIGNAL "nanite_comm_signal" //(comm_code(1-9999), comm_message) Called when sending a nanite comm signal to a mob.
#define COMSIG_NANITE_SCAN "nanite_scan" //(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
#define COMSIG_NANITE_UI_DATA "nanite_ui_data" //(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" //(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component

View File

@@ -1,307 +1,315 @@
/datum/component/nanites
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/mob/living/host_mob
var/nanite_volume = 50 //amount of nanites in the system, used as fuel for nanite programs
var/max_nanites = 250 //maximum amount of nanites in the system
var/regen_rate = 0.5 //nanites generated per second
var/safety_threshold = 25 //how low nanites will get before they stop processing/triggering
var/cloud_id = 0 //0 if not connected to the cloud, 1-100 to set a determined cloud backup to draw from
var/next_sync = 0
var/list/datum/nanite_program/programs = list()
var/max_programs = NANITE_PROGRAM_LIMIT
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
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
return COMPONENT_INCOMPATIBLE
nanite_volume = amount
cloud_id = cloud
//Nanites without hosts are non-interactive through normal means
if(isliving(parent))
host_mob = parent
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes)) //Shouldn't happen, but this avoids HUD runtimes in case a silicon gets them somehow.
return COMPONENT_INCOMPATIBLE
host_mob.hud_set_nanite_indicator()
START_PROCESSING(SSnanites, src)
if(cloud_id)
cloud_sync()
/datum/component/nanites/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
RegisterSignal(parent, COMSIG_NANITE_ADJUST_VOLUME, .proc/adjust_nanites)
RegisterSignal(parent, COMSIG_NANITE_SET_MAX_VOLUME, .proc/set_max_volume)
RegisterSignal(parent, COMSIG_NANITE_SET_CLOUD, .proc/set_cloud)
RegisterSignal(parent, COMSIG_NANITE_SET_SAFETY, .proc/set_safety)
RegisterSignal(parent, COMSIG_NANITE_SET_REGEN, .proc/set_regen)
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_ATOM_EMP_ACT, .proc/on_emp)
if(isliving(parent))
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/on_death)
RegisterSignal(parent, COMSIG_MOB_ALLOWED, .proc/check_access)
RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_shock)
RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, .proc/on_minor_shock)
RegisterSignal(parent, COMSIG_SPECIES_GAIN, .proc/check_viable_biotype)
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
/datum/component/nanites/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
COMSIG_NANITE_UI_DATA,
COMSIG_NANITE_GET_PROGRAMS,
COMSIG_NANITE_SET_VOLUME,
COMSIG_NANITE_ADJUST_VOLUME,
COMSIG_NANITE_SET_MAX_VOLUME,
COMSIG_NANITE_SET_CLOUD,
COMSIG_NANITE_SET_SAFETY,
COMSIG_NANITE_SET_REGEN,
COMSIG_NANITE_ADD_PROGRAM,
COMSIG_NANITE_SCAN,
COMSIG_NANITE_SYNC,
COMSIG_ATOM_EMP_ACT,
COMSIG_MOB_DEATH,
COMSIG_MOB_ALLOWED,
COMSIG_LIVING_ELECTROCUTE_ACT,
COMSIG_LIVING_MINOR_SHOCK,
COMSIG_MOVABLE_HEAR,
COMSIG_SPECIES_GAIN,
COMSIG_NANITE_SIGNAL))
/datum/component/nanites/Destroy()
STOP_PROCESSING(SSnanites, src)
set_nanite_bar(TRUE)
QDEL_LIST(programs)
if(host_mob)
host_mob.hud_set_nanite_indicator()
host_mob = null
return ..()
/datum/component/nanites/InheritComponent(datum/component/nanites/new_nanites, i_am_original, list/arguments)
if(new_nanites)
adjust_nanites(null, new_nanites.nanite_volume)
else
adjust_nanites(null, arguments[1]) //just add to the nanite volume
/datum/component/nanites/process()
adjust_nanites(null, regen_rate)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_process()
set_nanite_bar()
if(cloud_id && world.time > next_sync)
cloud_sync()
next_sync = world.time + NANITE_SYNC_DELAY
//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_add = source.programs.Copy()
for(var/X in programs)
var/datum/nanite_program/NP = X
for(var/Y in programs_to_add)
var/datum/nanite_program/SNP = Y
if(NP.type == SNP.type)
programs_to_remove -= NP
programs_to_add -= SNP
SNP.copy_programming(NP, copy_activation)
break
if(full_overwrite)
for(var/X in programs_to_remove)
qdel(X)
for(var/X in programs_to_add)
var/datum/nanite_program/SNP = X
add_program(null, SNP.copy())
/datum/component/nanites/proc/cloud_sync()
if(!cloud_id)
return
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
if(backup)
var/datum/component/nanites/cloud_copy = backup.nanites
if(cloud_copy)
sync(null, cloud_copy)
/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program)
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)
return COMPONENT_PROGRAM_NOT_INSTALLED
if(source_program)
source_program.copy_programming(new_program)
programs += new_program
new_program.on_add(src)
return COMPONENT_PROGRAM_INSTALLED
/datum/component/nanites/proc/consume_nanites(amount, force = FALSE)
if(!force && safety_threshold && (nanite_volume - amount < safety_threshold))
return FALSE
adjust_nanites(null, -amount)
return (nanite_volume > 0)
/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)
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
var/icon/I = icon(host_mob.icon, host_mob.icon_state, host_mob.dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = null
if(remove || stealth)
return //bye icon
var/nanite_percent = (nanite_volume / max_nanites) * 100
nanite_percent = CLAMP(CEILING(nanite_percent, 10), 10, 100)
holder.icon_state = "nanites[nanite_percent]"
/datum/component/nanites/proc/on_emp(datum/source, severity)
adjust_nanites(null, -(nanite_volume * 0.3 + 50)) //Lose 30% variable and 50 flat nanite volume.
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)
adjust_nanites(null, -(nanite_volume * (shock_damage * 0.005) + shock_damage)) //0.5% of shock damage (@ 50 damage it'd drain 25%) + shock damage flat volume
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, -25)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_minor_shock()
/datum/component/nanites/proc/on_death(datum/source, gibbed)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_death(gibbed)
/datum/component/nanites/proc/receive_signal(datum/source, code, source = "an unidentified source")
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.receive_signal(code, source)
/datum/component/nanites/proc/check_viable_biotype()
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes))
qdel(src) //bodytype no longer sustains nanites
/datum/component/nanites/proc/check_access(datum/source, obj/O)
for(var/datum/nanite_program/triggered/access/access_program in programs)
if(access_program.activated)
return O.check_access_list(access_program.access)
else
return FALSE
return FALSE
/datum/component/nanites/proc/set_volume(datum/source, amount)
nanite_volume = CLAMP(amount, 0, max_nanites)
/datum/component/nanites/proc/set_max_volume(datum/source, amount)
max_nanites = max(1, max_nanites)
/datum/component/nanites/proc/set_cloud(datum/source, amount)
cloud_id = CLAMP(amount, 0, 100)
/datum/component/nanites/proc/set_safety(datum/source, amount)
safety_threshold = CLAMP(amount, 0, max_nanites)
/datum/component/nanites/proc/set_regen(datum/source, amount)
regen_rate = amount
/datum/component/nanites/proc/confirm_nanites()
return TRUE //yup i exist
/datum/component/nanites/proc/get_data(list/nanite_data)
nanite_data["nanite_volume"] = nanite_volume
nanite_data["max_nanites"] = max_nanites
nanite_data["cloud_id"] = cloud_id
nanite_data["regen_rate"] = regen_rate
nanite_data["safety_threshold"] = safety_threshold
nanite_data["stealth"] = stealth
/datum/component/nanites/proc/get_programs(datum/source, list/nanite_programs)
nanite_programs |= programs
/datum/component/nanites/proc/nanite_scan(datum/source, mob/user, full_scan)
if(!full_scan)
if(!stealth)
to_chat(user, "<span class='notice'><b>Nanites Detected</b></span>")
to_chat(user, "<span class='notice'>Saturation: [nanite_volume]/[max_nanites]</span>")
return TRUE
else
to_chat(user, "<span class='info'>NANITES DETECTED</span>")
to_chat(user, "<span class='info'>================</span>")
to_chat(user, "<span class='info'>Saturation: [nanite_volume]/[max_nanites]</span>")
to_chat(user, "<span class='info'>Safety Threshold: [safety_threshold]</span>")
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
to_chat(user, "<span class='info'>================</span>")
to_chat(user, "<span class='info'>Program List:</span>")
if(!diagnostics)
to_chat(user, "<span class='alert'>Diagnostics Disabled</span>")
else
for(var/X in programs)
var/datum/nanite_program/NP = X
to_chat(user, "<span class='info'><b>[NP.name]</b> | [NP.activated ? "Active" : "Inactive"]</span>")
return TRUE
/datum/component/nanites/proc/nanite_ui_data(datum/source, list/data, scan_level)
data["has_nanites"] = TRUE
data["nanite_volume"] = nanite_volume
data["regen_rate"] = regen_rate
data["safety_threshold"] = safety_threshold
data["cloud_id"] = cloud_id
var/list/mob_programs = list()
var/id = 1
for(var/X in programs)
var/datum/nanite_program/P = X
var/list/mob_program = list()
mob_program["name"] = P.name
mob_program["desc"] = P.desc
mob_program["id"] = id
if(scan_level >= 2)
mob_program["activated"] = P.activated
mob_program["use_rate"] = P.use_rate
mob_program["can_trigger"] = P.can_trigger
mob_program["trigger_cost"] = P.trigger_cost
mob_program["trigger_cooldown"] = P.trigger_cooldown / 10
if(scan_level >= 3)
mob_program["activation_delay"] = P.activation_delay
mob_program["timer"] = P.timer
mob_program["timer_type"] = P.get_timer_type_text()
var/list/extra_settings = list()
for(var/Y in P.extra_settings)
var/list/setting = list()
setting["name"] = Y
setting["value"] = P.get_extra_setting(Y)
extra_settings += list(setting)
mob_program["extra_settings"] = extra_settings
if(LAZYLEN(extra_settings))
mob_program["has_extra_settings"] = TRUE
if(scan_level >= 4)
mob_program["activation_code"] = P.activation_code
mob_program["deactivation_code"] = P.deactivation_code
mob_program["kill_code"] = P.kill_code
mob_program["trigger_code"] = P.trigger_code
id++
mob_programs += list(mob_program)
data["mob_programs"] = mob_programs
/datum/component/nanites
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/mob/living/host_mob
var/nanite_volume = 50 //amount of nanites in the system, used as fuel for nanite programs
var/max_nanites = 250 //maximum amount of nanites in the system
var/regen_rate = 0.5 //nanites generated per second
var/safety_threshold = 25 //how low nanites will get before they stop processing/triggering
var/cloud_id = 0 //0 if not connected to the cloud, 1-100 to set a determined cloud backup to draw from
var/next_sync = 0
var/list/datum/nanite_program/programs = list()
var/max_programs = NANITE_PROGRAM_LIMIT
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
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
return COMPONENT_INCOMPATIBLE
nanite_volume = amount
cloud_id = cloud
//Nanites without hosts are non-interactive through normal means
if(isliving(parent))
host_mob = parent
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes)) //Shouldn't happen, but this avoids HUD runtimes in case a silicon gets them somehow.
return COMPONENT_INCOMPATIBLE
host_mob.hud_set_nanite_indicator()
START_PROCESSING(SSnanites, src)
if(cloud_id)
cloud_sync()
/datum/component/nanites/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
RegisterSignal(parent, COMSIG_NANITE_ADJUST_VOLUME, .proc/adjust_nanites)
RegisterSignal(parent, COMSIG_NANITE_SET_MAX_VOLUME, .proc/set_max_volume)
RegisterSignal(parent, COMSIG_NANITE_SET_CLOUD, .proc/set_cloud)
RegisterSignal(parent, COMSIG_NANITE_SET_SAFETY, .proc/set_safety)
RegisterSignal(parent, COMSIG_NANITE_SET_REGEN, .proc/set_regen)
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_ATOM_EMP_ACT, .proc/on_emp)
if(isliving(parent))
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/on_death)
RegisterSignal(parent, COMSIG_MOB_ALLOWED, .proc/check_access)
RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_shock)
RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, .proc/on_minor_shock)
RegisterSignal(parent, COMSIG_SPECIES_GAIN, .proc/check_viable_biotype)
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
RegisterSignal(parent, COMSIG_NANITE_COMM_SIGNAL, .proc/receive_comm_signal)
/datum/component/nanites/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
COMSIG_NANITE_UI_DATA,
COMSIG_NANITE_GET_PROGRAMS,
COMSIG_NANITE_SET_VOLUME,
COMSIG_NANITE_ADJUST_VOLUME,
COMSIG_NANITE_SET_MAX_VOLUME,
COMSIG_NANITE_SET_CLOUD,
COMSIG_NANITE_SET_SAFETY,
COMSIG_NANITE_SET_REGEN,
COMSIG_NANITE_ADD_PROGRAM,
COMSIG_NANITE_SCAN,
COMSIG_NANITE_SYNC,
COMSIG_ATOM_EMP_ACT,
COMSIG_MOB_DEATH,
COMSIG_MOB_ALLOWED,
COMSIG_LIVING_ELECTROCUTE_ACT,
COMSIG_LIVING_MINOR_SHOCK,
COMSIG_MOVABLE_HEAR,
COMSIG_SPECIES_GAIN,
COMSIG_NANITE_SIGNAL,
COMSIG_NANITE_COMM_SIGNAL))
/datum/component/nanites/Destroy()
STOP_PROCESSING(SSnanites, src)
set_nanite_bar(TRUE)
QDEL_LIST(programs)
if(host_mob)
host_mob.hud_set_nanite_indicator()
host_mob = null
return ..()
/datum/component/nanites/InheritComponent(datum/component/nanites/new_nanites, i_am_original, list/arguments)
if(new_nanites)
adjust_nanites(null, new_nanites.nanite_volume)
else
adjust_nanites(null, arguments[1]) //just add to the nanite volume
/datum/component/nanites/process()
adjust_nanites(null, regen_rate)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_process()
set_nanite_bar()
if(cloud_id && world.time > next_sync)
cloud_sync()
next_sync = world.time + NANITE_SYNC_DELAY
//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_add = source.programs.Copy()
for(var/X in programs)
var/datum/nanite_program/NP = X
for(var/Y in programs_to_add)
var/datum/nanite_program/SNP = Y
if(NP.type == SNP.type)
programs_to_remove -= NP
programs_to_add -= SNP
SNP.copy_programming(NP, copy_activation)
break
if(full_overwrite)
for(var/X in programs_to_remove)
qdel(X)
for(var/X in programs_to_add)
var/datum/nanite_program/SNP = X
add_program(null, SNP.copy())
/datum/component/nanites/proc/cloud_sync()
if(!cloud_id)
return
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
if(backup)
var/datum/component/nanites/cloud_copy = backup.nanites
if(cloud_copy)
sync(null, cloud_copy)
/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program)
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)
return COMPONENT_PROGRAM_NOT_INSTALLED
if(source_program)
source_program.copy_programming(new_program)
programs += new_program
new_program.on_add(src)
return COMPONENT_PROGRAM_INSTALLED
/datum/component/nanites/proc/consume_nanites(amount, force = FALSE)
if(!force && safety_threshold && (nanite_volume - amount < safety_threshold))
return FALSE
adjust_nanites(null, -amount)
return (nanite_volume > 0)
/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)
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
var/icon/I = icon(host_mob.icon, host_mob.icon_state, host_mob.dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = null
if(remove || stealth)
return //bye icon
var/nanite_percent = (nanite_volume / max_nanites) * 100
nanite_percent = CLAMP(CEILING(nanite_percent, 10), 10, 100)
holder.icon_state = "nanites[nanite_percent]"
/datum/component/nanites/proc/on_emp(datum/source, severity)
adjust_nanites(null, -(nanite_volume * 0.3 + 50)) //Lose 30% variable and 50 flat nanite volume.
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)
adjust_nanites(null, -(nanite_volume * (shock_damage * 0.005) + shock_damage)) //0.5% of shock damage (@ 50 damage it'd drain 25%) + shock damage flat volume
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, -25)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_minor_shock()
/datum/component/nanites/proc/on_death(datum/source, gibbed)
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.on_death(gibbed)
/datum/component/nanites/proc/receive_signal(datum/source, code, source = "an unidentified source")
for(var/X in programs)
var/datum/nanite_program/NP = X
NP.receive_signal(code, source)
/datum/component/nanites/proc/receive_comm_signal(datum/source, comm_code, comm_message, comm_source = "an unidentified source")
for(var/X in programs)
if(istype(X, /datum/nanite_program/triggered/comm))
var/datum/nanite_program/triggered/comm/NP = X
NP.receive_comm_signal(comm_code, comm_message, comm_source)
/datum/component/nanites/proc/check_viable_biotype()
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes))
qdel(src) //bodytype no longer sustains nanites
/datum/component/nanites/proc/check_access(datum/source, obj/O)
for(var/datum/nanite_program/triggered/access/access_program in programs)
if(access_program.activated)
return O.check_access_list(access_program.access)
else
return FALSE
return FALSE
/datum/component/nanites/proc/set_volume(datum/source, amount)
nanite_volume = CLAMP(amount, 0, max_nanites)
/datum/component/nanites/proc/set_max_volume(datum/source, amount)
max_nanites = max(1, max_nanites)
/datum/component/nanites/proc/set_cloud(datum/source, amount)
cloud_id = CLAMP(amount, 0, 100)
/datum/component/nanites/proc/set_safety(datum/source, amount)
safety_threshold = CLAMP(amount, 0, max_nanites)
/datum/component/nanites/proc/set_regen(datum/source, amount)
regen_rate = amount
/datum/component/nanites/proc/confirm_nanites()
return TRUE //yup i exist
/datum/component/nanites/proc/get_data(list/nanite_data)
nanite_data["nanite_volume"] = nanite_volume
nanite_data["max_nanites"] = max_nanites
nanite_data["cloud_id"] = cloud_id
nanite_data["regen_rate"] = regen_rate
nanite_data["safety_threshold"] = safety_threshold
nanite_data["stealth"] = stealth
/datum/component/nanites/proc/get_programs(datum/source, list/nanite_programs)
nanite_programs |= programs
/datum/component/nanites/proc/nanite_scan(datum/source, mob/user, full_scan)
if(!full_scan)
if(!stealth)
to_chat(user, "<span class='notice'><b>Nanites Detected</b></span>")
to_chat(user, "<span class='notice'>Saturation: [nanite_volume]/[max_nanites]</span>")
return TRUE
else
to_chat(user, "<span class='info'>NANITES DETECTED</span>")
to_chat(user, "<span class='info'>================</span>")
to_chat(user, "<span class='info'>Saturation: [nanite_volume]/[max_nanites]</span>")
to_chat(user, "<span class='info'>Safety Threshold: [safety_threshold]</span>")
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
to_chat(user, "<span class='info'>================</span>")
to_chat(user, "<span class='info'>Program List:</span>")
if(!diagnostics)
to_chat(user, "<span class='alert'>Diagnostics Disabled</span>")
else
for(var/X in programs)
var/datum/nanite_program/NP = X
to_chat(user, "<span class='info'><b>[NP.name]</b> | [NP.activated ? "Active" : "Inactive"]</span>")
return TRUE
/datum/component/nanites/proc/nanite_ui_data(datum/source, list/data, scan_level)
data["has_nanites"] = TRUE
data["nanite_volume"] = nanite_volume
data["regen_rate"] = regen_rate
data["safety_threshold"] = safety_threshold
data["cloud_id"] = cloud_id
var/list/mob_programs = list()
var/id = 1
for(var/X in programs)
var/datum/nanite_program/P = X
var/list/mob_program = list()
mob_program["name"] = P.name
mob_program["desc"] = P.desc
mob_program["id"] = id
if(scan_level >= 2)
mob_program["activated"] = P.activated
mob_program["use_rate"] = P.use_rate
mob_program["can_trigger"] = P.can_trigger
mob_program["trigger_cost"] = P.trigger_cost
mob_program["trigger_cooldown"] = P.trigger_cooldown / 10
if(scan_level >= 3)
mob_program["activation_delay"] = P.activation_delay
mob_program["timer"] = P.timer
mob_program["timer_type"] = P.get_timer_type_text()
var/list/extra_settings = list()
for(var/Y in P.extra_settings)
var/list/setting = list()
setting["name"] = Y
setting["value"] = P.get_extra_setting(Y)
extra_settings += list(setting)
mob_program["extra_settings"] = extra_settings
if(LAZYLEN(extra_settings))
mob_program["has_extra_settings"] = TRUE
if(scan_level >= 4)
mob_program["activation_code"] = P.activation_code
mob_program["deactivation_code"] = P.deactivation_code
mob_program["kill_code"] = P.kill_code
mob_program["trigger_code"] = P.trigger_code
id++
mob_programs += list(mob_program)
data["mob_programs"] = mob_programs

View File

@@ -36,6 +36,16 @@
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/nanite_comm_remote
name = "Nanite Communication Remote"
desc = "Allows for the construction of a nanite communication remote."
id = "nanite_comm_remote"
build_type = PROTOLATHE
materials = list(MAT_GLASS = 500, MAT_METAL = 500)
build_path = /obj/item/nanite_remote/comm
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/nanite_scanner
name = "Nanite Scanner"
desc = "Allows for the construction of a nanite scanner."

View File

@@ -445,21 +445,21 @@
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
id = "voice_nanites"
program_type = /datum/nanite_program/triggered/voice
program_type = /datum/nanite_program/triggered/comm/voice
category = list("Suppression Nanites")
/datum/design/nanites/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
id = "speech_nanites"
program_type = /datum/nanite_program/triggered/speech
program_type = /datum/nanite_program/triggered/comm/speech
category = list("Suppression Nanites")
/datum/design/nanites/hallucination
name = "Hallucination"
desc = "The nanites make the host see and hear things that aren't real."
id = "hallucination_nanites"
program_type = /datum/nanite_program/triggered/hallucination
program_type = /datum/nanite_program/triggered/comm/hallucination
category = list("Suppression Nanites")
////////////////////SENSOR NANITES//////////////////////////////////////

View File

@@ -114,7 +114,19 @@
. = ..()
host_mob.cure_fakedeath("nanites")
/datum/nanite_program/triggered/speech
//Can receive transmissions from a nanite communication remote for customized messages
/datum/nanite_program/triggered/comm
var/comm_code = 0
var/comm_message = ""
/datum/nanite_program/triggered/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source)
if(!activated || !comm_code)
return
if(signal_comm_code == comm_code)
host_mob.investigate_log("'s [name] nanite program was messaged by [comm_source] with comm code [signal_comm_code] and message '[comm_message]'.", INVESTIGATE_NANITES)
trigger(comm_message)
/datum/nanite_program/triggered/comm/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
unique = FALSE
@@ -122,10 +134,10 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
extra_settings = list("Sentence")
extra_settings = list("Sentence","Comm Code")
var/sentence = ""
/datum/nanite_program/triggered/speech/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/speech/set_extra_setting(user, setting)
if(setting == "Sentence")
var/new_sentence = stripped_input(user, "Choose the sentence that the host will be forced to say.", "Sentence", sentence, MAX_MESSAGE_LEN)
if(!new_sentence)
@@ -133,23 +145,34 @@
if(copytext(new_sentence, 1, 2) == "*") //emotes are abusable, like surrender
return
sentence = new_sentence
if(setting == "Comm Code")
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
/datum/nanite_program/triggered/speech/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/speech/get_extra_setting(setting)
if(setting == "Sentence")
return sentence
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/speech/copy_extra_settings_to(datum/nanite_program/triggered/speech/target)
/datum/nanite_program/triggered/comm/speech/copy_extra_settings_to(datum/nanite_program/triggered/comm/speech/target)
target.sentence = sentence
target.comm_code = comm_code
/datum/nanite_program/triggered/speech/trigger()
/datum/nanite_program/triggered/comm/speech/trigger(comm_message)
if(!..())
return
var/sent_message = comm_message
if(!comm_message)
sent_message = sentence
if(host_mob.stat == DEAD)
return
to_chat(host_mob, "<span class='warning'>You feel compelled to speak...</span>")
host_mob.say(sentence, forced = "nanite speech")
host_mob.say(sent_message, forced = "nanite speech")
/datum/nanite_program/triggered/voice
/datum/nanite_program/triggered/comm/voice
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
unique = FALSE
@@ -157,44 +180,62 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
extra_settings = list("Message")
extra_settings = list("Message","Comm Code")
var/message = ""
/datum/nanite_program/triggered/voice/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/voice/set_extra_setting(user, setting)
if(setting == "Message")
var/new_message = stripped_input(user, "Choose the message sent to the host.", "Message", message, MAX_MESSAGE_LEN)
if(!new_message)
return
message = new_message
if(setting == "Comm Code")
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
/datum/nanite_program/triggered/voice/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/voice/get_extra_setting(setting)
if(setting == "Message")
return message
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/voice/copy_extra_settings_to(datum/nanite_program/triggered/voice/target)
/datum/nanite_program/triggered/comm/voice/copy_extra_settings_to(datum/nanite_program/triggered/comm/voice/target)
target.message = message
target.comm_code = comm_code
/datum/nanite_program/triggered/voice/trigger()
/datum/nanite_program/triggered/comm/voice/trigger(comm_message)
if(!..())
return
var/sent_message = comm_message
if(!comm_message)
sent_message = message
if(host_mob.stat == DEAD)
return
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[message]</span>\"")
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[sent_message]</span>\"")
/datum/nanite_program/triggered/hallucination
/datum/nanite_program/triggered/comm/hallucination
name = "Hallucination"
desc = "The nanites make the host hallucinate something when triggered."
trigger_cost = 4
trigger_cooldown = 80
unique = FALSE
rogue_types = list(/datum/nanite_program/brain_misfire)
extra_settings = list("Hallucination Type")
extra_settings = list("Hallucination Type", "Comm Code")
var/hal_type
var/hal_details
/datum/nanite_program/triggered/hallucination/trigger()
/datum/nanite_program/triggered/comm/hallucination/trigger(comm_message)
if(!..())
return
if(comm_message && (hal_type != "Message")) //Triggered via comm remote, but not set to a message hallucination
return
var/sent_message = comm_message //Comm remotes can send custom hallucination messages for the chat hallucination
if(!sent_message)
sent_message = hal_details
if(!iscarbon(host_mob))
return
var/mob/living/carbon/C = host_mob
@@ -203,7 +244,7 @@
else
switch(hal_type)
if("Message")
new /datum/hallucination/chat(C, TRUE, null, hal_details)
new /datum/hallucination/chat(C, TRUE, null, sent_message)
if("Battle")
new /datum/hallucination/battle(C, TRUE, hal_details)
if("Sound")
@@ -223,7 +264,13 @@
if("Plasma Flood")
new /datum/hallucination/fake_flood(C, TRUE)
/datum/nanite_program/triggered/hallucination/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/hallucination/set_extra_setting(user, setting)
if(setting == "Comm Code")
var/new_code = input(user, "(Only for Message) Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
if(setting == "Hallucination Type")
var/list/possible_hallucinations = list("Random","Message","Battle","Sound","Weird Sound","Station Message","Health","Alert","Fire","Shock","Plasma Flood")
var/hal_type_choice = input("Choose the hallucination type", name) as null|anything in possible_hallucinations
@@ -299,13 +346,16 @@
if("Plasma Flood")
hal_type = "Plasma Flood"
/datum/nanite_program/triggered/hallucination/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/hallucination/get_extra_setting(setting)
if(setting == "Hallucination Type")
if(!hal_type)
return "Random"
else
return hal_type
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/hallucination/target)
/datum/nanite_program/triggered/comm/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/comm/hallucination/target)
target.hal_type = hal_type
target.hal_details = hal_details
target.hal_details = hal_details
target.comm_code = comm_code

View File

@@ -197,6 +197,15 @@
return
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source)
/datum/nanite_program/relay/proc/relay_comm_signal(comm_code, relay_code, comm_message)
if(!activated)
return
if(!host_mob)
return
if(relay_code != relay_channel)
return
SEND_SIGNAL(host_mob, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
/datum/nanite_program/metabolic_synthesis
name = "Metabolic Synthesis"
desc = "The nanites use the metabolic cycle of the host to speed up their replication rate, using their extra nutrition as fuel."

View File

@@ -168,6 +168,109 @@
. = TRUE
/obj/item/nanite_remote/comm
name = "nanite communication remote"
desc = "A device that can send text messages to specific programs."
icon_state = "nanite_comm_remote"
var/comm_code = 0
var/comm_message = ""
/obj/item/nanite_remote/comm/afterattack(atom/target, mob/user, etc)
switch(mode)
if(REMOTE_MODE_OFF)
return
if(REMOTE_MODE_SELF)
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.<span>")
signal_mob(user, comm_code, comm_message)
if(REMOTE_MODE_TARGET)
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].<span>")
signal_mob(target, code, comm_message, key_name(user))
if(REMOTE_MODE_AOE)
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.<span>")
for(var/mob/living/L in view(user, 7))
signal_mob(L, code, comm_message, key_name(user))
if(REMOTE_MODE_RELAY)
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
signal_relay(code, relay_code, comm_message, key_name(user))
/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source)
SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
/obj/item/nanite_remote/comm/signal_relay(code, relay_code, source)
for(var/X in SSnanites.nanite_relays)
var/datum/nanite_program/relay/N = X
N.relay_comm_signal(comm_code, relay_code, comm_message)
/obj/item/nanite_remote/comm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "nanite_comm_remote", name, 420, 800, master_ui, state)
ui.open()
/obj/item/nanite_remote/comm/ui_data()
var/list/data = list()
data["comm_code"] = comm_code
data["relay_code"] = relay_code
data["comm_message"] = comm_message
data["mode"] = mode
data["locked"] = locked
data["saved_settings"] = saved_settings
return data
/obj/item/nanite_remote/comm/ui_act(action, params)
if(..())
return
switch(action)
if("set_comm_code")
if(locked)
return
var/new_code = input("Set comm code (0000-9999):", name, code) as null|num
if(!isnull(new_code))
new_code = CLAMP(round(new_code, 1),0,9999)
comm_code = new_code
. = TRUE
if("set_message")
if(locked)
return
var/new_message = stripped_input(usr, "Set the message (Max 300 characters):", "Set Message", null , 300)
if(!new_message)
return
comm_message = new_message
. = TRUE
if("comm_save")
if(locked)
return
var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
if(!code_name)
return
var/new_save = list()
new_save["id"] = last_id + 1
last_id++
new_save["name"] = code_name
new_save["code"] = comm_code
new_save["mode"] = mode
new_save["relay_code"] = relay_code
new_save["message"] = comm_message
saved_settings += list(new_save)
. = TRUE
if("comm_load")
var/code_id = params["save_id"]
var/list/setting
for(var/list/X in saved_settings)
if(X["id"] == text2num(code_id))
setting = X
break
if(setting)
comm_code = setting["code"]
mode = setting["mode"]
relay_code = setting["relay_code"]
comm_message = setting["message"]
. = TRUE
#undef REMOTE_MODE_OFF
#undef REMOTE_MODE_SELF
#undef REMOTE_MODE_TARGET

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,41 @@
<ui-display title='Nanite Control'>
{{#if data.locked}}
<ui-notice>The interface is locked.</ui-notice>
{{else}}
<ui-button icon='lock' action='lock'>Lock Interface</ui-button>
<ui-button icon='save' action='comm_save'>Save Current Setting</ui-button>
<ui-section label='Comm Code'>
<span>{{data.comm_code}}</span>
<ui-button icon='pencil' action='set_comm_code'>Set</ui-button>
</ui-section>
<ui-section label='Message'>
{{data.comm_message}}
<br>
<ui-button icon='pencil' action='set_message'>Set</ui-button>
</ui-section>
{{#if data.mode == "Relay"}}
<ui-section label='Relay Code'>
<span>{{data.relay_code}}</span>
<ui-button icon='pencil' action='set_relay_code'>Set</ui-button>
</ui-section>
{{/if}}
<ui-section label='Signal Mode'>
<span>{{data.mode}}</span>
<br>
<ui-button action='select_mode' params='{"mode": "Off"}'>Off</ui-button>
<ui-button action='select_mode' params='{"mode": "Local"}'>Local</ui-button>
<ui-button action='select_mode' params='{"mode": "Targeted"}'>Targeted</ui-button>
<ui-button action='select_mode' params='{"mode": "Area"}'>Area</ui-button>
<ui-button action='select_mode' params='{"mode": "Relay"}'>Relay</ui-button>
</ui-section>
{{/if}}
</ui-display>
<ui-display title='Saved Settings'>
{{#each data.saved_settings}}
<ui-button icon='load' action='comm_load' params='{"save_id": "{{id}}"}'>{{name}}</ui-button>
{{#if !data.locked}}
<ui-button icon='remove' action='remove_save' params='{"save_id": "{{id}}"}'>Remove</ui-button>
{{/if}}
<br>
{{/each}}
</ui-display>