mirror of
https://github.com/KabKebab/GS13.git
synced 2026-02-09 15:17:41 +00:00
Merge pull request #1230 from ArchieBeepBoop/nanites
[Ready] Nanite Updates + Nanite TGUI Next
This commit is contained in:
@@ -1,11 +1,44 @@
|
||||
#define NANITE_TIMER_DEACTIVATE 1
|
||||
#define NANITE_TIMER_SELFDELETE 2
|
||||
#define NANITE_TIMER_TRIGGER 3
|
||||
#define NANITE_TIMER_RESET 4
|
||||
|
||||
#define NANITE_SYNC_DELAY 300
|
||||
|
||||
#define NANITE_SHOCK_IMMUNE 1
|
||||
#define NANITE_EMP_IMMUNE 2
|
||||
|
||||
#define NANITE_PROGRAM_LIMIT 20
|
||||
#define NANITE_PROGRAM_LIMIT 20
|
||||
|
||||
|
||||
#define NANITE_BASE_RESEARCH 3.5
|
||||
|
||||
#define NANITE_CLOUD_TOGGLE 1
|
||||
#define NANITE_CLOUD_DISABLE 2
|
||||
#define NANITE_CLOUD_ENABLE 3
|
||||
|
||||
///Nanite extra settings types: used to help uis know what type an extra setting is
|
||||
#define NESTYPE_TEXT "text"
|
||||
#define NESTYPE_NUMBER "number"
|
||||
#define NESTYPE_TYPE "type"
|
||||
#define NESTYPE_BOOLEAN "boolean"
|
||||
|
||||
///Nanite Extra Settings - Note that these will also be the names displayed in the UI
|
||||
#define NES_SENT_CODE "Sent Code"
|
||||
#define NES_DELAY "Delay"
|
||||
#define NES_MODE "Mode"
|
||||
#define NES_COMM_CODE "Comm Code"
|
||||
#define NES_RELAY_CHANNEL "Relay Channel"
|
||||
#define NES_HEALTH_PERCENT "Health Percent"
|
||||
#define NES_DIRECTION "Direction"
|
||||
#define NES_NANITE_PERCENT "Nanite Percent"
|
||||
#define NES_DAMAGE_TYPE "Damage Type"
|
||||
#define NES_DAMAGE "Damage"
|
||||
#define NES_SENTENCE "Sentence"
|
||||
#define NES_MESSAGE "Message"
|
||||
#define NES_DIRECTIVE "Directive"
|
||||
#define NES_INCLUSIVE_MODE "Inclusive Mode"
|
||||
#define NES_HALLUCINATION_TYPE "Hallucination Type"
|
||||
#define NES_HALLUCINATION_DETAIL "Hallucination Detail"
|
||||
#define NES_MOOD_MESSAGE "Mood Message"
|
||||
#define NES_PROGRAM_OVERWRITE "Program Overwrite"
|
||||
#define NES_CLOUD_OVERWRITE "Cloud Overwrite"
|
||||
#define NES_SCAN_TYPE "Scan Type"
|
||||
#define NES_BUTTON_NAME "Button Name"
|
||||
#define NES_ICON "Icon"
|
||||
#define NES_COLOR "Color"
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
} while (0)
|
||||
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
|
||||
|
||||
//mob traits
|
||||
#define TRAIT_BLIND "blind"
|
||||
|
||||
@@ -6,6 +6,7 @@ PROCESSING_SUBSYSTEM_DEF(nanites)
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/list/mob/living/nanite_monitored_mobs = list()
|
||||
var/list/datum/nanite_program/relay/nanite_relays = list()
|
||||
var/neural_network_count = 0
|
||||
|
||||
/datum/controller/subsystem/processing/nanites/proc/check_hardware(datum/nanite_cloud_backup/backup)
|
||||
if(QDELETED(backup.storage) || (backup.storage.stat & (NOPOWER|BROKEN)))
|
||||
|
||||
@@ -127,10 +127,6 @@
|
||||
for(var/datum/reagent/A in RC.reagents.reagent_list)
|
||||
.["other"][A.type] += A.volume
|
||||
.["other"][I.type] += 1
|
||||
if(istype(I, /obj/item/reagent_containers/food/snacks/grown) && !.["color"]) //First we find has priority
|
||||
var/obj/item/reagent_containers/food/snacks/grown/G = I
|
||||
if(G.modified_colors)
|
||||
.["color"] = G.color
|
||||
|
||||
/datum/component/personal_crafting/proc/check_tools(mob/user, datum/crafting_recipe/R, list/contents)
|
||||
if(!R.tools.len)
|
||||
@@ -166,9 +162,6 @@
|
||||
/datum/component/personal_crafting/proc/construct_item(mob/user, datum/crafting_recipe/R)
|
||||
var/list/contents = get_surroundings(user)
|
||||
var/send_feedback = 1
|
||||
var/cached_color = null //Do not remove this.
|
||||
if(contents["color"]) //From plants
|
||||
cached_color = contents["color"]
|
||||
if(check_contents(R, contents))
|
||||
if(check_tools(user, R, contents))
|
||||
if(do_after(user, R.time, target = user))
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
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/cloud_active = TRUE //if false, won't sync to the cloud
|
||||
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, and does not display the program list on nanite scans
|
||||
var/list/datum/nanite_program/protocol/protocols = list() ///Separate list of protocol programs, to avoid looping through the whole programs list when cheking for conflicts
|
||||
var/start_time = 0 ///Timestamp to when the nanites were first inserted in the host
|
||||
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))
|
||||
@@ -27,43 +31,52 @@
|
||||
if((MOB_SILICON & host_mob.mob_biotypes)) //Shouldn't happen, but this avoids HUD runtimes in case a silicon gets them somehow.
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
start_time = world.time
|
||||
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
START_PROCESSING(SSnanites, src)
|
||||
|
||||
if(cloud_id)
|
||||
if(cloud_id && cloud_active)
|
||||
cloud_sync()
|
||||
|
||||
/datum/component/nanites/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_IS_STEALTHY, .proc/check_stealth)
|
||||
RegisterSignal(parent, COMSIG_NANITE_DELETE, .proc/delete_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_CLOUD_SYNC, .proc/set_cloud_sync)
|
||||
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_ATOM_EMP_ACT, .proc/on_emp)
|
||||
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_IS_STEALTHY,
|
||||
COMSIG_NANITE_DELETE,
|
||||
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_CLOUD_SYNC,
|
||||
COMSIG_NANITE_SET_SAFETY,
|
||||
COMSIG_NANITE_SET_REGEN,
|
||||
COMSIG_NANITE_ADD_PROGRAM,
|
||||
@@ -76,13 +89,14 @@
|
||||
COMSIG_LIVING_MINOR_SHOCK,
|
||||
COMSIG_MOVABLE_HEAR,
|
||||
COMSIG_SPECIES_GAIN,
|
||||
COMSIG_NANITE_SIGNAL))
|
||||
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)
|
||||
set_nanite_bar(TRUE)
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
host_mob = null
|
||||
return ..()
|
||||
@@ -95,13 +109,18 @@
|
||||
|
||||
/datum/component/nanites/process()
|
||||
adjust_nanites(null, regen_rate)
|
||||
add_research()
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_process()
|
||||
set_nanite_bar()
|
||||
if(cloud_id && world.time > next_sync)
|
||||
if(cloud_id && cloud_active && world.time > next_sync)
|
||||
cloud_sync()
|
||||
next_sync = world.time + NANITE_SYNC_DELAY
|
||||
set_nanite_bar()
|
||||
|
||||
|
||||
/datum/component/nanites/proc/delete_nanites()
|
||||
qdel(src)
|
||||
|
||||
//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)
|
||||
@@ -124,13 +143,17 @@
|
||||
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)
|
||||
if(cloud_id)
|
||||
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)
|
||||
return
|
||||
//Without cloud syncing nanites can accumulate errors and/or defects
|
||||
if(prob(8) && programs.len)
|
||||
var/datum/nanite_program/NP = pick(programs)
|
||||
NP.software_error()
|
||||
|
||||
/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program)
|
||||
for(var/X in programs)
|
||||
@@ -168,23 +191,35 @@
|
||||
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.
|
||||
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))
|
||||
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)
|
||||
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_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
|
||||
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)
|
||||
adjust_nanites(null, -(rand(5, 15))) //Lose 5-15 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_minor_shock()
|
||||
|
||||
/datum/component/nanites/proc/check_stealth(datum/source)
|
||||
return stealth
|
||||
|
||||
/datum/component/nanites/proc/on_death(datum/source, gibbed)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
@@ -195,12 +230,18 @@
|
||||
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/comm))
|
||||
var/datum/nanite_program/comm/NP = X
|
||||
NP.receive_comm_signal(comm_code, comm_message, comm_source)
|
||||
|
||||
/datum/component/nanites/proc/check_viable_biotype()
|
||||
if((MOB_SILICON & 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)
|
||||
for(var/datum/nanite_program/access/access_program in programs)
|
||||
if(access_program.activated)
|
||||
return O.check_access_list(access_program.access)
|
||||
else
|
||||
@@ -216,6 +257,15 @@
|
||||
/datum/component/nanites/proc/set_cloud(datum/source, amount)
|
||||
cloud_id = CLAMP(amount, 0, 100)
|
||||
|
||||
/datum/component/nanites/proc/set_cloud_sync(datum/source, method)
|
||||
switch(method)
|
||||
if(NANITE_CLOUD_TOGGLE)
|
||||
cloud_active = !cloud_active
|
||||
if(NANITE_CLOUD_DISABLE)
|
||||
cloud_active = FALSE
|
||||
if(NANITE_CLOUD_ENABLE)
|
||||
cloud_active = TRUE
|
||||
|
||||
/datum/component/nanites/proc/set_safety(datum/source, amount)
|
||||
safety_threshold = CLAMP(amount, 0, max_nanites)
|
||||
|
||||
@@ -236,6 +286,19 @@
|
||||
/datum/component/nanites/proc/get_programs(datum/source, list/nanite_programs)
|
||||
nanite_programs |= programs
|
||||
|
||||
/datum/component/nanites/proc/add_research()
|
||||
var/research_value = NANITE_BASE_RESEARCH
|
||||
if(!ishuman(host_mob))
|
||||
if(!iscarbon(host_mob))
|
||||
research_value *= 0.4
|
||||
else
|
||||
research_value *= 0.8
|
||||
if(!host_mob.client)
|
||||
research_value *= 0.5
|
||||
if(host_mob.stat == DEAD)
|
||||
research_value *= 0.75
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_NANITES = research_value))
|
||||
|
||||
/datum/component/nanites/proc/nanite_scan(datum/source, mob/user, full_scan)
|
||||
if(!full_scan)
|
||||
if(!stealth)
|
||||
@@ -247,11 +310,12 @@
|
||||
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'>Cloud ID: [cloud_id ? cloud_id : "None"]</span>")
|
||||
to_chat(user, "<span class='info'>Cloud Sync: [cloud_active ? "Active" : "Disabled"]</span>")
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Program List:</span>")
|
||||
if(stealth)
|
||||
to_chat(user, "<span class='alert'>%#$ENCRYPTED&^@</span>")
|
||||
if(!diagnostics)
|
||||
to_chat(user, "<span class='alert'>Diagnostics Disabled</span>")
|
||||
else
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
@@ -264,6 +328,7 @@
|
||||
data["regen_rate"] = regen_rate
|
||||
data["safety_threshold"] = safety_threshold
|
||||
data["cloud_id"] = cloud_id
|
||||
data["cloud_active"] = cloud_active
|
||||
var/list/mob_programs = list()
|
||||
var/id = 1
|
||||
for(var/X in programs)
|
||||
@@ -281,24 +346,35 @@
|
||||
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["timer_restart"] = P.timer_restart / 10
|
||||
mob_program["timer_shutdown"] = P.timer_shutdown / 10
|
||||
mob_program["timer_trigger"] = P.timer_trigger / 10
|
||||
mob_program["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
mob_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
mob_program["has_extra_settings"] = TRUE
|
||||
else
|
||||
mob_program["has_extra_settings"] = FALSE
|
||||
|
||||
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
|
||||
var/list/rules = list()
|
||||
var/rule_id = 1
|
||||
for(var/Z in P.rules)
|
||||
var/datum/nanite_rule/nanite_rule = Z
|
||||
var/list/rule = list()
|
||||
rule["display"] = nanite_rule.display()
|
||||
rule["program_id"] = id
|
||||
rule["id"] = rule_id
|
||||
rules += list(rule)
|
||||
rule_id++
|
||||
mob_program["rules"] = rules
|
||||
if(LAZYLEN(rules))
|
||||
mob_program["has_rules"] = TRUE
|
||||
id++
|
||||
mob_programs += list(mob_program)
|
||||
data["mob_programs"] = mob_programs
|
||||
|
||||
@@ -217,7 +217,14 @@
|
||||
mood_change = -3
|
||||
timeout = 10 MINUTES
|
||||
|
||||
/datum/mood_event/nanite_sadness
|
||||
description = "<span class='warning robot'>+++++++HAPPINESS SUPPRESSION+++++++</span>\n"
|
||||
mood_change = -7
|
||||
/datum/mood_event/daylight_2
|
||||
description = "<span class='boldwarning'>I have been scorched by the unforgiving rays of the sun.</span>\n"
|
||||
mood_change = -6
|
||||
timeout = 15 MINUTES
|
||||
|
||||
/datum/mood_event/nanite_sadness/add_effects(message)
|
||||
description = "<span class='warning robot'>+++++++[message]+++++++</span>\n"
|
||||
|
||||
|
||||
@@ -131,6 +131,17 @@
|
||||
description = "<span class='nicegreen'>Whatever I ate was a-<i>nya</i>-zing!</span>\n"
|
||||
mood_change = 8 //Felinids become pacified from catnip, so give a bigger mood boost
|
||||
|
||||
/datum/mood_event/nanite_happiness
|
||||
description = "<span class='nicegreen robot'>+++++++HAPPINESS ENHANCEMENT+++++++</span>\n"
|
||||
mood_change = 7
|
||||
|
||||
/datum/mood_event/nanite_happiness/add_effects(message)
|
||||
description = "<span class='nicegreen robot'>+++++++[message]+++++++</span>\n"
|
||||
|
||||
/datum/mood_event/area
|
||||
description = "" //Fill this out in the area
|
||||
mood_change = 0
|
||||
|
||||
//Bloodsucker stuff below.
|
||||
/datum/mood_event/drankblood
|
||||
description = "<span class='nicegreen'>I have fed greedly from that which nourishes me.</span>\n"
|
||||
|
||||
@@ -431,26 +431,11 @@
|
||||
if((!req_defib && grab_ghost) || (req_defib && defib.grab_ghost))
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated!")
|
||||
H.grab_ghost() // Shove them back in their body.
|
||||
else if(can_defib(H))
|
||||
else if(H.can_defib())
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src)
|
||||
|
||||
do_help(H, user)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) //Our code here is different than tg, if it breaks in testing; BUG_PROBABLE_CAUSE
|
||||
var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart)
|
||||
if(H.suiciding || H.hellbound || HAS_TRAIT(H, TRAIT_HUSK))
|
||||
return
|
||||
if((world.time - H.timeofdeath) > tlimit)
|
||||
return
|
||||
if((H.getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (H.getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
|
||||
return
|
||||
if(!heart || (heart.organ_flags & ORGAN_FAILING))
|
||||
return
|
||||
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || H.suiciding)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
|
||||
if(req_defib)
|
||||
if(defib.pullshocksafely && isliving(H.pulledby))
|
||||
|
||||
@@ -845,6 +845,22 @@
|
||||
update_inv_handcuffed()
|
||||
update_hud_handcuffed()
|
||||
|
||||
/mob/living/carbon/proc/can_defib()
|
||||
var/tlimit = DEFIB_TIME_LIMIT * 10
|
||||
var/obj/item/organ/heart = getorgan(/obj/item/organ/heart)
|
||||
if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
return
|
||||
if((world.time - timeofdeath) > tlimit)
|
||||
return
|
||||
if((getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
|
||||
return
|
||||
if(!heart || (heart.organ_flags & ORGAN_FAILING))
|
||||
return
|
||||
var/obj/item/organ/brain/BR = getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || suiciding)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/fully_heal(admin_revive = FALSE)
|
||||
if(reagents)
|
||||
reagents.clear_reagents()
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
program_type = /datum/nanite_program/viral
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/research
|
||||
name = "Distributed Computing"
|
||||
desc = "The nanites aid the research servers by performing a portion of its calculations, increasing research point generation."
|
||||
id = "research_nanites"
|
||||
program_type = /datum/nanite_program/research
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/researchplus
|
||||
name = "Neural Network"
|
||||
desc = "The nanites link the host's brains together forming a neural research network, that becomes more efficient with the amount of total hosts. Can be overloaded to increase research output."
|
||||
id = "researchplus_nanites"
|
||||
program_type = /datum/nanite_program/researchplus
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/monitoring
|
||||
name = "Monitoring"
|
||||
desc = "The nanites monitor the host's vitals and location, sending them to the suit sensor network."
|
||||
@@ -36,7 +50,14 @@
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
id = "selfscan_nanites"
|
||||
program_type = /datum/nanite_program/triggered/self_scan
|
||||
program_type = /datum/nanite_program/self_scan
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/dermal_button
|
||||
name = "Dermal Button"
|
||||
desc = "Displays a button on the host's skin, which can be used to send a signal to the nanites."
|
||||
id = "dermal_button_nanites"
|
||||
program_type = /datum/nanite_program/dermal_button
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/stealth
|
||||
@@ -46,11 +67,19 @@
|
||||
program_type = /datum/nanite_program/stealth
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/reduced_diagnostics
|
||||
name = "Reduced Diagnostics"
|
||||
desc = "Disables some high-cost diagnostics in the nanites, making them unable to communicate their program list to portable scanners. \
|
||||
Doing so saves some power, slightly increasing their replication speed."
|
||||
id = "red_diag_nanites"
|
||||
program_type = /datum/nanite_program/reduced_diagnostics
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/access
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
id = "access_nanites"
|
||||
program_type = /datum/nanite_program/triggered/access
|
||||
program_type = /datum/nanite_program/access
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/relay
|
||||
@@ -76,9 +105,9 @@
|
||||
|
||||
/datum/design/nanites/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
id = "emp_nanites"
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
program_type = /datum/nanite_program/emp
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/spreading
|
||||
@@ -89,6 +118,13 @@
|
||||
program_type = /datum/nanite_program/spreading
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/nanite_sting
|
||||
name = "Nanite Sting"
|
||||
desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster."
|
||||
id = "nanite_sting_nanites"
|
||||
program_type = /datum/nanite_program/nanite_sting
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
@@ -167,7 +203,7 @@
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites, when triggered, send a defibrillating shock to the host's heart."
|
||||
id = "defib_nanites"
|
||||
program_type = /datum/nanite_program/triggered/defib
|
||||
program_type = /datum/nanite_program/defib
|
||||
category = list("Medical Nanites")
|
||||
|
||||
|
||||
@@ -212,7 +248,7 @@
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
id = "adrenaline_nanites"
|
||||
program_type = /datum/nanite_program/triggered/adrenaline
|
||||
program_type = /datum/nanite_program/adrenaline
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/mindshield
|
||||
@@ -336,21 +372,21 @@
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
id = "heartstop_nanites"
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
program_type = /datum/nanite_program/heart_stop
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Blows up all the nanites inside the host in a chain reaction when triggered."
|
||||
id = "explosive_nanites"
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
program_type = /datum/nanite_program/explosive
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
id = "mindcontrol_nanites"
|
||||
program_type = /datum/nanite_program/mind_control
|
||||
program_type = /datum/nanite_program/comm/mind_control
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
////////////////////SUPPRESSION NANITES//////////////////////////////////////
|
||||
@@ -359,21 +395,21 @@
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
id = "shock_nanites"
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
program_type = /datum/nanite_program/shocking
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
id = "stun_nanites"
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
program_type = /datum/nanite_program/stun
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
id = "sleep_nanites"
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
program_type = /datum/nanite_program/sleepy
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/paralyzing
|
||||
@@ -415,21 +451,35 @@
|
||||
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/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/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/comm/hallucination
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/good_mood
|
||||
name = "Happiness Enhancer"
|
||||
desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
|
||||
id = "good_mood_nanites"
|
||||
program_type = /datum/nanite_program/good_mood
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/bad_mood
|
||||
name = "Happiness Suppressor"
|
||||
desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
|
||||
id = "bad_mood_nanites"
|
||||
program_type = /datum/nanite_program/bad_mood
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
////////////////////SENSOR NANITES//////////////////////////////////////
|
||||
@@ -469,9 +519,42 @@
|
||||
program_type = /datum/nanite_program/sensor/voice
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor__nanite_volume
|
||||
/datum/design/nanites/sensor_nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
id = "sensor_nanite_volume"
|
||||
program_type = /datum/nanite_program/sensor/nanite_volume
|
||||
category = list("Sensor Nanites")
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
////////////////////NANITE PROTOCOLS//////////////////////////////////////
|
||||
//Note about the category name: The UI cuts the last 8 characters from the category name to remove the " Nanites" in the other categories
|
||||
//Because of this, Protocols was getting cut down to "P", so i had to add some padding
|
||||
/*
|
||||
/datum/design/nanites/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
id = "kickstart_nanites"
|
||||
program_type = /datum/nanite_program/protocol/kickstart
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. The factory decays if the protocol is not active."
|
||||
id = "factory_nanites"
|
||||
program_type = /datum/nanite_program/protocol/factory
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
id = "tinker_nanites"
|
||||
program_type = /datum/nanite_program/protocol/tinker
|
||||
category = list("Protocols_Nanites")
|
||||
|
||||
/datum/design/nanites/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
id = "offline_nanites"
|
||||
program_type = /datum/nanite_program/protocol/offline
|
||||
category = list("Protocols_Nanites")
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/datum/nanite_extra_setting
|
||||
var/setting_type
|
||||
var/value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_value()
|
||||
return value
|
||||
|
||||
/datum/nanite_extra_setting/proc/set_value(value)
|
||||
src.value = value
|
||||
|
||||
/datum/nanite_extra_setting/proc/get_copy()
|
||||
return
|
||||
|
||||
//I made the choice to send the name as part of the parameter instead of storing it directly on
|
||||
//this datum as a way of avoiding duplication of data between the containing assoc list
|
||||
//and this datum.
|
||||
//Also make sure to double wrap the list when implementing this as
|
||||
//+= is interpreted as a combine on lists, so the outer list gets unwrapped
|
||||
/datum/nanite_extra_setting/proc/get_frontend_list(name)
|
||||
return
|
||||
27
code/modules/research/nanites/extra_settings/boolean.dm
Normal file
27
code/modules/research/nanites/extra_settings/boolean.dm
Normal file
@@ -0,0 +1,27 @@
|
||||
/datum/nanite_extra_setting/boolean
|
||||
setting_type = NESTYPE_BOOLEAN
|
||||
var/true_text
|
||||
var/false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/New(initial, true_text, false_text)
|
||||
value = initial
|
||||
src.true_text = true_text
|
||||
src.false_text = false_text
|
||||
|
||||
/datum/nanite_extra_setting/boolean/set_value(value)
|
||||
if(isnull(value))
|
||||
src.value = !src.value
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_copy()
|
||||
return new /datum/nanite_extra_setting/boolean(value, true_text, false_text)
|
||||
|
||||
/datum/nanite_extra_setting/boolean/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"true_text" = true_text,
|
||||
"false_text" = false_text
|
||||
))
|
||||
32
code/modules/research/nanites/extra_settings/number.dm
Normal file
32
code/modules/research/nanites/extra_settings/number.dm
Normal file
@@ -0,0 +1,32 @@
|
||||
/datum/nanite_extra_setting/number
|
||||
setting_type = NESTYPE_NUMBER
|
||||
var/min
|
||||
var/max
|
||||
var/unit = ""
|
||||
|
||||
/datum/nanite_extra_setting/number/New(initial, min, max, unit)
|
||||
value = initial
|
||||
src.min = min
|
||||
src.max = max
|
||||
if(unit)
|
||||
src.unit = unit
|
||||
|
||||
/datum/nanite_extra_setting/number/set_value(value)
|
||||
if(istext(value))
|
||||
value = text2num(value)
|
||||
if(!value || !isnum(value))
|
||||
return
|
||||
src.value = CLAMP(value, min, max)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_copy()
|
||||
return new /datum/nanite_extra_setting/number(value, min, max, unit)
|
||||
|
||||
/datum/nanite_extra_setting/number/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"min" = min,
|
||||
"max" = max,
|
||||
"unit" = unit
|
||||
))
|
||||
18
code/modules/research/nanites/extra_settings/text.dm
Normal file
18
code/modules/research/nanites/extra_settings/text.dm
Normal file
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/text
|
||||
setting_type = NESTYPE_TEXT
|
||||
|
||||
/datum/nanite_extra_setting/text/New(initial)
|
||||
value = initial
|
||||
|
||||
/datum/nanite_extra_setting/text/set_value(value)
|
||||
src.value = trim(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_copy()
|
||||
return new /datum/nanite_extra_setting/text(value)
|
||||
|
||||
/datum/nanite_extra_setting/text/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value
|
||||
))
|
||||
18
code/modules/research/nanites/extra_settings/type.dm
Normal file
18
code/modules/research/nanites/extra_settings/type.dm
Normal file
@@ -0,0 +1,18 @@
|
||||
/datum/nanite_extra_setting/type
|
||||
setting_type = NESTYPE_TYPE
|
||||
var/list/types
|
||||
|
||||
/datum/nanite_extra_setting/type/New(initial, types)
|
||||
value = initial
|
||||
src.types = types
|
||||
|
||||
/datum/nanite_extra_setting/type/get_copy()
|
||||
return new /datum/nanite_extra_setting/type(value, types)
|
||||
|
||||
/datum/nanite_extra_setting/type/get_frontend_list(name)
|
||||
return list(list(
|
||||
"name" = name,
|
||||
"type" = setting_type,
|
||||
"value" = value,
|
||||
"types" = types
|
||||
))
|
||||
@@ -72,7 +72,7 @@
|
||||
return
|
||||
occupant.AddComponent(/datum/component/nanites, 100)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/install_program(datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/remove_nanites(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
@@ -83,74 +83,46 @@
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing installation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Installing program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_installation, locked_state, NP),55)
|
||||
//TODO OMINOUS MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing cleanup protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Analyzing host bio-structure...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Pinging nanites...", "[initial(icon_state)]_active"),40)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Initiating graceful self-destruct sequence...", "[initial(icon_state)]_active"),70)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Removing debris...", "[initial(icon_state)]_falling"),110)
|
||||
addtimer(CALLBACK(src, .proc/complete_removal, locked_state),130)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_installation(locked_state, datum/nanite_program/NP)
|
||||
/obj/machinery/nanite_chamber/proc/complete_removal(locked_state)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_DELETE)
|
||||
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_ADD_PROGRAM, NP.copy())
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/uninstall_program(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing uninstallation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Uninstalling program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_uninstallation, locked_state, NP),55)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_uninstallation(locked_state, datum/nanite_program/NP)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
qdel(NP)
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon_state()
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
icon_state = initial(icon_state) + "_occupied"
|
||||
else
|
||||
//running
|
||||
icon_state = initial(icon_state) + (state_open ? "_open" : "")
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
/obj/machinery/nanite_chamber/update_overlays()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/nanite_chamber/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
if((stat & MAINT) || panel_open)
|
||||
. += "maint"
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
. += "red"
|
||||
if(locked)
|
||||
. += "bolted"
|
||||
else
|
||||
. += "green"
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
@@ -177,7 +149,7 @@
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
@@ -226,6 +198,8 @@
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) || !Adjacent(target) || !user.Adjacent(target) || !iscarbon(target))
|
||||
return
|
||||
close_machine(target)
|
||||
if(close_machine(target))
|
||||
log_combat(user, target, "inserted", null, "into [src].")
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -5,30 +5,13 @@
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
|
||||
icon_screen = "nanite_chamber_control"
|
||||
ui_x = 380
|
||||
ui_y = 570
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/Initialize()
|
||||
. = ..()
|
||||
find_chamber()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/find_chamber()
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/C = locate(/obj/machinery/nanite_chamber, get_step(src, direction))
|
||||
@@ -43,41 +26,13 @@
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, 550, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
|
||||
if(!chamber)
|
||||
data["status_msg"] = "No chamber detected."
|
||||
@@ -97,6 +52,7 @@
|
||||
data["status_msg"] = chamber.busy_message
|
||||
return data
|
||||
|
||||
data["status_msg"] = null
|
||||
data["scan_level"] = chamber.scan_level
|
||||
data["locked"] = chamber.locked
|
||||
data["occupant_name"] = chamber.occupant.name
|
||||
@@ -113,46 +69,32 @@
|
||||
chamber.locked = !chamber.locked
|
||||
chamber.update_icon()
|
||||
. = TRUE
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("set_safety")
|
||||
var/threshold = input("Set safety threshold (0-500):", name, null) as null|num
|
||||
var/threshold = text2num(params["value"])
|
||||
if(!isnull(threshold))
|
||||
chamber.set_safety(CLAMP(round(threshold, 1),0,500))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' safety threshold was set to [threshold] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' safety threshold was set to [threshold] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("set_cloud")
|
||||
var/cloud_id = input("Set cloud ID (1-100, 0 to disable):", name, null) as null|num
|
||||
var/cloud_id = text2num(params["value"])
|
||||
if(!isnull(cloud_id))
|
||||
chamber.set_cloud(CLAMP(round(cloud_id, 1),0,100))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' cloud id was set to [cloud_id] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
chamber.occupant.investigate_log("'s nanites' cloud id was set to [cloud_id] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("connect_chamber")
|
||||
find_chamber()
|
||||
. = TRUE
|
||||
if("remove_nanites")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.remove_nanites()
|
||||
log_combat(usr, chamber.occupant, "cleared nanites from", null, "via [src]")
|
||||
chamber.occupant.investigate_log("'s nanites were cleared by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("nanite_injection")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
chamber.inject_nanites()
|
||||
investigate_log("[key_name(chamber.occupant)] was injected with nanites by [key_name(usr)] using a nanite chamber.", INVESTIGATE_NANITES)
|
||||
log_combat(usr, chamber.occupant, "injected", null, "with nanites via [src]")
|
||||
chamber.occupant.investigate_log("was injected with nanites by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("add_program")
|
||||
if(!disk || !chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
chamber.install_program(disk.program)
|
||||
investigate_log("Program of type [disk.program.type] was installed into [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_program")
|
||||
if(!chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
var/list/nanite_programs = list()
|
||||
SEND_SIGNAL(chamber.occupant, COMSIG_NANITE_GET_PROGRAMS, nanite_programs)
|
||||
if(LAZYLEN(nanite_programs))
|
||||
var/datum/nanite_program/P = nanite_programs[text2num(params["program_id"])]
|
||||
chamber.uninstall_program(P)
|
||||
investigate_log("Program of type [P.type] was uninstalled from [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -4,9 +4,13 @@
|
||||
circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_cloud_controller"
|
||||
ui_x = 375
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/current_view = 0 //0 is the main menu, any other number is the page of the backup with that ID
|
||||
var/new_backup_id = 1
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/Destroy()
|
||||
QDEL_LIST(cloud_backups) //rip backups
|
||||
@@ -19,8 +23,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -50,13 +54,14 @@
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
@@ -71,24 +76,28 @@
|
||||
disk_data["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
disk_data["timer_restart"] = P.timer_restart / 10
|
||||
disk_data["timer_shutdown"] = P.timer_shutdown / 10
|
||||
disk_data["timer_trigger"] = P.timer_trigger / 10
|
||||
disk_data["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
if(istype(P, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/sensor = P
|
||||
if(sensor.can_rule)
|
||||
disk_data["can_rule"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["new_backup_id"] = new_backup_id
|
||||
|
||||
data["current_view"] = current_view
|
||||
if(current_view)
|
||||
@@ -108,19 +117,30 @@
|
||||
cloud_program["trigger_cost"] = P.trigger_cost
|
||||
cloud_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
cloud_program["activated"] = P.activated
|
||||
cloud_program["activation_delay"] = P.activation_delay
|
||||
cloud_program["timer"] = P.timer
|
||||
cloud_program["timer_type"] = P.get_timer_type_text()
|
||||
cloud_program["timer_restart"] = P.timer_restart / 10
|
||||
cloud_program["timer_shutdown"] = P.timer_shutdown / 10
|
||||
cloud_program["timer_trigger"] = P.timer_trigger / 10
|
||||
cloud_program["timer_trigger_delay"] = P.timer_trigger_delay / 10
|
||||
|
||||
cloud_program["activation_code"] = P.activation_code
|
||||
cloud_program["deactivation_code"] = P.deactivation_code
|
||||
cloud_program["kill_code"] = P.kill_code
|
||||
cloud_program["trigger_code"] = P.trigger_code
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/rules = list()
|
||||
var/rule_id = 1
|
||||
for(var/X in P.rules)
|
||||
var/datum/nanite_rule/nanite_rule = X
|
||||
var/list/rule = list()
|
||||
rule["display"] = nanite_rule.display()
|
||||
rule["program_id"] = id
|
||||
rule["id"] = rule_id
|
||||
rules += list(rule)
|
||||
rule_id++
|
||||
cloud_program["rules"] = rules
|
||||
if(LAZYLEN(rules))
|
||||
cloud_program["has_rules"] = TRUE
|
||||
|
||||
var/list/extra_settings = P.get_extra_settings_frontend()
|
||||
cloud_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
cloud_program["has_extra_settings"] = TRUE
|
||||
@@ -147,17 +167,20 @@
|
||||
if("set_view")
|
||||
current_view = text2num(params["view"])
|
||||
. = TRUE
|
||||
if("update_new_backup_value")
|
||||
var/backup_value = text2num(params["value"])
|
||||
new_backup_id = backup_value
|
||||
if("create_backup")
|
||||
var/cloud_id = input("Choose a cloud ID (1-100):", name, null) as null|num
|
||||
var/cloud_id = new_backup_id
|
||||
if(!isnull(cloud_id))
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
cloud_id = CLAMP(round(cloud_id, 1),1,100)
|
||||
generate_backup(cloud_id, usr)
|
||||
. = TRUE
|
||||
if("delete_backup")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
qdel(backup)
|
||||
investigate_log("[key_name(usr)] deleted the nanite cloud backup #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -165,7 +188,7 @@
|
||||
if(disk && disk.program)
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
nanites.add_program(null, disk.program.copy())
|
||||
investigate_log("[key_name(usr)] uploaded program [disk.program.name] to cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
@@ -173,12 +196,37 @@
|
||||
if("remove_program")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
investigate_log("[key_name(usr)] deleted program [P.name] from cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
qdel(P)
|
||||
. = TRUE
|
||||
if("add_rule")
|
||||
if(disk && disk.program && istype(disk.program, /datum/nanite_program/sensor))
|
||||
var/datum/nanite_program/sensor/rule_template = disk.program
|
||||
if(!rule_template.can_rule)
|
||||
return
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = rule_template.make_rule(P)
|
||||
|
||||
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_rule")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
|
||||
rule.remove()
|
||||
|
||||
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
|
||||
/datum/nanite_cloud_backup
|
||||
var/cloud_id = 0
|
||||
@@ -193,4 +241,4 @@
|
||||
/datum/nanite_cloud_backup/Destroy()
|
||||
storage.cloud_backups -= src
|
||||
SSnanites.cloud_backups -= src
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/obj/item/nanite_hijacker
|
||||
name = "nanite remote control" //fake name
|
||||
desc = "A device that can load nanite programming disks, edit them at will, and imprint them to nanites remotely."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
item_flags = NOBLUDGEON
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/obj/item/nanite_hijacker/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(disk)
|
||||
eject()
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_hijacker/examine(mob/user)
|
||||
. = ..()
|
||||
if(disk)
|
||||
. += "<span class='notice'>Alt-click [src] to eject the disk.</span>"
|
||||
|
||||
/obj/item/nanite_hijacker/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject()
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/nanite_hijacker/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
program = null
|
||||
|
||||
/obj/item/nanite_hijacker/afterattack(atom/target, mob/user, etc)
|
||||
if(!disk || !disk.program)
|
||||
return
|
||||
if(isliving(target))
|
||||
var/success = SEND_SIGNAL(target, COMSIG_NANITE_ADD_PROGRAM, program.copy())
|
||||
switch(success)
|
||||
if(NONE)
|
||||
to_chat(user, "<span class='notice'>You don't detect any nanites in [target].</span>")
|
||||
if(COMPONENT_PROGRAM_INSTALLED)
|
||||
to_chat(user, "<span class='notice'>You insert the currently loaded program into [target]'s nanites.</span>")
|
||||
if(COMPONENT_PROGRAM_NOT_INSTALLED)
|
||||
to_chat(user, "<span class='warning'>You try to insert the currently loaded program into [target]'s nanites, but the installation fails.</span>")
|
||||
|
||||
//Same UI as the nanite programmer, as it pretty much does the same
|
||||
/obj/item/nanite_hijacker/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_programmer", "Internal Nanite Programmer", 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_hijacker/ui_data()
|
||||
var/list/data = list()
|
||||
data["has_disk"] = istype(disk)
|
||||
data["has_program"] = istype(program)
|
||||
if(program)
|
||||
data["name"] = program.name
|
||||
data["desc"] = program.desc
|
||||
data["use_rate"] = program.use_rate
|
||||
data["can_trigger"] = program.can_trigger
|
||||
data["trigger_cost"] = program.trigger_cost
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_hijacker/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
program.activation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("deactivation")
|
||||
program.deactivation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("kill")
|
||||
program.kill_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("trigger")
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if(!isnull(timer))
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
@@ -6,4 +6,4 @@
|
||||
icon_state = "nanite_remote"
|
||||
|
||||
/obj/item/nanite_injector/attack_self(mob/user)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
ui_x = 500
|
||||
ui_y = 700
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/techweb/linked_techweb
|
||||
var/current_category = "Main"
|
||||
var/detail_view = FALSE
|
||||
var/detail_view = TRUE
|
||||
var/categories = list(
|
||||
list(name = "Utility Nanites"),
|
||||
list(name = "Medical Nanites"),
|
||||
list(name = "Sensor Nanites"),
|
||||
list(name = "Augmentation Nanites"),
|
||||
list(name = "Suppression Nanites"),
|
||||
list(name = "Weaponized Nanites")
|
||||
list(name = "Weaponized Nanites"),
|
||||
//list(name = "Protocols") B.E.P.I.S Content, which we dont have
|
||||
)
|
||||
|
||||
/obj/machinery/nanite_program_hub/Initialize()
|
||||
@@ -31,8 +34,8 @@
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
@@ -45,10 +48,9 @@
|
||||
disk = null
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, 500, 700, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //to avoid making the whole program list every second
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_data()
|
||||
@@ -62,25 +64,31 @@
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
data["disk"] = disk_data
|
||||
else
|
||||
data["has_disk"] = FALSE
|
||||
|
||||
data["detail_view"] = detail_view
|
||||
data["category"] = current_category
|
||||
|
||||
if(current_category != "Main")
|
||||
var/list/program_list = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
if(current_category in D.category)
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
program_list += list(program_design)
|
||||
data["program_list"] = program_list
|
||||
else
|
||||
data["categories"] = categories
|
||||
return data
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["programs"] = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
|
||||
if(!istype(D))
|
||||
continue
|
||||
var/cat_name = D.category[1] //just put them in the first category fuck it
|
||||
if(isnull(data["programs"][cat_name]))
|
||||
data["programs"][cat_name] = list()
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
data["programs"][cat_name] += list(program_design)
|
||||
|
||||
if(!length(data["programs"]))
|
||||
data["programs"] = null
|
||||
|
||||
return data
|
||||
|
||||
@@ -101,11 +109,10 @@
|
||||
qdel(disk.program)
|
||||
disk.program = new downloaded.program_type
|
||||
disk.name = "[initial(disk.name)] \[[disk.program.name]\]"
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_category")
|
||||
var/new_category = params["category"]
|
||||
current_category = new_category
|
||||
if("refresh")
|
||||
update_static_data(usr)
|
||||
. = TRUE
|
||||
if("toggle_details")
|
||||
detail_view = !detail_view
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
flags_1 = HEAR_1
|
||||
ui_x = 420
|
||||
ui_y = 550
|
||||
|
||||
/obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
@@ -17,7 +20,7 @@
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
@@ -32,9 +35,9 @@
|
||||
program = null
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, 600, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, ui_x, ui_y, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_data()
|
||||
@@ -50,20 +53,16 @@
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
data["timer_restart"] = program.timer_restart / 10
|
||||
data["timer_shutdown"] = program.timer_shutdown / 10
|
||||
data["timer_trigger"] = program.timer_trigger / 10
|
||||
data["timer_trigger_delay"] = program.timer_trigger_delay / 10
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
var/list/extra_settings = program.get_extra_settings_frontend()
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
@@ -78,20 +77,12 @@
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
var/new_code = text2num(params["code"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
@@ -104,37 +95,44 @@
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
program.set_extra_setting(params["target_setting"], params["value"])
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if("set_restart_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_restart = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
if("set_shutdown_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_shutdown = timer
|
||||
. = TRUE
|
||||
if("set_trigger_timer")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger = timer
|
||||
. = TRUE
|
||||
if("set_timer_trigger_delay")
|
||||
var/timer = text2num(params["delay"])
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, FALSE)
|
||||
timer = CLAMP(round(timer, 1), 0, 3600)
|
||||
timer *= 10 //convert to deciseconds
|
||||
program.timer_trigger_delay = timer
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when
|
||||
if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer))
|
||||
say("When you code it!!")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/trigger_cost = 0 //Amount of nanites required to trigger
|
||||
var/trigger_cooldown = 50 //Deciseconds required between each trigger activation
|
||||
var/next_trigger = 0 //World time required for the next trigger activation
|
||||
var/timer_counter = 0 //Counts up while active. Used for the timer and the activation delay.
|
||||
|
||||
var/program_flags = NONE
|
||||
var/passive_enabled = FALSE //If the nanites have an on/off-style effect, it's tracked by this var
|
||||
|
||||
@@ -28,9 +28,17 @@
|
||||
|
||||
//The following vars are customizable
|
||||
var/activated = TRUE //If FALSE, the program won't process, disables passive effects, can't trigger and doesn't consume nanites
|
||||
var/activation_delay = 0 //Seconds before the program self-activates.
|
||||
var/timer = 0 //Seconds before the timer effect activates. Starts counting AFTER the activation delay
|
||||
var/timer_type = NANITE_TIMER_DEACTIVATE //What happens when the timer runs out
|
||||
|
||||
var/timer_restart = 0 //When deactivated, the program will wait X deciseconds before self-reactivating. Also works if the program begins deactivated.
|
||||
var/timer_shutdown = 0 //When activated, the program will wait X deciseconds before self-deactivating. Also works if the program begins activated.
|
||||
var/timer_trigger = 0 //[Trigger only] While active, the program will attempt to trigger once every x deciseconds.
|
||||
var/timer_trigger_delay = 0 //[Trigger only] While active, the program will delay trigger signals by X deciseconds.
|
||||
|
||||
//Indicates the next world.time tick where these timers will act
|
||||
var/timer_restart_next = 0
|
||||
var/timer_shutdown_next = 0
|
||||
var/timer_trigger_next = 0
|
||||
var/timer_trigger_delay_next = 0
|
||||
|
||||
//Signal codes, these handle remote input to the nanites. If set to 0 they'll ignore signals.
|
||||
var/activation_code = 0 //Code that activates the program [1-9999]
|
||||
@@ -39,19 +47,19 @@
|
||||
var/trigger_code = 0 //Code that triggers the program (if available) [1-9999]
|
||||
|
||||
//Extra settings
|
||||
//Must be listed in text form, with the same title they'll be displayed in the programmer UI
|
||||
//Changing these values is handled by set_extra_setting()
|
||||
//Viewing these values is handled by get_extra_setting()
|
||||
//Copying these values is handled by copy_extra_settings_to()
|
||||
///Don't ever override this or I will come to your house and stand menacingly behind a bush
|
||||
var/list/extra_settings = list()
|
||||
|
||||
/datum/nanite_program/triggered
|
||||
use_rate = 0
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 50
|
||||
can_trigger = TRUE
|
||||
//Rules
|
||||
//Rules that automatically manage if the program's active without requiring separate sensor programs
|
||||
var/list/datum/nanite_rule/rules = list()
|
||||
|
||||
/datum/nanite_program/New()
|
||||
. = ..()
|
||||
register_extra_settings()
|
||||
|
||||
/datum/nanite_program/Destroy()
|
||||
extra_settings = null
|
||||
if(host_mob)
|
||||
if(activated)
|
||||
deactivate()
|
||||
@@ -64,39 +72,60 @@
|
||||
|
||||
/datum/nanite_program/proc/copy()
|
||||
var/datum/nanite_program/new_program = new type()
|
||||
|
||||
new_program.activated = activated
|
||||
new_program.activation_delay = activation_delay
|
||||
new_program.timer = timer
|
||||
new_program.timer_type = timer_type
|
||||
new_program.activation_code = activation_code
|
||||
new_program.deactivation_code = deactivation_code
|
||||
new_program.kill_code = kill_code
|
||||
new_program.trigger_code = trigger_code
|
||||
copy_extra_settings_to(new_program)
|
||||
copy_programming(new_program, TRUE)
|
||||
|
||||
return new_program
|
||||
|
||||
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
|
||||
if(copy_activated)
|
||||
target.activated = activated
|
||||
target.activation_delay = activation_delay
|
||||
target.timer = timer
|
||||
target.timer_type = timer_type
|
||||
target.timer_restart = timer_restart
|
||||
target.timer_shutdown = timer_shutdown
|
||||
target.timer_trigger = timer_trigger
|
||||
target.timer_trigger_delay = timer_trigger_delay
|
||||
target.activation_code = activation_code
|
||||
target.deactivation_code = deactivation_code
|
||||
target.kill_code = kill_code
|
||||
target.trigger_code = trigger_code
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
/datum/nanite_program/proc/set_extra_setting(user, setting)
|
||||
target.rules = list()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
rule.copy_to(target)
|
||||
|
||||
if(istype(target,src))
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
///Register extra settings by overriding this.
|
||||
///extra_settings[name] = new typepath() for each extra setting
|
||||
/datum/nanite_program/proc/register_extra_settings()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/get_extra_setting(setting)
|
||||
return
|
||||
///You can override this if you need to have special behavior after setting certain settings.
|
||||
/datum/nanite_program/proc/set_extra_setting(setting, value)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.set_value(value)
|
||||
|
||||
///You probably shouldn't be overriding this one, but I'm not a cop.
|
||||
/datum/nanite_program/proc/get_extra_setting_value(setting)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[setting]
|
||||
return ES.get_value()
|
||||
|
||||
///Used for getting information about the extra settings to the frontend
|
||||
/datum/nanite_program/proc/get_extra_settings_frontend()
|
||||
var/list/out = list()
|
||||
for(var/name in extra_settings)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[name]
|
||||
out += ES.get_frontend_list(name)
|
||||
return out
|
||||
|
||||
///Copy of the list instead of direct reference for obvious reasons
|
||||
/datum/nanite_program/proc/copy_extra_settings_to(datum/nanite_program/target)
|
||||
return
|
||||
var/list/copy_list = list()
|
||||
for(var/ns_name in extra_settings)
|
||||
var/datum/nanite_extra_setting/extra_setting = extra_settings[ns_name]
|
||||
copy_list[ns_name] = extra_setting.get_copy()
|
||||
target.extra_settings = copy_list
|
||||
|
||||
/datum/nanite_program/proc/on_add(datum/component/nanites/_nanites)
|
||||
nanites = _nanites
|
||||
@@ -105,10 +134,12 @@
|
||||
|
||||
/datum/nanite_program/proc/on_mob_add()
|
||||
host_mob = nanites.host_mob
|
||||
if(activated) //apply activation effects if it starts active
|
||||
if(activated) //apply activation effects depending on initial status; starts the restart and shutdown timers
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
|
||||
datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/on_mob_remove()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/toggle()
|
||||
@@ -119,36 +150,35 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
|
||||
/datum/nanite_program/proc/activate()
|
||||
activated = TRUE
|
||||
timer_counter = activation_delay
|
||||
if(timer_shutdown)
|
||||
timer_shutdown_next = world.time + timer_shutdown
|
||||
|
||||
/datum/nanite_program/proc/deactivate()
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
activated = FALSE
|
||||
if(timer_restart)
|
||||
timer_restart_next = world.time + timer_restart
|
||||
|
||||
/datum/nanite_program/proc/on_process()
|
||||
timer_counter++
|
||||
|
||||
if(activation_delay)
|
||||
if(activated && timer_counter < activation_delay)
|
||||
deactivate()
|
||||
else if(!activated && timer_counter >= activation_delay)
|
||||
activate()
|
||||
if(!activated)
|
||||
if(timer_restart_next && world.time > timer_restart_next)
|
||||
activate()
|
||||
timer_restart_next = 0
|
||||
return
|
||||
|
||||
if(timer && timer_counter > timer)
|
||||
if(timer_type == NANITE_TIMER_DEACTIVATE)
|
||||
deactivate()
|
||||
return
|
||||
else if(timer_type == NANITE_TIMER_SELFDELETE)
|
||||
qdel(src)
|
||||
return
|
||||
else if(can_trigger && timer_type == NANITE_TIMER_TRIGGER)
|
||||
trigger()
|
||||
timer_counter = activation_delay
|
||||
else if(timer_type == NANITE_TIMER_RESET)
|
||||
timer_counter = 0
|
||||
if(timer_shutdown_next && world.time > timer_shutdown_next)
|
||||
deactivate()
|
||||
timer_shutdown_next = 0
|
||||
|
||||
if(timer_trigger && world.time > timer_trigger_next)
|
||||
trigger()
|
||||
timer_trigger_next = world.time + timer_trigger
|
||||
|
||||
if(timer_trigger_delay_next && world.time > timer_trigger_delay_next)
|
||||
trigger(delayed = TRUE)
|
||||
timer_trigger_delay_next = 0
|
||||
|
||||
if(check_conditions() && consume_nanites(use_rate))
|
||||
if(!passive_enabled)
|
||||
enable_passive_effect()
|
||||
@@ -160,6 +190,10 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
//If false, disables active and passive effects, but doesn't consume nanites
|
||||
//Can be used to avoid consuming nanites for nothing
|
||||
/datum/nanite_program/proc/check_conditions()
|
||||
for(var/R in rules)
|
||||
var/datum/nanite_rule/rule = R
|
||||
if(!rule.check_rule())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Constantly procs as long as the program is active
|
||||
@@ -174,15 +208,25 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/disable_passive_effect()
|
||||
passive_enabled = FALSE
|
||||
|
||||
/datum/nanite_program/proc/trigger()
|
||||
//Checks conditions then fires the nanite trigger effect
|
||||
/datum/nanite_program/proc/trigger(delayed = FALSE, comm_message)
|
||||
if(!can_trigger)
|
||||
return
|
||||
if(!activated)
|
||||
return FALSE
|
||||
return
|
||||
if(timer_trigger_delay && !delayed)
|
||||
timer_trigger_delay_next = world.time + timer_trigger_delay
|
||||
return
|
||||
if(world.time < next_trigger)
|
||||
return FALSE
|
||||
return
|
||||
if(!consume_nanites(trigger_cost))
|
||||
return FALSE
|
||||
return
|
||||
next_trigger = world.time + trigger_cooldown
|
||||
return TRUE
|
||||
on_trigger(comm_message)
|
||||
|
||||
//Nanite trigger effect, requires can_trigger to be used
|
||||
/datum/nanite_program/proc/on_trigger(comm_message)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/consume_nanites(amount, force = FALSE)
|
||||
return nanites.consume_nanites(amount, force)
|
||||
@@ -234,24 +278,36 @@ datum/nanite_program/proc/on_mob_remove()
|
||||
/datum/nanite_program/proc/receive_signal(code, source)
|
||||
if(activation_code && code == activation_code && !activated)
|
||||
activate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
else if(deactivation_code && code == deactivation_code && activated)
|
||||
deactivate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
host_mob.investigate_log("'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(can_trigger && trigger_code && code == trigger_code)
|
||||
trigger()
|
||||
host_mob.investigate_log("[host_mob]'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)
|
||||
host_mob.investigate_log("[host_mob]'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)
|
||||
|
||||
/datum/nanite_program/proc/get_timer_type_text()
|
||||
switch(timer_type)
|
||||
if(NANITE_TIMER_DEACTIVATE)
|
||||
return "Deactivate"
|
||||
if(NANITE_TIMER_SELFDELETE)
|
||||
return "Self-Delete"
|
||||
if(NANITE_TIMER_TRIGGER)
|
||||
return "Trigger"
|
||||
if(NANITE_TIMER_RESET)
|
||||
return "Reset Activation Timer"
|
||||
///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once.
|
||||
//Currently unused due to us lacking the B.E.P.I.S
|
||||
/datum/nanite_program/protocol
|
||||
name = "Nanite Protocol"
|
||||
var/protocol_class = NONE
|
||||
|
||||
/datum/nanite_program/protocol/check_conditions()
|
||||
. = ..()
|
||||
for(var/protocol in nanites.protocols)
|
||||
var/datum/nanite_program/protocol/P = protocol
|
||||
if(P != src && P.activated && P.protocol_class == protocol_class)
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/protocol/on_add(datum/component/nanites/_nanites)
|
||||
..()
|
||||
nanites.protocols += src
|
||||
|
||||
/datum/nanite_program/protocol/Destroy()
|
||||
if(nanites)
|
||||
nanites.protocols -= src
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -18,24 +18,16 @@
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.stun_mod *= 2
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline
|
||||
/datum/nanite_program/adrenaline
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/toxic, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline/trigger()
|
||||
if(!..())
|
||||
return
|
||||
to_chat(host_mob, "<span class='notice'>You feel a sudden surge of energy!</span>")
|
||||
host_mob.SetStun(0)
|
||||
host_mob.SetKnockdown(0)
|
||||
host_mob.SetUnconscious(0)
|
||||
host_mob.adjustStaminaLoss(-10) //stimulants give stamina heal now
|
||||
host_mob.lying = 0
|
||||
host_mob.update_canmove()
|
||||
host_mob.reagents.add_reagent(/datum/reagent/medicine/stimulants, 1.5)
|
||||
/datum/nanite_program/adrenaline/on_trigger()
|
||||
host_mob.do_adrenaline(-10, TRUE, TRUE, FALSE, TRUE, list(/datum/reagent/medicine/stimulants = 1.5), "<span class='notice'>You feel a sudden surge of energy!</span>", FALSE, FALSE, FALSE)
|
||||
|
||||
/datum/nanite_program/hardening
|
||||
name = "Dermal Hardening"
|
||||
@@ -120,7 +112,7 @@
|
||||
|
||||
/datum/nanite_program/mindshield/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev)) //won't work if on a rev, to avoid having implanted revs
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev, TRUE)) //won't work if on a rev, to avoid having implanted revs.
|
||||
ADD_TRAIT(host_mob, TRAIT_MINDSHIELD, "nanites")
|
||||
host_mob.sec_hud_set_implants()
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/datum/nanite_program/regenerative
|
||||
name = "Accelerated Regeneration"
|
||||
desc = "The nanites boost the host's natural regeneration, increasing their healing speed. Does not consume nanites if the host is unharmed."
|
||||
use_rate = 2.5
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/regenerative/check_conditions()
|
||||
@@ -23,11 +23,11 @@
|
||||
if(!parts.len)
|
||||
return
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1/parts.len, 1/parts.len))
|
||||
if(L.heal_damage(0.5/parts.len, 0.5/parts.len, null, BODYPART_ORGANIC))
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-1, TRUE)
|
||||
host_mob.adjustFireLoss(-1, TRUE)
|
||||
host_mob.adjustBruteLoss(-0.5, TRUE)
|
||||
host_mob.adjustFireLoss(-0.5, TRUE)
|
||||
|
||||
/datum/nanite_program/temperature
|
||||
name = "Temperature Adjustment"
|
||||
@@ -48,12 +48,12 @@
|
||||
|
||||
/datum/nanite_program/purging
|
||||
name = "Blood Purification"
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slimepeople biology due to inaccuracy."
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slime biology due to inaccuracy."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/purging/check_conditions()
|
||||
var/foreign_reagent = LAZYLEN(host_mob.reagents.reagent_list)
|
||||
var/foreign_reagent = length(host_mob.reagents?.reagent_list)
|
||||
if(!host_mob.getToxLoss() && !foreign_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -73,18 +73,17 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/brain_heal/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_BASIC)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
@@ -112,7 +111,7 @@
|
||||
/datum/nanite_program/repairing
|
||||
name = "Mechanical Repair"
|
||||
desc = "The nanites fix damage in the host's mechanical limbs."
|
||||
use_rate = 0.5 //much more efficient than organic healing
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/repairing/check_conditions()
|
||||
@@ -137,18 +136,18 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1/parts.len, 1/parts.len, only_robotic = TRUE, only_organic = FALSE))
|
||||
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, BODYPART_ROBOTIC)) //much faster than organic healing
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-1, TRUE)
|
||||
host_mob.adjustFireLoss(-1, TRUE)
|
||||
host_mob.adjustBruteLoss(-1.5, TRUE)
|
||||
host_mob.adjustFireLoss(-1.5, TRUE)
|
||||
|
||||
/datum/nanite_program/purging_advanced
|
||||
name = "Selective Blood Purification"
|
||||
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. Due to added complexity, it is safe with slimepeople biology."
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate. This program is safe with slime biology due to the increased precision."
|
||||
use_rate = 2
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
@@ -181,7 +180,7 @@
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len))
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len, null, BODYPART_ORGANIC))
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
@@ -196,70 +195,54 @@
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/check_conditions()
|
||||
var/problems = FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
for(var/X in C.get_traumas())
|
||||
var/datum/brain_trauma/BT = X
|
||||
if(BT.resilience <= TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
return ..()
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
|
||||
return ..()
|
||||
return FALSE
|
||||
if(length(C.get_traumas()))
|
||||
problems = TRUE
|
||||
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN) > 0)
|
||||
problems = TRUE
|
||||
return problems ? ..() : FALSE
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/active_effect()
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2, TRUE)
|
||||
host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
|
||||
/datum/nanite_program/triggered/defib
|
||||
/datum/nanite_program/defib
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 120
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking)
|
||||
|
||||
/datum/nanite_program/triggered/defib/trigger()
|
||||
if(!..())
|
||||
return
|
||||
rogue_types = list(/datum/nanite_program/shocking)
|
||||
|
||||
/datum/nanite_program/defib/on_trigger(comm_message)
|
||||
host_mob.notify_ghost_cloning("Your heart is being defibrillated by nanites. Re-enter your corpse if you want to be revived!")
|
||||
addtimer(CALLBACK(src, .proc/zap), 50)
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/check_revivable()
|
||||
/datum/nanite_program/defib/proc/check_revivable()
|
||||
if(!iscarbon(host_mob)) //nonstandard biology
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(C.suiciding || HAS_TRAIT(C, TRAIT_NOCLONE) || C.hellbound) //can't revive
|
||||
return FALSE
|
||||
if((world.time - C.timeofdeath) > 1800) //too late
|
||||
return FALSE
|
||||
if((C.getBruteLoss() > 180) || (C.getFireLoss() > 180) || !C.can_be_revived()) //too damaged
|
||||
return FALSE
|
||||
if(!C.getorgan(/obj/item/organ/heart)) //what are we even shocking
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/BR = C.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || C.suiciding)
|
||||
return FALSE
|
||||
if(C.get_ghost())
|
||||
return FALSE
|
||||
return TRUE
|
||||
return C.can_defib()
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/zap()
|
||||
/datum/nanite_program/defib/proc/zap()
|
||||
var/mob/living/carbon/C = host_mob
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_charge.ogg', 50, FALSE)
|
||||
sleep(30)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_zap.ogg', 50, FALSE)
|
||||
if(check_revivable())
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, FALSE)
|
||||
C.set_heartattack(FALSE)
|
||||
C.revive()
|
||||
C.revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
C.emote("gasp")
|
||||
C.Jitter(100)
|
||||
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
|
||||
var/tplus = world.time - C.timeofdeath
|
||||
if(tplus > 600)
|
||||
C.adjustOrganLoss(ORGAN_SLOT_BRAIN, max(0, ((1800 - tplus) / 1800 * 150)), 150)
|
||||
log_game("[C] has been successfully defibrillated by nanites.")
|
||||
else
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
playsound(C, 'sound/machines/defib_failed.ogg', 50, FALSE)
|
||||
|
||||
|
||||
107
code/modules/research/nanites/nanite_programs/protocols.dm
Normal file
107
code/modules/research/nanites/nanite_programs/protocols.dm
Normal file
@@ -0,0 +1,107 @@
|
||||
//Replication Protocols
|
||||
/datum/nanite_program/protocol/kickstart
|
||||
name = "Kickstart Protocol"
|
||||
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost_duration = 1200
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/check_conditions()
|
||||
if(!(world.time < nanites.start_time + boost_duration))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/kickstart/active_effect()
|
||||
nanites.adjust_nanites(null, 3.5)
|
||||
|
||||
/datum/nanite_program/protocol/factory
|
||||
name = "Factory Protocol"
|
||||
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. \
|
||||
The factory decays if the protocol is not active, or if the nanites are disrupted by shocks or EMPs."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/factory_efficiency = 0
|
||||
var/max_efficiency = 1000 //Goes up to 2 bonus regen per tick after 16 minutes and 40 seconds
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_process()
|
||||
if(!activated || !check_conditions())
|
||||
factory_efficiency = max(0, factory_efficiency - 5)
|
||||
..()
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_emp(severity)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 300)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_shock(shock_damage)
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 200)
|
||||
|
||||
/datum/nanite_program/protocol/factory/on_minor_shock()
|
||||
..()
|
||||
factory_efficiency = max(0, factory_efficiency - 100)
|
||||
|
||||
/datum/nanite_program/protocol/factory/active_effect()
|
||||
factory_efficiency = min(factory_efficiency + 1, max_efficiency)
|
||||
nanites.adjust_nanites(null, round(0.002 * factory_efficiency, 0.1))
|
||||
|
||||
/datum/nanite_program/protocol/tinker
|
||||
name = "Tinker Protocol"
|
||||
desc = "Replication Protocol: the nanites learn to use metallic material in the host's bloodstream to speed up the replication process."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 2
|
||||
var/list/valid_reagents = list(
|
||||
/datum/reagent/iron,
|
||||
/datum/reagent/copper,
|
||||
/datum/reagent/gold,
|
||||
/datum/reagent/silver,
|
||||
/datum/reagent/mercury,
|
||||
/datum/reagent/aluminium,
|
||||
/datum/reagent/silicon)
|
||||
|
||||
/datum/nanite_program/protocol/tinker/check_conditions()
|
||||
if(!nanites.host_mob.reagents)
|
||||
return FALSE
|
||||
|
||||
var/found_reagent = FALSE
|
||||
|
||||
var/datum/reagents/R = nanites.host_mob.reagents
|
||||
for(var/VR in valid_reagents)
|
||||
if(R.has_reagent(VR, 0.5))
|
||||
R.remove_reagent(VR, 0.5)
|
||||
found_reagent = TRUE
|
||||
break
|
||||
if(!found_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/tinker/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
|
||||
/datum/nanite_program/protocol/offline
|
||||
name = "Offline Production Protocol"
|
||||
desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
protocol_class = NANITE_PROTOCOL_REPLICATION
|
||||
var/boost = 3
|
||||
|
||||
/datum/nanite_program/protocol/offline/check_conditions()
|
||||
var/is_offline = FALSE
|
||||
if(nanites.host_mob.IsSleeping() || nanites.host_mob.IsUnconscious())
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.stat == DEAD || HAS_TRAIT(nanites.host_mob, TRAIT_DEATHCOMA))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOSOFTCRIT))
|
||||
is_offline = TRUE
|
||||
if(nanites.host_mob.InFullCritical() && !HAS_TRAIT(nanites.host_mob, TRAIT_NOHARDCRIT))
|
||||
is_offline = TRUE
|
||||
if(!is_offline)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/protocol/offline/active_effect()
|
||||
nanites.adjust_nanites(null, boost)
|
||||
@@ -2,71 +2,41 @@
|
||||
name = "Sensor Nanites"
|
||||
desc = "These nanites send a signal code when a certain condition is met."
|
||||
unique = FALSE
|
||||
extra_settings = list("Sent Code")
|
||||
var/can_rule = FALSE
|
||||
|
||||
var/sent_code = 0
|
||||
|
||||
/datum/nanite_program/sensor/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
|
||||
/datum/nanite_program/sensor/copy_extra_settings_to(datum/nanite_program/sensor/target)
|
||||
target.sent_code = sent_code
|
||||
/datum/nanite_program/sensor/register_extra_settings()
|
||||
extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/proc/check_event()
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/proc/send_code()
|
||||
if(activated)
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code, "a [name] program")
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_SENT_CODE]
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, ES.value, "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/active_effect()
|
||||
if(sent_code && check_event())
|
||||
if(check_event())
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/proc/make_rule(datum/nanite_program/target)
|
||||
return
|
||||
|
||||
/datum/nanite_program/sensor/repeat
|
||||
name = "Signal Repeater"
|
||||
desc = "When triggered, sends another signal to the nanites, optionally with a delay."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
|
||||
/datum/nanite_program/sensor/repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/repeat/copy_extra_settings_to(datum/nanite_program/sensor/repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
|
||||
/datum/nanite_program/sensor/repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat
|
||||
name = "Relay Signal Repeater"
|
||||
@@ -74,98 +44,46 @@
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Relay Channel","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
var/relay_channel = 0
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
/datum/nanite_program/sensor/relay_repeat/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s")
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/copy_extra_settings_to(datum/nanite_program/sensor/relay_repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
target.relay_channel = relay_channel
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
/datum/nanite_program/sensor/relay_repeat/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY]
|
||||
addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/send_code()
|
||||
if(activated && relay_channel)
|
||||
var/datum/nanite_extra_setting/relay = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(activated && relay.get_value())
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_signal(sent_code, relay_channel, "a [name] program")
|
||||
var/datum/nanite_extra_setting/code = extra_settings[NES_SENT_CODE]
|
||||
N.relay_signal(code.get_value(), relay.get_value(), "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/health
|
||||
name = "Health Sensor"
|
||||
desc = "The nanites receive a signal when the host's health is above/below a target percentage."
|
||||
extra_settings = list("Sent Code","Health Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Health Percent")
|
||||
var/new_percent = input(user, "Set the health percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), -99, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Health Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/health/copy_extra_settings_to(datum/nanite_program/sensor/health/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/health/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_HEALTH_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/health/check_event()
|
||||
var/health_percent = host_mob.health / host_mob.maxHealth * 100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
if(direction == "Above")
|
||||
if(health_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(health_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(health_percent < percent)
|
||||
if(health_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -177,9 +95,18 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/health/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/health/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/crit
|
||||
name = "Critical Health Sensor"
|
||||
desc = "The nanites receive a signal when the host first reaches critical health."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/check_event()
|
||||
@@ -192,61 +119,44 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/crit/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/death
|
||||
name = "Death Sensor"
|
||||
desc = "The nanites receive a signal when they detect the host is dead."
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/death/on_death()
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/death/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/death/rule = new(target)
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
extra_settings = list("Sent Code","Nanite Percent","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Nanite Percent")
|
||||
var/new_percent = input(user, "Set the nanite percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), 1, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Nanite Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/copy_extra_settings_to(datum/nanite_program/sensor/nanite_volume/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/nanite_volume/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_NANITE_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%")
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/check_event()
|
||||
var/nanite_percent = (nanites.nanite_volume - nanites.safety_threshold)/(nanites.max_nanites - nanites.safety_threshold)*100
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/detected = FALSE
|
||||
|
||||
if(direction == "Above")
|
||||
if(nanite_percent >= percent)
|
||||
if(direction.get_value())
|
||||
if(nanite_percent >= percent.get_value())
|
||||
detected = TRUE
|
||||
else
|
||||
if(nanite_percent < percent)
|
||||
if(nanite_percent < percent.get_value())
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
@@ -258,75 +168,51 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/nanites/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = percent.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/damage
|
||||
name = "Damage Sensor"
|
||||
desc = "The nanites receive a signal when a host's specific damage type is above/below a target value."
|
||||
extra_settings = list("Sent Code","Damage Type","Damage","Direction")
|
||||
can_rule = TRUE
|
||||
var/spent = FALSE
|
||||
var/damage_type = "Brute"
|
||||
var/damage = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Damage")
|
||||
var/new_damage = input(user, "Set the damage threshold:", name, null) as null|num
|
||||
if(isnull(new_damage))
|
||||
return
|
||||
damage = CLAMP(round(new_damage, 1), 0, 500)
|
||||
if(setting == "Damage Type")
|
||||
var/list/damage_types = list("Brute","Burn","Toxin","Oxygen","Cellular")
|
||||
var/new_damage_type = input("Choose the damage type", name) as null|anything in damage_types
|
||||
if(!new_damage_type)
|
||||
return
|
||||
damage_type = new_damage_type
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Damage")
|
||||
return damage
|
||||
if(setting == "Damage Type")
|
||||
return damage_type
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/damage/copy_extra_settings_to(datum/nanite_program/sensor/damage/target)
|
||||
target.sent_code = sent_code
|
||||
target.damage = damage
|
||||
target.damage_type = damage_type
|
||||
target.direction = direction
|
||||
/datum/nanite_program/sensor/damage/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DAMAGE_TYPE] = new /datum/nanite_extra_setting/type(BRUTE, list(BRUTE, BURN, TOX, OXY, CLONE))
|
||||
extra_settings[NES_DAMAGE] = new /datum/nanite_extra_setting/number(50, 0, 500)
|
||||
extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below")
|
||||
|
||||
/datum/nanite_program/sensor/damage/check_event()
|
||||
var/reached_threshold = FALSE
|
||||
var/check_above = (direction == "Above")
|
||||
var/datum/nanite_extra_setting/type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/check_above = direction.get_value()
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if("Brute")
|
||||
switch(type.get_value())
|
||||
if(BRUTE)
|
||||
damage_amt = host_mob.getBruteLoss()
|
||||
if("Burn")
|
||||
if(BURN)
|
||||
damage_amt = host_mob.getFireLoss()
|
||||
if("Toxin")
|
||||
if(TOX)
|
||||
damage_amt = host_mob.getToxLoss()
|
||||
if("Oxygen")
|
||||
if(OXY)
|
||||
damage_amt = host_mob.getOxyLoss()
|
||||
if("Cellular")
|
||||
if(CLONE)
|
||||
damage_amt = host_mob.getCloneLoss()
|
||||
|
||||
if(damage_amt >= damage)
|
||||
if(check_above)
|
||||
if(check_above)
|
||||
if(damage_amt >= damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else
|
||||
if(damage_amt < damage.get_value())
|
||||
reached_threshold = TRUE
|
||||
else if(!check_above)
|
||||
reached_threshold = TRUE
|
||||
|
||||
if(reached_threshold)
|
||||
if(!spent)
|
||||
@@ -337,14 +223,25 @@
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/damage/make_rule(datum/nanite_program/target)
|
||||
var/datum/nanite_rule/damage/rule = new(target)
|
||||
var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION]
|
||||
var/datum/nanite_extra_setting/damage_type = extra_settings[NES_DAMAGE_TYPE]
|
||||
var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE]
|
||||
rule.above = direction.get_value()
|
||||
rule.threshold = damage.get_value()
|
||||
rule.damage_type = damage_type.get_value()
|
||||
return rule
|
||||
|
||||
/datum/nanite_program/sensor/voice
|
||||
name = "Voice Sensor"
|
||||
desc = "Sends a signal when the nanites hear a determined word or sentence."
|
||||
extra_settings = list("Sent Code","Sentence","Inclusive Mode")
|
||||
var/spent = FALSE
|
||||
var/sentence = ""
|
||||
var/inclusive = TRUE
|
||||
|
||||
/datum/nanite_program/sensor/voice/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("")
|
||||
extra_settings[NES_INCLUSIVE_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Inclusive", "Exclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/on_mob_add()
|
||||
. = ..()
|
||||
@@ -353,45 +250,14 @@
|
||||
/datum/nanite_program/sensor/voice/on_mob_remove()
|
||||
UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear)
|
||||
|
||||
/datum/nanite_program/sensor/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that triggers the sensor.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
sentence = new_sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
var/new_inclusive = input("Should the sensor detect the sentence if contained within another sentence?", name) as null|anything in list("Inclusive","Exclusive")
|
||||
if(!new_inclusive)
|
||||
return
|
||||
inclusive = (new_inclusive == "Inclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
if(inclusive)
|
||||
return "Inclusive"
|
||||
else
|
||||
return "Exclusive"
|
||||
|
||||
/datum/nanite_program/sensor/voice/copy_extra_settings_to(datum/nanite_program/sensor/voice/target)
|
||||
target.sent_code = sent_code
|
||||
target.sentence = sentence
|
||||
target.inclusive = inclusive
|
||||
|
||||
/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args)
|
||||
if(!sentence)
|
||||
var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE]
|
||||
var/datum/nanite_extra_setting/inclusive = extra_settings[NES_INCLUSIVE_MODE]
|
||||
if(!sentence.get_value())
|
||||
return
|
||||
if(inclusive)
|
||||
if(inclusive.get_value())
|
||||
if(findtextEx(hearing_args[HEARING_RAW_MESSAGE], sentence))
|
||||
send_code()
|
||||
else
|
||||
if(hearing_args[HEARING_RAW_MESSAGE] == sentence)
|
||||
send_code()
|
||||
send_code()
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
//Programs that are generally useful for population control and non-harmful suppression.
|
||||
|
||||
/datum/nanite_program/triggered/sleepy
|
||||
/datum/nanite_program/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 15
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/triggered/sleepy/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/sleepy/on_trigger(comm_message)
|
||||
to_chat(host_mob, "<span class='warning'>You start to feel very sleepy...</span>")
|
||||
host_mob.drowsyness += 20
|
||||
addtimer(CALLBACK(host_mob, /mob/living.proc/Sleeping, 200), rand(60,200))
|
||||
@@ -31,30 +30,28 @@
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='notice'>Your muscles relax, and you can move again.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/shocking
|
||||
/datum/nanite_program/shocking
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 10
|
||||
trigger_cooldown = 300
|
||||
program_flags = NANITE_SHOCK_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/shocking/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/shocking/on_trigger(comm_message)
|
||||
host_mob.electrocute_act(rand(5,10), "shock nanites", TRUE, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/stun
|
||||
/datum/nanite_program/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 4
|
||||
trigger_cooldown = 300
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking, /datum/nanite_program/nerve_decay)
|
||||
rogue_types = list(/datum/nanite_program/shocking, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/stun/trigger()
|
||||
if(!..())
|
||||
return
|
||||
playsound(host_mob, "sparks", 75, 1, -1)
|
||||
/datum/nanite_program/stun/on_trigger(comm_message)
|
||||
playsound(host_mob, "sparks", 75, TRUE, -1)
|
||||
host_mob.Knockdown(80)
|
||||
|
||||
/datum/nanite_program/pacifying
|
||||
@@ -114,42 +111,51 @@
|
||||
. = ..()
|
||||
host_mob.cure_fakedeath("nanites")
|
||||
|
||||
/datum/nanite_program/triggered/speech
|
||||
//Can receive transmissions from a nanite communication remote for customized messages
|
||||
/datum/nanite_program/comm
|
||||
can_trigger = TRUE
|
||||
var/comm_code = 0
|
||||
var/comm_message = ""
|
||||
|
||||
/datum/nanite_program/comm/register_extra_settings()
|
||||
extra_settings[NES_COMM_CODE] = new /datum/nanite_extra_setting/number(0, 0, 9999)
|
||||
|
||||
/datum/nanite_program/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/comm/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
unique = FALSE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
var/static/list/blacklist = list(
|
||||
"*surrender",
|
||||
"*collapse"
|
||||
)
|
||||
|
||||
extra_settings = list("Sentence")
|
||||
var/sentence = ""
|
||||
/datum/nanite_program/comm/speech/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/triggered/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)
|
||||
return
|
||||
if(new_sentence[1] == "*") //emotes are abusable, like surrender
|
||||
return
|
||||
sentence = new_sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/get_extra_setting(setting)
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/copy_extra_settings_to(datum/nanite_program/triggered/speech/target)
|
||||
target.sentence = sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/trigger()
|
||||
if(!..())
|
||||
/datum/nanite_program/comm/speech/on_trigger(comm_message)
|
||||
var/sent_message = comm_message
|
||||
if(!comm_message)
|
||||
var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE]
|
||||
sent_message = sentence.get_value()
|
||||
if(sent_message in blacklist)
|
||||
return
|
||||
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/comm/voice
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
unique = FALSE
|
||||
@@ -157,53 +163,67 @@
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
extra_settings = list("Message")
|
||||
var/message = ""
|
||||
/datum/nanite_program/comm/voice/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MESSAGE] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/triggered/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
|
||||
|
||||
/datum/nanite_program/triggered/voice/get_extra_setting(setting)
|
||||
if(setting == "Message")
|
||||
return message
|
||||
|
||||
/datum/nanite_program/triggered/voice/copy_extra_settings_to(datum/nanite_program/triggered/voice/target)
|
||||
target.message = message
|
||||
|
||||
/datum/nanite_program/triggered/voice/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/comm/voice/on_trigger(comm_message)
|
||||
var/sent_message = comm_message
|
||||
if(!comm_message)
|
||||
var/datum/nanite_extra_setting/message_setting = extra_settings[NES_MESSAGE]
|
||||
sent_message = message_setting.get_value()
|
||||
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/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")
|
||||
var/hal_type
|
||||
var/hal_details
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/trigger()
|
||||
if(!..())
|
||||
/datum/nanite_program/comm/hallucination/register_extra_settings()
|
||||
. = ..()
|
||||
var/list/options = list(
|
||||
"Message",
|
||||
"Battle",
|
||||
"Sound",
|
||||
"Weird Sound",
|
||||
"Station Message",
|
||||
"Health",
|
||||
"Alert",
|
||||
"Fire",
|
||||
"Shock",
|
||||
"Plasma Flood",
|
||||
"Random"
|
||||
)
|
||||
extra_settings[NES_HALLUCINATION_TYPE] = new /datum/nanite_extra_setting/type("Message", options)
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("")
|
||||
|
||||
/datum/nanite_program/comm/hallucination/on_trigger(comm_message)
|
||||
var/datum/nanite_extra_setting/hal_setting = extra_settings[NES_HALLUCINATION_TYPE]
|
||||
var/hal_type = hal_setting.get_value()
|
||||
var/datum/nanite_extra_setting/hal_detail_setting = extra_settings[NES_HALLUCINATION_DETAIL]
|
||||
var/hal_details = hal_detail_setting.get_value()
|
||||
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
|
||||
if(!hal_type)
|
||||
if(hal_details == "random")
|
||||
hal_details = null
|
||||
if(hal_type == "Random")
|
||||
C.hallucination += 15
|
||||
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")
|
||||
@@ -213,6 +233,13 @@
|
||||
if("Station Message")
|
||||
new /datum/hallucination/stationmessage(C, TRUE, hal_details)
|
||||
if("Health")
|
||||
switch(hal_details)
|
||||
if("critical")
|
||||
hal_details = SCREWYHUD_CRIT
|
||||
if("dead")
|
||||
hal_details = SCREWYHUD_DEAD
|
||||
if("healthy")
|
||||
hal_details = SCREWYHUD_HEALTHY
|
||||
new /datum/hallucination/hudscrew(C, TRUE, hal_details)
|
||||
if("Alert")
|
||||
new /datum/hallucination/fake_alert(C, TRUE, hal_details)
|
||||
@@ -223,89 +250,59 @@
|
||||
if("Plasma Flood")
|
||||
new /datum/hallucination/fake_flood(C, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/set_extra_setting(user, setting)
|
||||
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
|
||||
if(!hal_type_choice)
|
||||
return
|
||||
switch(hal_type_choice)
|
||||
if("Random")
|
||||
hal_type = null
|
||||
hal_details = null
|
||||
/datum/nanite_program/comm/hallucination/set_extra_setting(setting, value)
|
||||
. = ..()
|
||||
if(setting == NES_HALLUCINATION_TYPE)
|
||||
switch(value)
|
||||
if("Message")
|
||||
hal_type = "Message"
|
||||
var/hal_chat = stripped_input(user, "Choose the message the host will hear, or leave empty for random messages.", "Message", hal_details, MAX_MESSAGE_LEN)
|
||||
if(hal_chat)
|
||||
hal_details = hal_chat
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("")
|
||||
if("Battle")
|
||||
hal_type = "Battle"
|
||||
var/sound_list = list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb")
|
||||
var/hal_choice = input("Choose the hallucination battle type", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb"))
|
||||
if("Sound")
|
||||
hal_type = "Sound"
|
||||
var/sound_list = list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack"))
|
||||
if("Weird Sound")
|
||||
hal_type = "Weird Sound"
|
||||
var/sound_list = list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla"))
|
||||
if("Station Message")
|
||||
hal_type = "Station Message"
|
||||
var/msg_list = list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter")
|
||||
var/hal_choice = input("Choose the hallucination station message", name) as null|anything in msg_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter"))
|
||||
if("Health")
|
||||
hal_type = "Health"
|
||||
var/health_list = list("random","critical","dead","healthy")
|
||||
var/hal_choice = input("Choose the health status", name) as null|anything in health_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
switch(hal_choice)
|
||||
if("critical")
|
||||
hal_details = SCREWYHUD_CRIT
|
||||
if("dead")
|
||||
hal_details = SCREWYHUD_DEAD
|
||||
if("healthy")
|
||||
hal_details = SCREWYHUD_HEALTHY
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","critical","dead","healthy"))
|
||||
if("Alert")
|
||||
hal_type = "Alert"
|
||||
var/alert_list = list("random","not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","gravity","fire","locked","hacked","temphot","tempcold","pressure")
|
||||
var/hal_choice = input("Choose the alert", name) as null|anything in alert_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Fire")
|
||||
hal_type = "Fire"
|
||||
if("Shock")
|
||||
hal_type = "Shock"
|
||||
if("Plasma Flood")
|
||||
hal_type = "Plasma Flood"
|
||||
extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","gravity","fire","locked","hacked","temphot","tempcold","pressure"))
|
||||
else
|
||||
extra_settings.Remove(NES_HALLUCINATION_DETAIL)
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/get_extra_setting(setting)
|
||||
if(setting == "Hallucination Type")
|
||||
if(!hal_type)
|
||||
return "Random"
|
||||
else
|
||||
return hal_type
|
||||
/datum/nanite_program/good_mood
|
||||
name = "Happiness Enhancer"
|
||||
desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
|
||||
use_rate = 0.1
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/hallucination/target)
|
||||
target.hal_type = hal_type
|
||||
target.hal_details = hal_details
|
||||
/datum/nanite_program/good_mood/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS ENHANCEMENT")
|
||||
|
||||
/datum/nanite_program/good_mood/enable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, get_extra_setting_value(NES_MOOD_MESSAGE))
|
||||
|
||||
/datum/nanite_program/good_mood/disable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_happy")
|
||||
|
||||
/datum/nanite_program/bad_mood
|
||||
name = "Happiness Suppressor"
|
||||
desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
|
||||
use_rate = 0.1
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/bad_mood/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS SUPPRESSION")
|
||||
|
||||
/datum/nanite_program/bad_mood/enable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, get_extra_setting_value(NES_MOOD_MESSAGE))
|
||||
|
||||
/datum/nanite_program/bad_mood/disable_passive_effect()
|
||||
. = ..()
|
||||
SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_sadness")
|
||||
|
||||
@@ -1,78 +1,30 @@
|
||||
//Programs that interact with other programs or nanites directly, or have other special purposes.
|
||||
/datum/nanite_program/viral
|
||||
name = "Viral Replica"
|
||||
desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters."
|
||||
desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters, also overriding or disabling their cloud sync."
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
extra_settings = list("Program Overwrite","Cloud Overwrite")
|
||||
var/pulse_cooldown = 0
|
||||
|
||||
var/sync_programs = TRUE
|
||||
var/sync_overwrite = FALSE
|
||||
var/overwrite_cloud = FALSE
|
||||
var/set_cloud = 0
|
||||
|
||||
/datum/nanite_program/viral/set_extra_setting(user, setting)
|
||||
if(setting == "Program Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's programs", name) as null|anything in list("Overwrite","Add To","Ignore")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Ignore") //Do not affect programs (if you only want to set the cloud ID)
|
||||
sync_programs = FALSE
|
||||
sync_overwrite = FALSE
|
||||
if("Add To") //Add to existing programs (so the target does not notice theirs are missing)
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = FALSE
|
||||
if("Overwrite") //Replace target's programs with the source
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = TRUE
|
||||
if(setting == "Cloud Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's Cloud ID", name) as null|anything in list("Overwrite","Disable","Keep")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Keep") //Don't change the cloud ID
|
||||
overwrite_cloud = FALSE
|
||||
set_cloud = 0
|
||||
if("Disable") //Set the cloud ID to disabled
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = 0
|
||||
if("Overwrite") //Set the cloud ID to what we choose
|
||||
var/new_cloud = input(user, "Choose the Cloud ID to set on infected nanites (1-100)", name, null) as null|num
|
||||
if(isnull(new_cloud))
|
||||
return
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = CLAMP(round(new_cloud, 1), 1, 100)
|
||||
|
||||
/datum/nanite_program/viral/get_extra_setting(setting)
|
||||
if(setting == "Program Overwrite")
|
||||
if(!sync_programs)
|
||||
return "Ignore"
|
||||
else if(sync_overwrite)
|
||||
return "Overwrite"
|
||||
else
|
||||
return "Add To"
|
||||
if(setting == "Cloud Overwrite")
|
||||
if(!overwrite_cloud)
|
||||
return "None"
|
||||
else if(set_cloud == 0)
|
||||
return "Disable"
|
||||
else
|
||||
return set_cloud
|
||||
|
||||
/datum/nanite_program/viral/copy_extra_settings_to(datum/nanite_program/viral/target)
|
||||
target.overwrite_cloud = overwrite_cloud
|
||||
target.set_cloud = set_cloud
|
||||
target.sync_programs = sync_programs
|
||||
target.sync_overwrite = sync_overwrite
|
||||
/datum/nanite_program/viral/register_extra_settings()
|
||||
extra_settings[NES_PROGRAM_OVERWRITE] = new /datum/nanite_extra_setting/type("Add To", list("Overwrite", "Add To", "Ignore"))
|
||||
extra_settings[NES_CLOUD_OVERWRITE] = new /datum/nanite_extra_setting/number(0, 0, 100)
|
||||
|
||||
/datum/nanite_program/viral/active_effect()
|
||||
if(world.time < pulse_cooldown)
|
||||
return
|
||||
var/datum/nanite_extra_setting/program = extra_settings[NES_PROGRAM_OVERWRITE]
|
||||
var/datum/nanite_extra_setting/cloud = extra_settings[NES_CLOUD_OVERWRITE]
|
||||
for(var/mob/M in orange(host_mob, 5))
|
||||
if(prob(5))
|
||||
if(sync_programs)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
|
||||
if(overwrite_cloud)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
|
||||
if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY))
|
||||
continue
|
||||
switch(program.get_value())
|
||||
if("Overwrite")
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, TRUE)
|
||||
if("Add To")
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, FALSE)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, cloud.get_value())
|
||||
pulse_cooldown = world.time + 75
|
||||
|
||||
/datum/nanite_program/monitoring
|
||||
name = "Monitoring"
|
||||
@@ -89,38 +41,23 @@
|
||||
SSnanites.nanite_monitored_mobs -= host_mob
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
|
||||
/datum/nanite_program/triggered/self_scan
|
||||
/datum/nanite_program/self_scan
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
unique = FALSE
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 50
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Scan Type")
|
||||
var/scan_type = "Medical"
|
||||
/datum/nanite_program/self_scan/register_extra_settings()
|
||||
extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Nanite"))
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/set_extra_setting(user, setting)
|
||||
if(setting == "Scan Type")
|
||||
var/list/scan_types = list("Medical","Chemical","Nanite")
|
||||
var/new_scan_type = input("Choose the scan type", name) as null|anything in scan_types
|
||||
if(!new_scan_type)
|
||||
return
|
||||
scan_type = new_scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/get_extra_setting(setting)
|
||||
if(setting == "Scan Type")
|
||||
return scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/copy_extra_settings_to(datum/nanite_program/triggered/self_scan/target)
|
||||
target.scan_type = scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/self_scan/on_trigger(comm_message)
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
switch(scan_type)
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_SCAN_TYPE]
|
||||
switch(NS.get_value())
|
||||
if("Medical")
|
||||
healthscan(host_mob, host_mob)
|
||||
if("Chemical")
|
||||
@@ -130,7 +67,7 @@
|
||||
|
||||
/datum/nanite_program/stealth
|
||||
name = "Stealth"
|
||||
desc = "The nanites hide their activity and programming from superficial scans."
|
||||
desc = "The nanites mask their activity from superficial scans, becoming undetectable by HUDs and non-specialized scanners."
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
use_rate = 0.2
|
||||
|
||||
@@ -142,27 +79,28 @@
|
||||
. = ..()
|
||||
nanites.stealth = FALSE
|
||||
|
||||
/datum/nanite_program/reduced_diagnostics
|
||||
name = "Reduced Diagnostics"
|
||||
desc = "Disables some high-cost diagnostics in the nanites, making them unable to communicate their program list to portable scanners. \
|
||||
Doing so saves some power, slightly increasing their replication speed."
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
use_rate = -0.1
|
||||
|
||||
/datum/nanite_program/reduced_diagnostics/enable_passive_effect()
|
||||
. = ..()
|
||||
nanites.diagnostics = FALSE
|
||||
|
||||
/datum/nanite_program/reduced_diagnostics/disable_passive_effect()
|
||||
. = ..()
|
||||
nanites.diagnostics = TRUE
|
||||
|
||||
/datum/nanite_program/relay
|
||||
name = "Relay"
|
||||
desc = "The nanites receive and relay long-range nanite signals."
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Relay Channel")
|
||||
var/relay_channel = 1
|
||||
|
||||
/datum/nanite_program/relay/set_extra_setting(user, setting)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/relay/get_extra_setting(setting)
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
|
||||
/datum/nanite_program/relay/copy_extra_settings_to(datum/nanite_program/relay/target)
|
||||
target.relay_channel = relay_channel
|
||||
/datum/nanite_program/relay/register_extra_settings()
|
||||
extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
|
||||
/datum/nanite_program/relay/enable_passive_effect()
|
||||
. = ..()
|
||||
@@ -177,10 +115,21 @@
|
||||
return
|
||||
if(!host_mob)
|
||||
return
|
||||
if(relay_code != relay_channel)
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(relay_code != NS.get_value())
|
||||
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
|
||||
var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL]
|
||||
if(relay_code != NS.get_value())
|
||||
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."
|
||||
@@ -198,14 +147,64 @@
|
||||
host_mob.nutrition -= 0.5
|
||||
nanites.adjust_nanites(src, 0.5)
|
||||
|
||||
/datum/nanite_program/triggered/access
|
||||
/datum/nanite_program/research
|
||||
name = "Distributed Computing"
|
||||
desc = "The nanites aid the research servers by performing a portion of its calculations, increasing research point generation."
|
||||
use_rate = 0.2
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/research/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/points = 1
|
||||
if(!host_mob.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
/datum/nanite_program/researchplus
|
||||
name = "Neural Network"
|
||||
desc = "The nanites link the host's brains together forming a neural research network, that becomes more efficient with the amount of total hosts."
|
||||
use_rate = 0.3
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/researchplus/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count++
|
||||
else
|
||||
SSnanites.neural_network_count += 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/disable_passive_effect()
|
||||
. = ..()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
if(host_mob.client)
|
||||
SSnanites.neural_network_count--
|
||||
else
|
||||
SSnanites.neural_network_count -= 0.25
|
||||
|
||||
/datum/nanite_program/researchplus/active_effect()
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/points = round(SSnanites.neural_network_count / 12, 0.1)
|
||||
if(!C.client) //less brainpower
|
||||
points *= 0.25
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
|
||||
|
||||
/datum/nanite_program/access
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 30
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
var/access = list()
|
||||
|
||||
//Syncs the nanites with the cumulative current mob's access level. Can potentially wipe existing access.
|
||||
/datum/nanite_program/triggered/access/trigger()
|
||||
/datum/nanite_program/access/on_trigger(comm_message)
|
||||
var/list/new_access = list()
|
||||
var/obj/item/current_item
|
||||
current_item = host_mob.get_active_held_item()
|
||||
@@ -232,38 +231,120 @@
|
||||
resulting in an extremely infective strain of nanites."
|
||||
use_rate = 1.50
|
||||
rogue_types = list(/datum/nanite_program/aggressive_replication, /datum/nanite_program/necrotic)
|
||||
var/spread_cooldown = 0
|
||||
|
||||
/datum/nanite_program/spreading/active_effect()
|
||||
if(prob(10))
|
||||
var/list/mob/living/target_hosts = list()
|
||||
for(var/mob/living/L in oview(5, host_mob))
|
||||
if((MOB_SILICON & L.mob_biotypes))
|
||||
continue
|
||||
target_hosts += L
|
||||
if(!target_hosts.len)
|
||||
return
|
||||
var/mob/living/infectee = pick(target_hosts)
|
||||
if(prob(100 - (infectee.get_permeability_protection() * 100)))
|
||||
//this will potentially take over existing nanites!
|
||||
infectee.AddComponent(/datum/component/nanites, 10)
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("[key_name(infectee)] was infected by spreading nanites by [key_name(host_mob)]", INVESTIGATE_NANITES)
|
||||
if(spread_cooldown < world.time)
|
||||
return
|
||||
spread_cooldown = world.time + 50
|
||||
var/list/mob/living/target_hosts = list()
|
||||
for(var/mob/living/L in oview(5, host_mob))
|
||||
if(!prob(25))
|
||||
continue
|
||||
if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)))
|
||||
continue
|
||||
target_hosts += L
|
||||
if(!target_hosts.len)
|
||||
return
|
||||
var/mob/living/infectee = pick(target_hosts)
|
||||
if(prob(100 - (infectee.get_permeability_protection() * 100)))
|
||||
//this will potentially take over existing nanites!
|
||||
infectee.AddComponent(/datum/component/nanites, 10)
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("was infected by spreading nanites by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
|
||||
|
||||
/datum/nanite_program/nanite_sting
|
||||
name = "Nanite Sting"
|
||||
desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 100
|
||||
rogue_types = list(/datum/nanite_program/glitch, /datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/nanite_sting/on_trigger(comm_message)
|
||||
var/list/mob/living/target_hosts = list()
|
||||
for(var/mob/living/L in oview(1, host_mob))
|
||||
if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)) || SEND_SIGNAL(L, COMSIG_HAS_NANITES) || !L.Adjacent(host_mob))
|
||||
continue
|
||||
target_hosts += L
|
||||
if(!target_hosts.len)
|
||||
consume_nanites(-5)
|
||||
return
|
||||
var/mob/living/infectee = pick(target_hosts)
|
||||
if(prob(100 - (infectee.get_permeability_protection() * 100)))
|
||||
//unlike with Infective Exo-Locomotion, this can't take over existing nanites, because Nanite Sting only targets non-hosts.
|
||||
infectee.AddComponent(/datum/component/nanites, 5)
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("was infected by a nanite cluster by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
|
||||
to_chat(infectee, "<span class='warning'>You feel a tiny prick.</span>")
|
||||
|
||||
/datum/nanite_program/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
but it causes occasional software errors due to faulty copies. Not compatible with cloud sync."
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process. Becomes more effective the more nanites are already in the host.\
|
||||
The replication has also a chance to corrupt the nanite programming due to copy faults - cloud sync is highly recommended."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/mitosis/active_effect()
|
||||
if(nanites.cloud_id)
|
||||
return
|
||||
var/rep_rate = round(nanites.nanite_volume / 50, 1) //0.5 per 50 nanite volume
|
||||
rep_rate *= 0.5
|
||||
nanites.adjust_nanites(rep_rate)
|
||||
nanites.adjust_nanites(null, rep_rate)
|
||||
if(prob(rep_rate))
|
||||
var/datum/nanite_program/fault = pick(nanites.programs)
|
||||
if(fault == src)
|
||||
return
|
||||
fault.software_error()
|
||||
|
||||
/datum/nanite_program/dermal_button
|
||||
name = "Dermal Button"
|
||||
desc = "Displays a button on the host's skin, which can be used to send a signal to the nanites."
|
||||
unique = FALSE
|
||||
var/datum/action/innate/nanite_button/button
|
||||
|
||||
/datum/nanite_program/dermal_button/register_extra_settings()
|
||||
extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(1, 1, 9999)
|
||||
extra_settings[NES_BUTTON_NAME] = new /datum/nanite_extra_setting/text("Button")
|
||||
extra_settings[NES_ICON] = new /datum/nanite_extra_setting/type("power", list("one","two","three","four","five","plus","minus","power"))
|
||||
extra_settings[NES_COLOR] = new /datum/nanite_extra_setting/type("green", list("green","red","yellow","blue"))
|
||||
|
||||
/datum/nanite_program/dermal_button/enable_passive_effect()
|
||||
. = ..()
|
||||
var/datum/nanite_extra_setting/bn_name = extra_settings[NES_BUTTON_NAME]
|
||||
var/datum/nanite_extra_setting/bn_icon = extra_settings[NES_ICON]
|
||||
var/datum/nanite_extra_setting/bn_color = extra_settings[NES_COLOR]
|
||||
if(!button)
|
||||
button = new(src, bn_name.get_value(), bn_icon.get_value(), bn_color.get_value())
|
||||
button.target = host_mob
|
||||
button.Grant(host_mob)
|
||||
|
||||
/datum/nanite_program/dermal_button/disable_passive_effect()
|
||||
. = ..()
|
||||
if(button)
|
||||
button.Remove(host_mob)
|
||||
|
||||
/datum/nanite_program/dermal_button/on_mob_remove()
|
||||
. = ..()
|
||||
qdel(button)
|
||||
|
||||
/datum/nanite_program/dermal_button/proc/press()
|
||||
if(activated)
|
||||
host_mob.visible_message("<span class='notice'>[host_mob] presses a button on [host_mob.p_their()] forearm.</span>",
|
||||
"<span class='notice'>You press the nanite button on your forearm.</span>", null, 2)
|
||||
var/datum/nanite_extra_setting/sent_code = extra_settings[NES_SENT_CODE]
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code.get_value(), "a [name] program")
|
||||
|
||||
/datum/action/innate/nanite_button
|
||||
name = "Button"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "power_green"
|
||||
var/datum/nanite_program/dermal_button/program
|
||||
|
||||
/datum/action/innate/nanite_button/New(datum/nanite_program/dermal_button/_program, _name, _icon, _color)
|
||||
..()
|
||||
program = _program
|
||||
name = _name
|
||||
button_icon_state = "[_icon]_[_color]"
|
||||
|
||||
/datum/action/innate/nanite_button/Activate()
|
||||
program.press()
|
||||
|
||||
@@ -73,21 +73,20 @@
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='warning'>Your blood cools down, and the pain gradually fades.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/explosive
|
||||
/datum/nanite_program/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Detonates all the nanites inside the host in a chain reaction when triggered."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 25 //plus every idle nanite left afterwards
|
||||
trigger_cooldown = 100 //Just to avoid double-triggering
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/explosive/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/explosive/on_trigger(comm_message)
|
||||
host_mob.visible_message("<span class='warning'>[host_mob] starts emitting a high-pitched buzzing, and [host_mob.p_their()] skin begins to glow...</span>",\
|
||||
"<span class='userdanger'>You start emitting a high-pitched buzzing, and your skin begins to glow...</span>")
|
||||
addtimer(CALLBACK(src, .proc/boom), CLAMP((nanites.nanite_volume * 0.35), 25, 150))
|
||||
|
||||
/datum/nanite_program/triggered/explosive/proc/boom()
|
||||
/datum/nanite_program/explosive/proc/boom()
|
||||
var/nanite_amount = nanites.nanite_volume
|
||||
var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
|
||||
var/light_range = FLOOR(nanite_amount/50, 1) - 1
|
||||
@@ -96,16 +95,15 @@
|
||||
|
||||
//TODO make it defuse if triggered again
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop
|
||||
/datum/nanite_program/heart_stop
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 12
|
||||
trigger_cooldown = 10
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/heart_stop/on_trigger(comm_message)
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART)
|
||||
@@ -115,16 +113,16 @@
|
||||
else
|
||||
heart.Restart()
|
||||
|
||||
/datum/nanite_program/triggered/emp
|
||||
/datum/nanite_program/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 10
|
||||
trigger_cooldown = 50
|
||||
program_flags = NANITE_EMP_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/emp/trigger()
|
||||
if(!..())
|
||||
return
|
||||
/datum/nanite_program/emp/on_trigger(comm_message)
|
||||
empulse(host_mob, 1, 2)
|
||||
|
||||
/datum/nanite_program/pyro/active_effect()
|
||||
@@ -148,7 +146,7 @@
|
||||
|
||||
/datum/nanite_program/cryo
|
||||
name = "Cryogenic Treatment"
|
||||
desc = "The nanites rapidly skin heat through the host's skin, lowering their temperature."
|
||||
desc = "The nanites rapidly sink heat through the host's skin, lowering their temperature."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/skin_decay, /datum/nanite_program/pyro)
|
||||
|
||||
@@ -160,40 +158,33 @@
|
||||
/datum/nanite_program/cryo/active_effect()
|
||||
host_mob.adjust_bodytemperature(-rand(15,25), 50)
|
||||
|
||||
/datum/nanite_program/mind_control
|
||||
/datum/nanite_program/comm/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
use_rate = 3
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain for one minute when triggered."
|
||||
trigger_cost = 30
|
||||
trigger_cooldown = 1800
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
extra_settings = list("Directive")
|
||||
var/cooldown = 0 //avoids spam when nanites are running low
|
||||
var/directive = "..."
|
||||
/datum/nanite_program/comm/mind_control/register_extra_settings()
|
||||
. = ..()
|
||||
extra_settings[NES_DIRECTIVE] = new /datum/nanite_extra_setting/text("...")
|
||||
|
||||
/datum/nanite_program/mind_control/set_extra_setting(user, setting)
|
||||
if(setting == "Directive")
|
||||
var/new_directive = stripped_input(user, "Choose the directive to imprint with mind control.", "Directive", directive, MAX_MESSAGE_LEN)
|
||||
if(!new_directive)
|
||||
return
|
||||
directive = new_directive
|
||||
|
||||
/datum/nanite_program/mind_control/get_extra_setting(setting)
|
||||
if(setting == "Directive")
|
||||
return directive
|
||||
|
||||
/datum/nanite_program/mind_control/copy_extra_settings_to(datum/nanite_program/mind_control/target)
|
||||
target.directive = directive
|
||||
|
||||
/datum/nanite_program/mind_control/enable_passive_effect()
|
||||
if(world.time < cooldown)
|
||||
/datum/nanite_program/comm/mind_control/on_trigger(comm_message)
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
. = ..()
|
||||
brainwash(host_mob, directive)
|
||||
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
|
||||
var/sent_directive = comm_message
|
||||
if(!comm_message)
|
||||
var/datum/nanite_extra_setting/ES = extra_settings[NES_DIRECTIVE]
|
||||
sent_directive = ES.get_value()
|
||||
brainwash(host_mob, sent_directive)
|
||||
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[sent_directive]'.")
|
||||
addtimer(CALLBACK(src, .proc/end_brainwashing), 600)
|
||||
|
||||
/datum/nanite_program/mind_control/disable_passive_effect()
|
||||
. = ..()
|
||||
/datum/nanite_program/comm/mind_control/proc/end_brainwashing()
|
||||
if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed))
|
||||
host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed)
|
||||
log_game("[key_name(host_mob)] is no longer brainwashed by nanites.")
|
||||
cooldown = world.time + 450
|
||||
|
||||
/datum/nanite_program/comm/mind_control/disable_passive_effect()
|
||||
. = ..()
|
||||
end_brainwashing()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var/last_id = 0
|
||||
var/code = 0
|
||||
var/relay_code = 0
|
||||
var/current_program_name = "Program"
|
||||
|
||||
/obj/item/nanite_remote/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -35,7 +36,6 @@
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/nanite_remote/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
@@ -46,31 +46,30 @@
|
||||
locked = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/nanite_remote/update_icon()
|
||||
/obj/item/nanite_remote/update_overlays()
|
||||
. = ..()
|
||||
cut_overlays()
|
||||
if(obj_flags & EMAGGED)
|
||||
add_overlay("nanite_remote_emagged")
|
||||
. += "nanite_remote_emagged"
|
||||
if(locked)
|
||||
add_overlay("nanite_remote_locked")
|
||||
. += "nanite_remote_locked"
|
||||
|
||||
/obj/item/nanite_remote/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>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.</span>")
|
||||
signal_mob(user, code, key_name(user))
|
||||
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>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].</span>")
|
||||
signal_mob(target, code, 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>")
|
||||
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, key_name(user))
|
||||
if(REMOTE_MODE_RELAY)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.</span>")
|
||||
signal_relay(code, relay_code, key_name(user))
|
||||
|
||||
/obj/item/nanite_remote/proc/signal_mob(mob/living/M, code, source)
|
||||
@@ -82,9 +81,9 @@
|
||||
N.relay_signal(code, relay_code, source)
|
||||
|
||||
/obj/item/nanite_remote/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)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_remote", name, 420, 800, master_ui, state)
|
||||
ui = new(user, src, ui_key, "nanite_remote", name, 420, 500, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_remote/ui_data()
|
||||
@@ -94,6 +93,7 @@
|
||||
data["mode"] = mode
|
||||
data["locked"] = locked
|
||||
data["saved_settings"] = saved_settings
|
||||
data["program_name"] = current_program_name
|
||||
|
||||
return data
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
if("set_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set code (0000-9999):", name, code) as null|num
|
||||
var/new_code = text2num(params["code"])
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
code = new_code
|
||||
@@ -112,21 +112,21 @@
|
||||
if("set_relay_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set relay code (0000-9999):", name, code) as null|num
|
||||
var/new_code = text2num(params["code"])
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
relay_code = new_code
|
||||
. = TRUE
|
||||
if("update_name")
|
||||
current_program_name = params["name"]
|
||||
. = TRUE
|
||||
if("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["name"] = current_program_name
|
||||
new_save["code"] = code
|
||||
new_save["mode"] = mode
|
||||
new_save["relay_code"] = relay_code
|
||||
@@ -166,8 +166,67 @@
|
||||
. = 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_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, 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, 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(code, relay_code, comm_message)
|
||||
|
||||
/obj/item/nanite_remote/comm/ui_data()
|
||||
var/list/data = list()
|
||||
data["comms"] = TRUE
|
||||
data["code"] = code
|
||||
data["relay_code"] = relay_code
|
||||
data["message"] = comm_message
|
||||
data["mode"] = mode
|
||||
data["locked"] = locked
|
||||
data["saved_settings"] = saved_settings
|
||||
data["program_name"] = current_program_name
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_remote/comm/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("set_message")
|
||||
if(locked)
|
||||
return
|
||||
var/new_message = html_encode(params["value"])
|
||||
if(!new_message)
|
||||
return
|
||||
comm_message = new_message
|
||||
. = TRUE
|
||||
|
||||
#undef REMOTE_MODE_OFF
|
||||
#undef REMOTE_MODE_SELF
|
||||
#undef REMOTE_MODE_TARGET
|
||||
#undef REMOTE_MODE_AOE
|
||||
#undef REMOTE_MODE_RELAY
|
||||
#undef REMOTE_MODE_RELAY
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
program_type = /datum/nanite_program/relay
|
||||
|
||||
/obj/item/disk/nanite_program/emp
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
program_type = /datum/nanite_program/emp
|
||||
|
||||
/obj/item/disk/nanite_program/spreading
|
||||
program_type = /datum/nanite_program/spreading
|
||||
@@ -91,16 +91,16 @@
|
||||
program_type = /datum/nanite_program/suffocating
|
||||
|
||||
/obj/item/disk/nanite_program/heart_stop
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
program_type = /datum/nanite_program/heart_stop
|
||||
|
||||
/obj/item/disk/nanite_program/explosive
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
program_type = /datum/nanite_program/explosive
|
||||
|
||||
/obj/item/disk/nanite_program/shock
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
program_type = /datum/nanite_program/shocking
|
||||
|
||||
/obj/item/disk/nanite_program/sleepy
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
program_type = /datum/nanite_program/sleepy
|
||||
|
||||
/obj/item/disk/nanite_program/paralyzing
|
||||
program_type = /datum/nanite_program/paralyzing
|
||||
@@ -130,4 +130,23 @@
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/stun
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
program_type = /datum/nanite_program/stun
|
||||
|
||||
/obj/item/disk/nanite_program/dermal_button
|
||||
program_type = /datum/nanite_program/dermal_button
|
||||
|
||||
/obj/item/disk/nanite_program/research
|
||||
program_type = /datum/nanite_program/research
|
||||
|
||||
/obj/item/disk/nanite_program/researchplus
|
||||
program_type = /datum/nanite_program/researchplus
|
||||
|
||||
/obj/item/disk/nanite_program/reduced_diagnostics
|
||||
program_type = /datum/nanite_program/reduced_diagnostics
|
||||
|
||||
/obj/item/disk/nanite_program/good_mood
|
||||
program_type = /datum/nanite_program/good_mood
|
||||
|
||||
/obj/item/disk/nanite_program/bad_mood
|
||||
program_type = /datum/nanite_program/bad_mood
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
busy_icon_state = working_icon
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/inject_nanites()
|
||||
/obj/machinery/public_nanite_chamber/proc/inject_nanites(mob/living/attacker)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
@@ -47,46 +47,67 @@
|
||||
set_busy(TRUE, "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"),60)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state),80)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state, attacker),80)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state)
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state, mob/living/attacker)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
if(attacker)
|
||||
occupant.investigate_log("was injected with nanites by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
log_combat(attacker, occupant, "injected", null, "with nanites via [src]")
|
||||
occupant.AddComponent(/datum/component/nanites, 75, cloud_id)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/change_cloud(mob/living/attacker)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
set_busy(TRUE, "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"),40)
|
||||
addtimer(CALLBACK(src, .proc/complete_cloud_change, locked_state, attacker),60)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_cloud_change(locked_state, mob/living/attacker)
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
if(attacker)
|
||||
occupant.investigate_log("had their nanite cloud ID changed into [cloud_id] by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/update_icon_state()
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
else
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
/obj/machinery/public_nanite_chamber/power_change()
|
||||
/obj/machinery/public_nanite_chamber/update_overlays()
|
||||
. = ..()
|
||||
update_icon()
|
||||
if((stat & MAINT) || panel_open)
|
||||
. += "maint"
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
. += "red"
|
||||
if(locked)
|
||||
. += "bolted"
|
||||
else
|
||||
. += "green"
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
@@ -94,7 +115,7 @@
|
||||
return
|
||||
|
||||
if(state_open)
|
||||
close_machine()
|
||||
close_machine(null, user)
|
||||
return
|
||||
|
||||
else if(locked)
|
||||
@@ -113,7 +134,7 @@
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
@@ -122,7 +143,7 @@
|
||||
"<span class='notice'>You successfully break out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user)
|
||||
/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user, mob/living/attacker)
|
||||
if(!state_open)
|
||||
return FALSE
|
||||
|
||||
@@ -130,12 +151,15 @@
|
||||
|
||||
. = TRUE
|
||||
|
||||
addtimer(CALLBACK(src, .proc/try_inject_nanites), 30) //If someone is shoved in give them a chance to get out before the injection starts
|
||||
addtimer(CALLBACK(src, .proc/try_inject_nanites, attacker), 30) //If someone is shoved in give them a chance to get out before the injection starts
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/try_inject_nanites()
|
||||
/obj/machinery/public_nanite_chamber/proc/try_inject_nanites(mob/living/attacker)
|
||||
if(occupant)
|
||||
var/mob/living/L = occupant
|
||||
if(SEND_SIGNAL(L, COMSIG_HAS_NANITES))
|
||||
var/datum/component/nanites/nanites = L.GetComponent(/datum/component/nanites)
|
||||
if(nanites && nanites.cloud_id != cloud_id)
|
||||
change_cloud(attacker)
|
||||
return
|
||||
if((MOB_ORGANIC & L.mob_biotypes) || (MOB_UNDEAD & L.mob_biotypes) || (MOB_ROBOTIC & L.mob_biotypes))
|
||||
inject_nanites()
|
||||
@@ -173,6 +197,8 @@
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK) || !Adjacent(target) || !user.Adjacent(target) || !iscarbon(target))
|
||||
return
|
||||
close_machine(target)
|
||||
if(close_machine(target, user))
|
||||
log_combat(user, target, "inserted", null, "into [src].")
|
||||
add_fingerprint(user)
|
||||
|
||||
151
code/modules/research/nanites/rules.dm
Normal file
151
code/modules/research/nanites/rules.dm
Normal file
@@ -0,0 +1,151 @@
|
||||
/datum/nanite_rule
|
||||
var/name = "Generic Condition"
|
||||
var/desc = "When triggered, the program is active"
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/datum/nanite_rule/New(datum/nanite_program/new_program)
|
||||
program = new_program
|
||||
if(LAZYLEN(new_program.rules) <= 5) //Avoid infinite stacking rules
|
||||
new_program.rules += src
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_rule/proc/remove()
|
||||
program.rules -= src
|
||||
program = null
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_rule/proc/check_rule()
|
||||
return TRUE
|
||||
|
||||
/datum/nanite_rule/proc/display()
|
||||
return name
|
||||
|
||||
/datum/nanite_rule/proc/copy_to(datum/nanite_program/new_program)
|
||||
new type(new_program)
|
||||
|
||||
/datum/nanite_rule/health
|
||||
name = "Health"
|
||||
desc = "Checks the host's health status."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
|
||||
/datum/nanite_rule/health/check_rule()
|
||||
var/health_percent = program.host_mob.health / program.host_mob.maxHealth * 100
|
||||
if(above)
|
||||
if(health_percent >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(health_percent < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/health/display()
|
||||
return "[name] [above ? ">" : "<"] [threshold]%"
|
||||
|
||||
/datum/nanite_rule/health/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/health/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
|
||||
//TODO allow inversion
|
||||
/datum/nanite_rule/crit
|
||||
name = "Crit"
|
||||
desc = "Checks if the host is in critical condition."
|
||||
|
||||
/datum/nanite_rule/crit/check_rule()
|
||||
if(program.host_mob.InCritical())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/death
|
||||
name = "Death"
|
||||
desc = "Checks if the host is dead."
|
||||
|
||||
/datum/nanite_rule/death/check_rule()
|
||||
if(program.host_mob.stat == DEAD || HAS_TRAIT(program.host_mob, TRAIT_FAKEDEATH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/cloud_sync
|
||||
name = "Cloud Sync"
|
||||
desc = "Checks if the nanites have cloud sync enabled or disabled."
|
||||
var/check_type = "Enabled"
|
||||
|
||||
/datum/nanite_rule/cloud_sync/check_rule()
|
||||
if(check_type == "Enabled")
|
||||
return program.nanites.cloud_active
|
||||
else
|
||||
return !program.nanites.cloud_active
|
||||
|
||||
/datum/nanite_rule/cloud_sync/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/cloud_sync/rule = new(new_program)
|
||||
rule.check_type = check_type
|
||||
|
||||
/datum/nanite_rule/cloud_sync/display()
|
||||
return "[name]:[check_type]"
|
||||
|
||||
/datum/nanite_rule/nanites
|
||||
name = "Nanite Volume"
|
||||
desc = "Checks the host's nanite volume."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
|
||||
/datum/nanite_rule/nanites/check_rule()
|
||||
var/nanite_percent = (program.nanites.nanite_volume - program.nanites.safety_threshold)/(program.nanites.max_nanites - program.nanites.safety_threshold)*100
|
||||
if(above)
|
||||
if(nanite_percent >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(nanite_percent < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/nanites/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/nanites/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
|
||||
/datum/nanite_rule/nanites/display()
|
||||
return "[name] [above ? ">" : "<"] [threshold]%"
|
||||
|
||||
/datum/nanite_rule/damage
|
||||
name = "Damage"
|
||||
desc = "Checks the host's damage."
|
||||
|
||||
var/threshold = 50
|
||||
var/above = TRUE
|
||||
var/damage_type = BRUTE
|
||||
|
||||
/datum/nanite_rule/damage/check_rule()
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
damage_amt = program.host_mob.getBruteLoss()
|
||||
if(BURN)
|
||||
damage_amt = program.host_mob.getFireLoss()
|
||||
if(TOX)
|
||||
damage_amt = program.host_mob.getToxLoss()
|
||||
if(OXY)
|
||||
damage_amt = program.host_mob.getOxyLoss()
|
||||
if(CLONE)
|
||||
damage_amt = program.host_mob.getCloneLoss()
|
||||
|
||||
if(above)
|
||||
if(damage_amt >= threshold)
|
||||
return TRUE
|
||||
else
|
||||
if(damage_amt < threshold)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_rule/damage/copy_to(datum/nanite_program/new_program)
|
||||
var/datum/nanite_rule/damage/rule = new(new_program)
|
||||
rule.above = above
|
||||
rule.threshold = threshold
|
||||
rule.damage_type = damage_type
|
||||
|
||||
/datum/nanite_rule/damage/display()
|
||||
return "[damage_type] [above ? ">" : "<"] [threshold]"
|
||||
@@ -959,9 +959,9 @@
|
||||
display_name = "Basic Nanite Programming"
|
||||
description = "The basics of nanite construction and programming."
|
||||
prereq_ids = list("datatheory","robotics")
|
||||
design_ids = list("nanite_disk","nanite_remote","nanite_scanner",\
|
||||
design_ids = list("nanite_disk","nanite_remote","nanite_comm_remote","nanite_scanner",\
|
||||
"nanite_chamber","public_nanite_chamber","nanite_chamber_control","nanite_programmer","nanite_program_hub","nanite_cloud_control",\
|
||||
"relay_nanites", "monitoring_nanites", "access_nanites", "repairing_nanites","sensor_nanite_volume", "repeater_nanites", "relay_repeater_nanites")
|
||||
"relay_nanites", "monitoring_nanites", "access_nanites", "repairing_nanites","sensor_nanite_volume", "repeater_nanites", "relay_repeater_nanites","red_diag_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
display_name = "Smart Nanite Programming"
|
||||
description = "Nanite programs that require nanites to perform complex actions, act independently, roam or seek targets."
|
||||
prereq_ids = list("nanite_base","adv_robotics")
|
||||
design_ids = list("purging_nanites", "metabolic_nanites", "stealth_nanites", "memleak_nanites","sensor_voice_nanites", "voice_nanites")
|
||||
design_ids = list("purging_nanites", "research_nanites", "metabolic_nanites", "stealth_nanites", "memleak_nanites","sensor_voice_nanites", "voice_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000)
|
||||
export_price = 4000
|
||||
|
||||
@@ -979,7 +979,7 @@
|
||||
display_name = "Mesh Nanite Programming"
|
||||
description = "Nanite programs that require static structures and membranes."
|
||||
prereq_ids = list("nanite_base","engineering")
|
||||
design_ids = list("hardening_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")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
@@ -998,7 +998,7 @@
|
||||
display_name = "Neural Nanite Programming"
|
||||
description = "Nanite programs affecting nerves and brain matter."
|
||||
prereq_ids = list("nanite_bio")
|
||||
design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites")
|
||||
design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites","good_mood_nanites","bad_mood_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
@@ -1016,7 +1016,7 @@
|
||||
display_name = "Harmonic Nanite Programming"
|
||||
description = "Nanite programs that require seamless integration between nanites and biology."
|
||||
prereq_ids = list("nanite_bio","nanite_smart","nanite_mesh")
|
||||
design_ids = list("fakedeath_nanites","aggressive_nanites","defib_nanites","regenerative_plus_nanites","brainheal_plus_nanites","purging_plus_nanites","adrenaline_nanites")
|
||||
design_ids = list("fakedeath_nanites","researchplus_nanites","aggressive_nanites","defib_nanites","regenerative_plus_nanites","brainheal_plus_nanites","purging_plus_nanites","adrenaline_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
|
||||
export_price = 8000
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 56 KiB |
@@ -2757,7 +2757,6 @@
|
||||
#include "code\modules\research\nanites\nanite_chamber.dm"
|
||||
#include "code\modules\research\nanites\nanite_chamber_computer.dm"
|
||||
#include "code\modules\research\nanites\nanite_cloud_controller.dm"
|
||||
#include "code\modules\research\nanites\nanite_hijacker.dm"
|
||||
#include "code\modules\research\nanites\nanite_misc_items.dm"
|
||||
#include "code\modules\research\nanites\nanite_program_hub.dm"
|
||||
#include "code\modules\research\nanites\nanite_programmer.dm"
|
||||
@@ -2765,6 +2764,12 @@
|
||||
#include "code\modules\research\nanites\nanite_remote.dm"
|
||||
#include "code\modules\research\nanites\program_disks.dm"
|
||||
#include "code\modules\research\nanites\public_chamber.dm"
|
||||
#include "code\modules\research\nanites\rules.dm"
|
||||
#include "code\modules\research\nanites\extra_settings\_extra_setting.dm"
|
||||
#include "code\modules\research\nanites\extra_settings\boolean.dm"
|
||||
#include "code\modules\research\nanites\extra_settings\number.dm"
|
||||
#include "code\modules\research\nanites\extra_settings\text.dm"
|
||||
#include "code\modules\research\nanites\extra_settings\type.dm"
|
||||
#include "code\modules\research\nanites\nanite_programs\buffing.dm"
|
||||
#include "code\modules\research\nanites\nanite_programs\healing.dm"
|
||||
#include "code\modules\research\nanites\nanite_programs\rogue.dm"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -51,6 +51,11 @@ import { LaborClaimConsole } from './interfaces/LaborClaimConsole';
|
||||
import { LanguageMenu } from './interfaces/LanguageMenu';
|
||||
import { LaunchpadConsole, LaunchpadRemote } from './interfaces/Launchpad';
|
||||
import { MechBayPowerConsole } from './interfaces/MechBayPowerConsole';
|
||||
import { NaniteChamberControl } from './interfaces/NaniteChamberControl';
|
||||
import { NaniteCloudControl } from './interfaces/NaniteCloudControl';
|
||||
import { NaniteProgramHub } from './interfaces/NaniteProgramHub';
|
||||
import { NaniteProgrammer } from './interfaces/NaniteProgrammer';
|
||||
import { NaniteRemote } from './interfaces/NaniteRemote';
|
||||
import { Mule } from './interfaces/Mule';
|
||||
import { NotificationPreferences } from './interfaces/NotificationPreferences';
|
||||
import { NtnetRelay } from './interfaces/NtnetRelay';
|
||||
@@ -324,6 +329,26 @@ const ROUTES = {
|
||||
component: () => MechBayPowerConsole,
|
||||
scrollable: false,
|
||||
},
|
||||
nanite_chamber_control: {
|
||||
component: () => NaniteChamberControl,
|
||||
scrollable: true,
|
||||
},
|
||||
nanite_cloud_control: {
|
||||
component: () => NaniteCloudControl,
|
||||
scrollable: true,
|
||||
},
|
||||
nanite_program_hub: {
|
||||
component: () => NaniteProgramHub,
|
||||
scrollable: true,
|
||||
},
|
||||
nanite_programmer: {
|
||||
component: () => NaniteProgrammer,
|
||||
scrollable: true,
|
||||
},
|
||||
nanite_remote: {
|
||||
component: () => NaniteRemote,
|
||||
scrollable: true,
|
||||
},
|
||||
mulebot: {
|
||||
component: () => Mule,
|
||||
scrollable: false,
|
||||
|
||||
File diff suppressed because one or more lines are too long
41
tgui/src/interfaces/nanite_comm_remote.ract
Normal file
41
tgui/src/interfaces/nanite_comm_remote.ract
Normal 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>
|
||||
Reference in New Issue
Block a user