Merge pull request #14860 from Arturlang/nanite_updates

Updates our nanite stuff to TG's, mostly
This commit is contained in:
silicons
2021-06-18 20:01:05 -07:00
committed by GitHub
25 changed files with 479 additions and 226 deletions
+11 -12
View File
@@ -502,17 +502,17 @@
return 0
return ..()
/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
return 1
/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1)
if((HAS_TRAIT(src, TRAIT_NOHUNGER) || HAS_TRAIT(src, TRAIT_TOXINLOVER)) && !force)
return TRUE
if(nutrition < 100 && !blood)
if(nutrition < 100 && !blood && !force)
if(message)
visible_message("<span class='warning'>[src] dry heaves!</span>", \
"<span class='userdanger'>You try to throw up, but there's nothing in your stomach!</span>")
if(stun)
DefaultCombatKnockdown(200)
return 1
return TRUE
if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
if(message)
@@ -525,30 +525,29 @@
visible_message("<span class='danger'>[src] throws up!</span>", "<span class='userdanger'>You throw up!</span>")
if(!isflyperson(src))
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
if(stun)
Stun(80)
playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
playsound(get_turf(src), 'sound/effects/splat.ogg', 50, TRUE)
var/turf/T = get_turf(src)
if(!blood)
adjust_nutrition(-lost_nutrition)
adjustToxLoss(-3)
for(var/i=0 to distance)
if(blood)
if(T)
add_splatter_floor(T)
if(stun)
if(harm)
adjustBruteLoss(3)
else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam))
if(T)
T.add_vomit_floor(src, VOMIT_PURPLE)
else
if(T)
T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
T.add_vomit_floor(src, vomit_type, purge_ratio) //toxic barf looks different || call purge when doing detoxicfication to pump more chems out of the stomach.
T = get_step(T, dir)
if (is_blocked_turf(T))
break
return 1
return TRUE
/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
var/list/spillable_organs = list()
@@ -840,8 +840,8 @@
override = dna.species.override_float
..()
/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = 0, stun = 1, distance = 0, message = 1, toxic = 0)
if(blood && dna?.species && (NOBLOOD in dna.species.species_traits))
/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1)
if(blood && dna?.species && (NOBLOOD in dna.species.species_traits) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))
if(message)
visible_message("<span class='warning'>[src] dry heaves!</span>", \
"<span class='userdanger'>You try to throw up, but there's nothing in your stomach!</span>")
@@ -1095,7 +1095,7 @@
* * Rock / Brownish if a golem
* * Green if none of the others apply (aka, generic organic)
*/
/mob/living/carbon/human/proc/spec_trait_examine_font()
/mob/living/carbon/human/proc/spec_trait_examine_font()
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
return "<font color='#aaa9ad'>"
if(HAS_TRAIT(src, TRAIT_TOXINLOVER))
+1 -1
View File
@@ -273,7 +273,7 @@
if(getToxLoss() >= 45 && nutrition > 20 && !HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
lastpuke += prob(50)
if(lastpuke >= 50) // about 25 second delay I guess
vomit(20, toxic = TRUE)
vomit(20)
lastpuke = 0
@@ -2196,7 +2196,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
if(prob(10))
stored_teleports += rand(2,6)
if(prob(70))
M.vomit()
M.vomit(vomit_type = VOMIT_PURPLE)
return ..()
/datum/reagent/consumable/ethanol/planet_cracker
@@ -2516,101 +2516,19 @@ All effects don't start immediately, but rather get worse over time; the rate is
color = "#FFFFFF"
boozepwr = 35
quality = DRINK_GOOD
taste_description = "bad coding"
can_synth = FALSE
var/list/names = list("null fruit" = 1) //Names of the fruits used. Associative list where name is key, value is the percentage of that fruit.
var/list/tastes = list("bad coding" = 1) //List of tastes. See above.
pH = 4
taste_description = "a delightful softened punch"
glass_icon_state = "godfather"
glass_name = "Godfather"
glass_desc = "A classic from old Italy and enjoyed by gangsters, pray the orange peel doesnt end up in your mouth."
/datum/reagent/consumable/ethanol/fruit_wine/on_new(list/data)
names = data["names"]
tastes = data["tastes"]
boozepwr = data["boozepwr"]
color = data["color"]
generate_data_info(data)
/datum/reagent/consumable/ethanol/godmother
name = "Godmother"
description = "A twist on a classic, liked more by mature women."
boozepwr = 50
color = "#E68F00"
quality = DRINK_GOOD
taste_description = "sweetness and a zesty twist"
glass_icon_state = "godmother"
glass_name = "Godmother"
glass_desc = "A lovely fresh smelling cocktail, a true Sicilian delight."
/datum/reagent/consumable/ethanol/fruit_wine/on_merge(list/data, amount)
var/diff = (amount/volume)
if(diff < 1)
color = BlendRGB(color, data["color"], diff/2) //The percentage difference over two, so that they take average if equal.
else
color = BlendRGB(color, data["color"], (1/diff)/2) //Adjust so it's always blending properly.
var/oldvolume = volume-amount
var/list/cachednames = data["names"]
for(var/name in names | cachednames)
names[name] = ((names[name] * oldvolume) + (cachednames[name] * amount)) / volume
var/list/cachedtastes = data["tastes"]
for(var/taste in tastes | cachedtastes)
tastes[taste] = ((tastes[taste] * oldvolume) + (cachedtastes[taste] * amount)) / volume
boozepwr *= oldvolume
var/newzepwr = data["boozepwr"] * amount
boozepwr += newzepwr
boozepwr /= volume //Blending boozepwr to volume.
generate_data_info(data)
/datum/reagent/consumable/ethanol/fruit_wine/proc/generate_data_info(list/data)
var/minimum_percent = 0.15 //Percentages measured between 0 and 1.
var/list/primary_tastes = list()
var/list/secondary_tastes = list()
glass_name = "glass of [name]"
glass_desc = description
for(var/taste in tastes)
switch(tastes[taste])
if(minimum_percent*2 to INFINITY)
primary_tastes += taste
if(minimum_percent to minimum_percent*2)
secondary_tastes += taste
var/minimum_name_percent = 0.35
name = ""
var/list/names_in_order = sortTim(names, /proc/cmp_numeric_dsc, TRUE)
var/named = FALSE
for(var/fruit_name in names)
if(names[fruit_name] >= minimum_name_percent)
name += "[fruit_name] "
named = TRUE
if(named)
name += "wine"
else
name = "mixed [names_in_order[1]] wine"
var/alcohol_description
switch(boozepwr)
if(120 to INFINITY)
alcohol_description = "suicidally strong"
if(90 to 120)
alcohol_description = "rather strong"
if(70 to 90)
alcohol_description = "strong"
if(40 to 70)
alcohol_description = "rich"
if(20 to 40)
alcohol_description = "mild"
if(0 to 20)
alcohol_description = "sweet"
else
alcohol_description = "watery" //How the hell did you get negative boozepwr?
var/list/fruits = list()
if(names_in_order.len <= 3)
fruits = names_in_order
else
for(var/i in 1 to 3)
fruits += names_in_order[i]
fruits += "other plants"
var/fruit_list = english_list(fruits)
description = "A [alcohol_description] wine brewed from [fruit_list]."
var/flavor = ""
if(!primary_tastes.len)
primary_tastes = list("[alcohol_description] alcohol")
flavor += english_list(primary_tastes)
if(secondary_tastes.len)
flavor += ", with a hint of "
flavor += english_list(secondary_tastes)
taste_description = flavor
if(holder.my_atom)
holder.my_atom.on_reagent_change()
@@ -735,7 +735,7 @@
/datum/reagent/toxin/spewium/on_mob_life(mob/living/carbon/C)
.=..()
if(current_cycle >=11 && prob(min(50,current_cycle)))
C.vomit(10, prob(10), prob(50), rand(0,4), TRUE, prob(30))
C.vomit(10, prob(10), prob(50), rand(0,4), TRUE)
for(var/datum/reagent/toxin/R in C.reagents.reagent_list)
if(R != src)
C.reagents.remove_reagent(R.type,1)
@@ -246,8 +246,8 @@
category = list("Augmentation Nanites")
/datum/design/nanites/coagulating
name = "Rapid Coagulation"
desc = "The nanites induce rapid coagulation when the host is wounded, dramatically reducing bleeding rate."
name = "Vein Repressurization"
desc = "The nanites re-route circulating blood away from open wounds, dramatically reducing bleeding rate."
id = "coagulating_nanites"
program_type = /datum/nanite_program/coagulating
category = list("Augmentation Nanites")
@@ -558,15 +558,15 @@
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
/datum/design/nanites/pyramid
name = "Pyramid Protocol"
desc = "Replication Protocol: the nanites implement an alternate cooperative replication protocol that is more efficient as long as the saturation level is above 80%."
id = "pyramid_nanites"
program_type = /datum/nanite_program/protocol/pyramid
category = list("Protocols_Nanites")
/datum/design/nanites/offline
name = "Offline Production Protocol"
name = "Eclipse 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
@@ -578,3 +578,32 @@
id = "synergy_nanites"
program_type = /datum/nanite_program/protocol/synergy
category = list("Protocols_Nanites")
/datum/design/nanites/hive
name = "Hive Protocol"
desc = "Storage Protocol: the nanites use a more efficient grid arrangment for volume storage, increasing maximum volume in a host."
id = "hive_nanites"
program_type = /datum/nanite_program/protocol/hive
category = list("Protocols_Nanites")
/datum/design/nanites/zip
name = "Zip Protocol"
desc = "Storage Protocol: the nanites are disassembled and compacted when unused, greatly increasing the maximum volume while in a host. However, the process slows down the replication rate slightly."
id = "zip_nanites"
program_type = /datum/nanite_program/protocol/zip
category = list("Protocols_Nanites")
/datum/design/nanites/free_range
name = "Free-range Protocol"
desc = "Storage Protocol: the nanites discard their default storage protocols in favour of a cheaper and more organic approach. Reduces maximum volume, but increases the replication rate."
id = "free_range_nanites"
program_type = /datum/nanite_program/protocol/free_range
category = list("Protocols_Nanites")
/datum/design/nanites/unsafe_storage
name = "S.L.O. Protocol"
desc = "Storage Protocol: 'S.L.O.P.', or Storage Level Override Protocol, completely disables the safety measures normally present in nanites,\
allowing them to reach much higher saturation levels, but at the risk of causing internal damage to the host."
id = "unsafe_storage_nanites"
program_type = /datum/nanite_program/protocol/unsafe_storage
category = list("Protocols_Nanites")
@@ -4,6 +4,7 @@
icon = 'icons/obj/machines/research.dmi'
icon_state = "nanite_cloud_controller"
circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
icon_screen = "nanite_cloud_controller_screen"
var/obj/item/disk/nanite_program/disk
var/list/datum/nanite_cloud_backup/cloud_backups = list()
@@ -144,6 +145,7 @@
cloud_program["rules"] = rules
if(LAZYLEN(rules))
cloud_program["has_rules"] = TRUE
cloud_program["all_rules_required"] = P.all_rules_required
var/list/extra_settings = P.get_extra_settings_frontend()
cloud_program["extra_settings"] = extra_settings
@@ -232,6 +234,15 @@
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
. = TRUE
if("toggle_rule_logic")
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
if(backup)
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"])]
P.all_rules_required = !P.all_rules_required
investigate_log("[key_name(usr)] edited rule logic for program [P.name] into [P.all_rules_required ? "All" : "Any"] in cloud #[current_view]", INVESTIGATE_NANITES)
. = TRUE
/datum/nanite_cloud_backup
var/cloud_id = 0
@@ -26,6 +26,14 @@
. = ..()
linked_techweb = SSresearch.science_tech
/obj/machinery/nanite_program_hub/update_overlays()
. = ..()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
if((stat & (NOPOWER|MAINT|BROKEN)) || panel_open)
return
SSvis_overlays.add_vis_overlay(src, icon, "nanite_program_hub_on", layer, plane)
SSvis_overlays.add_vis_overlay(src, icon, "nanite_program_hub_on", EMISSIVE_LAYER, EMISSIVE_PLANE)
/obj/machinery/nanite_program_hub/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/disk/nanite_program))
var/obj/item/disk/nanite_program/N = I
@@ -11,6 +11,14 @@
flags_1 = HEAR_1
circuit = /obj/item/circuitboard/machine/nanite_programmer
/obj/machinery/nanite_programmer/update_overlays()
. = ..()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
if((stat & (NOPOWER|MAINT|BROKEN)) || panel_open)
return
SSvis_overlays.add_vis_overlay(src, icon, "nanite_programmer_on", layer, plane)
SSvis_overlays.add_vis_overlay(src, icon, "nanite_programmer_on", EMISSIVE_LAYER, EMISSIVE_PLANE)
/obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/disk/nanite_program))
var/obj/item/disk/nanite_program/N = I
@@ -48,11 +48,12 @@
//Extra settings
///Don't ever override this or I will come to your house and stand menacingly behind a bush
var/list/extra_settings = list()
VAR_FINAL/list/extra_settings = list()
//Rules
//Rules that automatically manage if the program's active without requiring separate sensor programs
var/list/datum/nanite_rule/rules = list()
var/all_rules_required = TRUE //Whether all rules are required for positive condition or any of specified
/// Corruptable - able to have code/configuration changed
var/corruptable = TRUE
@@ -76,6 +77,9 @@
if(nanites)
nanites.programs -= src
nanites.permanent_programs -= src
for(var/datum/nanite_rule/rule as anything in rules)
rule.remove()
rules.Cut()
return ..()
/**
@@ -108,6 +112,7 @@
for(var/R in rules)
var/datum/nanite_rule/rule = R
rule.copy_to(target)
target.all_rules_required = all_rules_required
if(istype(target,src))
copy_extra_settings_to(target)
@@ -186,14 +191,17 @@
if(timer_shutdown_next && world.time > timer_shutdown_next)
deactivate()
timer_shutdown_next = 0
return
if(timer_trigger && world.time > timer_trigger_next)
trigger()
timer_trigger_next = world.time + timer_trigger
return
if(timer_trigger_delay_next && world.time > timer_trigger_delay_next)
trigger(delayed = TRUE)
timer_trigger_delay_next = 0
return
if(check_conditions() && consume_nanites(use_rate))
if(!passive_enabled)
@@ -203,14 +211,18 @@
if(passive_enabled)
disable_passive_effect()
//If false, disables active and passive effects, but doesn't consume nanites
//If false, disables active, passive effects, and triggers without consuming nanites
//Can be used to avoid consuming nanites for nothing
/datum/nanite_program/proc/check_conditions()
if (!LAZYLEN(rules))
return TRUE
for(var/R in rules)
var/datum/nanite_rule/rule = R
if(!rule.check_rule())
if(!all_rules_required && rule.check_rule())
return TRUE
if(all_rules_required && !rule.check_rule())
return FALSE
return TRUE
return all_rules_required ? TRUE : FALSE
//Constantly procs as long as the program is active
/datum/nanite_program/proc/active_effect()
@@ -235,6 +247,8 @@
return
if(world.time < next_trigger)
return
if(!check_conditions())
return
if(!consume_nanites(trigger_cost))
return
next_trigger = world.time + trigger_cooldown
@@ -251,18 +265,22 @@
if(program_flags & NANITE_EMP_IMMUNE)
return
if(prob(severity / 2))
host_mob.investigate_log("[src] nanite program received a software error due to emp.", INVESTIGATE_NANITES)
software_error()
/datum/nanite_program/proc/on_shock(shock_damage)
if(!(program_flags & NANITE_SHOCK_IMMUNE))
if(prob(10))
host_mob.investigate_log("[src] nanite program received a software error due to shock.", INVESTIGATE_NANITES)
software_error()
else if(prob(33))
host_mob.investigate_log("[src] nanite program was deleted due to shock.", INVESTIGATE_NANITES)
self_destruct()
/datum/nanite_program/proc/on_minor_shock()
if(!(program_flags & NANITE_SHOCK_IMMUNE))
if(prob(10))
host_mob.investigate_log("[src] nanite program received a software error due to minor shock.", INVESTIGATE_NANITES)
software_error()
/datum/nanite_program/proc/on_death()
@@ -273,10 +291,12 @@
type = rand(1,is_permanent()? 4 : 5)
switch(type)
if(1)
self_destruct() //kill switch
host_mob.investigate_log("[src] nanite program was deleted by software error.", INVESTIGATE_NANITES)
qdel(src) //kill switch
return
if(2) //deprogram codes
if(corruptable)
host_mob.investigate_log("[src] nanite program was de-programmed by software error.", INVESTIGATE_NANITES)
activation_code = 0
deactivation_code = 0
kill_code = 0
@@ -284,15 +304,18 @@
if(3)
if(error_flicking)
toggle() //enable/disable
host_mob.investigate_log("[src] nanite program was toggled by software error.", INVESTIGATE_NANITES)
if(4)
if(error_flicking && can_trigger)
if(can_trigger)
host_mob.investigate_log("[src] nanite program was triggered by software error.", INVESTIGATE_NANITES)
trigger()
if(5) //Program is scrambled and does something different
if(corruptable)
var/rogue_type = pick(rogue_types)
var/datum/nanite_program/rogue = new rogue_type
host_mob.investigate_log("[src] nanite program was converted into [rogue.name] by software error.", INVESTIGATE_NANITES)
nanites.add_program(null, rogue, src)
self_destruct()
self_destruct(src)
/datum/nanite_program/proc/receive_signal(code, source)
if(activation_code && code == activation_code && !activated)
@@ -315,9 +338,7 @@
if(is_permanent())
return
qdel(src)
///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once.
//Moved to being 'normally' researched due to lack of B.E.P.I.S.
/datum/nanite_program/protocol
name = "Nanite Protocol"
var/protocol_class = NONE
@@ -337,4 +358,3 @@
if(nanites)
nanites.protocols -= src
return ..()
@@ -2,7 +2,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."
desc = "The nanites boost the host's natural regeneration, increasing their healing speed. Will not consume nanites while the host is unharmed."
use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
@@ -31,7 +31,7 @@
/datum/nanite_program/temperature
name = "Temperature Adjustment"
desc = "The nanites adjust the host's internal temperature to an ideal level."
desc = "The nanites adjust the host's internal temperature to an ideal level. Will not consume nanites while the host is at a normal body temperature."
use_rate = 3.5
rogue_types = list(/datum/nanite_program/skin_decay)
@@ -53,10 +53,12 @@
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
/datum/nanite_program/purging/check_conditions()
. = ..()
if(!. || !host_mob.reagents)
return FALSE // No trying to purge simple mobs
var/foreign_reagent = length(host_mob.reagents?.reagent_list)
if(!host_mob.getToxLoss() && !foreign_reagent)
return FALSE
return ..()
/datum/nanite_program/purging/active_effect()
host_mob.adjustToxLoss(-1)
@@ -68,7 +70,7 @@
/datum/nanite_program/brain_heal
name = "Neural Regeneration"
desc = "The nanites fix neural connections in the host's brain, reversing brain damage and minor traumas."
desc = "The nanites fix neural connections in the host's brain, reversing brain damage and minor traumas. Will not consume nanites while it would not have an effect."
use_rate = 1.5
rogue_types = list(/datum/nanite_program/brain_decay)
@@ -91,7 +93,7 @@
/datum/nanite_program/blood_restoring
name = "Blood Regeneration"
desc = "The nanites stimulate and boost blood cell production in the host."
desc = "The nanites stimulate and boost blood cell production in the host. Will not consume nanites while the host has a safe blood level."
use_rate = 1
rogue_types = list(/datum/nanite_program/suffocating)
@@ -111,7 +113,7 @@
/datum/nanite_program/repairing
name = "Mechanical Repair"
desc = "The nanites fix damage in the host's mechanical limbs."
desc = "The nanites fix damage in the host's mechanical limbs. Will not consume nanites while the host's mechanical limbs are undamaged, or while the host has no mechanical limbs."
use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
@@ -153,13 +155,15 @@
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
/datum/nanite_program/purging_advanced/check_conditions()
. = ..()
if(!. || !host_mob.reagents)
return FALSE
var/foreign_reagent = FALSE
for(var/datum/reagent/toxin/R in host_mob.reagents.reagent_list)
foreign_reagent = TRUE
break
if(!host_mob.getToxLoss() && !foreign_reagent)
return FALSE
return ..()
/datum/nanite_program/purging_advanced/active_effect()
host_mob.adjustToxLoss(-1, forced = TRUE)
@@ -1,7 +1,8 @@
//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."
desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation, \
resulting in an additional 420 nanite volume being produced during the first two minutes."
use_rate = 0
rogue_types = list(/datum/nanite_program/necrotic)
protocol_class = NANITE_PROTOCOL_REPLICATION
@@ -17,8 +18,9 @@
/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."
desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time, \
granting a maximum of 2 additional nanite production after roughly 17 minutes. \
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
@@ -46,43 +48,26 @@
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."
/datum/nanite_program/protocol/pyramid
name = "Pyramid Protocol"
desc = "Replication Protocol: the nanites implement an alternate cooperative replication protocol that is active as long as the nanite saturation level is above 80%, \
resulting in an additional volume production of 1.2 per second."
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)
var/boost = 1.2
/datum/nanite_program/protocol/tinker/check_conditions()
if(!nanites.host_mob.reagents)
/datum/nanite_program/protocol/pyramid/check_conditions()
if((nanites.nanite_volume / nanites.max_nanites) < 0.8)
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()
/datum/nanite_program/protocol/pyramid/active_effect()
nanites.adjust_nanites(null, boost)
/datum/nanite_program/protocol/offline
name = "Offline Production Protocol"
name = "Eclipse 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)
@@ -105,7 +90,6 @@
/datum/nanite_program/protocol/offline/active_effect()
nanites.adjust_nanites(null, boost)
/datum/nanite_program/protocol/synergy
name = "Synergy Protocol"
desc = "Replication Protocol: the nanites syncronize their tasks and processes within a host, leading to an increase in replication speed proportional to the current nanite volume."
@@ -116,3 +100,195 @@
/datum/nanite_program/protocol/synergy/active_effect()
nanites.adjust_nanites(null, round(max_boost * (nanites.nanite_volume / nanites.max_nanites), 0.1))
/datum/nanite_program/protocol/hive
name = "Hive Protocol"
desc = "Storage Protocol: the nanites use a more efficient grid arrangment for volume storage, increasing maximum volume to 750."
use_rate = 0
rogue_types = list(/datum/nanite_program/necrotic)
protocol_class = NANITE_PROTOCOL_STORAGE
var/extra_volume = 250
/datum/nanite_program/protocol/hive/enable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites + extra_volume)
/datum/nanite_program/protocol/hive/disable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites - extra_volume)
/datum/nanite_program/protocol/zip
name = "Zip Protocol"
desc = "Storage Protocol: the nanites are disassembled and compacted when unused, increasing the maximum volume to 1000. However, the process slows down their replication rate slightly."
use_rate = 0.2
rogue_types = list(/datum/nanite_program/necrotic)
protocol_class = NANITE_PROTOCOL_STORAGE
var/extra_volume = 500
/datum/nanite_program/protocol/zip/enable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites + extra_volume)
/datum/nanite_program/protocol/zip/disable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites - extra_volume)
/datum/nanite_program/protocol/free_range
name = "Free-range Protocol"
desc = "Storage Protocol: the nanites discard their default storage protocols in favour of a cheaper and more organic approach. Reduces maximum volume to 250, but increases the replication rate by 0.5."
use_rate = 0
rogue_types = list(/datum/nanite_program/necrotic)
protocol_class = NANITE_PROTOCOL_STORAGE
var/boost = 0.5
var/extra_volume = -250
/datum/nanite_program/protocol/free_range/enable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites + extra_volume)
/datum/nanite_program/protocol/free_range/disable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites - extra_volume)
/datum/nanite_program/protocol/free_range/active_effect()
nanites.adjust_nanites(null, boost)
/datum/nanite_program/protocol/unsafe_storage
name = "S.L.O. Protocol"
desc = "Storage Protocol: 'S.L.O.P.', or Storage Level Override Protocol, completely disables the safety measures normally present in nanites, \
allowing them to reach a whopping maximum volume level of 2000, but at the risk of causing damage to the host at nanite concentrations above the standard limit of 500."
use_rate = 0
rogue_types = list(/datum/nanite_program/necrotic)
protocol_class = NANITE_PROTOCOL_STORAGE
var/extra_volume = 1500
var/next_warning = 0
var/min_warning_cooldown = 120
var/max_warning_cooldown = 350
var/volume_warnings_stage_1 = list("You feel a dull pain in your abdomen.",
"You feel a tickling sensation in your abdomen.")
var/volume_warnings_stage_2 = list("You feel a dull pain in your stomach.",
"You feel a dull pain when breathing.",
"Your stomach grumbles.",
"You feel a tickling sensation in your throat.",
"You feel a tickling sensation in your lungs.",
"You feel a tickling sensation in your stomach.",
"Your lungs feel stiff.")
var/volume_warnings_stage_3 = list("You feel a dull pain in your chest.",
"You hear a faint buzzing coming from nowhere.",
"You hear a faint buzzing inside your head.",
"Your head aches.")
var/volume_warnings_stage_4 = list("You feel a dull pain in your ears.",
"You feel a dull pain behind your eyes.",
"You hear a loud, echoing buzz inside your ears.",
"You feel dizzy.",
"You feel an itch coming from behind your eyes.",
"Your eardrums itch.",
"You see tiny grey motes drifting in your field of view.")
var/volume_warnings_stage_5 = list("You feel sick.",
"You feel a dull pain from every part of your body.",
"You feel nauseous.")
var/volume_warnings_stage_6 = list("Your skin itches and burns.",
"Your muscles ache.",
"You feel tired.",
"You feel something skittering under your skin.",)
/datum/nanite_program/protocol/unsafe_storage/enable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites + extra_volume)
/datum/nanite_program/protocol/unsafe_storage/disable_passive_effect()
. = ..()
nanites.set_max_volume(null, nanites.max_nanites - extra_volume)
/datum/nanite_program/protocol/unsafe_storage/active_effect()
if(!iscarbon(host_mob))
if(prob(10))
host_mob.adjustBruteLoss(((max(nanites.nanite_volume - 450, 0) / 450) ** 2 ) * 0.5) // 0.5 -> 2 -> 4.5 -> 8 damage per successful tick
return
var/mob/living/carbon/C = host_mob
if(nanites.nanite_volume < 500)
return
var/current_stage = 0
if(nanites.nanite_volume > 500) //Liver is the main hub of nanite replication and the first to be threatened by excess volume
if(prob(10))
var/obj/item/organ/liver/liver = C.getorganslot(ORGAN_SLOT_LIVER)
if(liver)
liver.applyOrganDamage(0.6)
current_stage++
if(nanites.nanite_volume > 750) //Extra volume spills out in other central organs
if(prob(10))
var/obj/item/organ/stomach/stomach = C.getorganslot(ORGAN_SLOT_STOMACH)
if(stomach)
stomach.applyOrganDamage(0.75)
if(prob(10))
var/obj/item/organ/lungs/lungs = C.getorganslot(ORGAN_SLOT_LUNGS)
if(lungs)
lungs.applyOrganDamage(0.75)
current_stage++
if(nanites.nanite_volume > 1000) //Extra volume spills out in more critical organs
if(prob(10))
var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART)
if(heart)
heart.applyOrganDamage(0.75)
if(prob(10))
var/obj/item/organ/brain/brain = C.getorganslot(ORGAN_SLOT_BRAIN)
if(brain)
brain.applyOrganDamage(0.75)
current_stage++
if(nanites.nanite_volume > 1250) //Excess nanites start invading smaller organs for more space, including sensory organs
if(prob(13))
var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.applyOrganDamage(0.75)
if(prob(13))
var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS)
if(ears)
ears.applyOrganDamage(0.75)
current_stage++
if(nanites.nanite_volume > 1500) //Nanites start spilling into the bloodstream, causing toxicity
if(prob(15))
C.adjustToxLoss(0.5, TRUE, forced = TRUE) //Not healthy for slimepeople either
current_stage++
if(nanites.nanite_volume > 1750) //Nanites have almost reached their physical limit, and the pressure itself starts causing tissue damage
if(prob(15))
C.adjustBruteLoss(0.75, TRUE)
current_stage++
volume_warning(current_stage)
/datum/nanite_program/protocol/unsafe_storage/proc/volume_warning(tier)
if(world.time < next_warning)
return
var/list/main_warnings
var/list/extra_warnings
switch(tier)
if(1)
main_warnings = volume_warnings_stage_1
extra_warnings = null
if(2)
main_warnings = volume_warnings_stage_2
extra_warnings = volume_warnings_stage_1
if(3)
main_warnings = volume_warnings_stage_3
extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2
if(4)
main_warnings = volume_warnings_stage_4
extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3
if(5)
main_warnings = volume_warnings_stage_5
extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3 + volume_warnings_stage_4
if(6)
main_warnings = volume_warnings_stage_6
extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3 + volume_warnings_stage_4 + volume_warnings_stage_5
if(prob(35))
to_chat(host_mob, "<span class='warning'>[pick(main_warnings)]</span>")
next_warning = world.time + rand(min_warning_cooldown, max_warning_cooldown)
else if(islist(extra_warnings))
to_chat(host_mob, "<span class='warning'>[pick(extra_warnings)]</span>")
next_warning = world.time + rand(min_warning_cooldown, max_warning_cooldown)
@@ -235,8 +235,7 @@
/datum/nanite_program/sensor/voice
name = "Voice Sensor"
desc = "Sends a signal when the nanites hear a determined word or sentence."
var/spent = FALSE
desc = "The nanites receive a signal when they detect a specific, preprogrammed word or phrase being said."
/datum/nanite_program/sensor/voice/register_extra_settings()
. = ..()
@@ -248,16 +247,17 @@
RegisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear)
/datum/nanite_program/sensor/voice/on_mob_remove()
UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear)
UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR)
/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args)
SIGNAL_HANDLER
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.get_value())
if(findtextEx(hearing_args[HEARING_RAW_MESSAGE], sentence))
if(findtext(hearing_args[HEARING_RAW_MESSAGE], sentence.get_value()))
send_code()
else
if(hearing_args[HEARING_RAW_MESSAGE] == sentence)
if(lowertext(hearing_args[HEARING_RAW_MESSAGE]) == lowertext(sentence.get_value()))
send_code()
@@ -2,7 +2,7 @@
/datum/nanite_program/sleepy
name = "Sleep Induction"
desc = "The nanites cause rapid narcolepsy when triggered."
desc = "The nanites induce rapid narcolepsy when triggered."
can_trigger = TRUE
trigger_cost = 15
trigger_cooldown = 1200
@@ -116,13 +116,13 @@
//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)
var/datum/nanite_extra_setting/comm_code = extra_settings[NES_COMM_CODE]
if(!activated || !comm_code)
return
if(signal_comm_code == comm_code)
@@ -138,7 +138,8 @@
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
var/static/list/blacklist = list(
"*surrender",
"*collapse"
"*collapse",
"*faint",
)
/datum/nanite_program/comm/speech/register_extra_settings()
@@ -207,24 +207,23 @@
//Syncs the nanites with the cumulative current mob's access level. Can potentially wipe existing access.
/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()
if(current_item)
new_access += current_item.GetAccess()
current_item = host_mob.get_inactive_held_item()
if(current_item)
new_access += current_item.GetAccess()
var/list/potential_items = list()
potential_items += host_mob.get_active_held_item()
potential_items += host_mob.get_inactive_held_item()
if(ishuman(host_mob))
var/mob/living/carbon/human/H = host_mob
current_item = H.wear_id
if(current_item)
new_access += current_item.GetAccess()
potential_items += H.wear_id
else if(isanimal(host_mob))
potential_items += host_mob.pulling
var/mob/living/simple_animal/A = host_mob
current_item = A.access_card
if(current_item)
new_access += current_item.GetAccess()
potential_items += A.access_card
var/list/new_access = list()
for(var/obj/item/I in potential_items)
new_access += I.GetAccess()
access = new_access
/datum/nanite_program/spreading
@@ -253,6 +252,7 @@
//this will potentially take over existing nanites!
infectee.AddComponent(/datum/component/nanites, 10)
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
SEND_SIGNAL(infectee, COMSIG_NANITE_SET_CLOUD, nanites.cloud_id)
infectee.investigate_log("was infected by spreading nanites by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
/datum/nanite_program/nanite_sting
@@ -277,13 +277,15 @@
//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)
SEND_SIGNAL(infectee, COMSIG_NANITE_SET_CLOUD, nanites.cloud_id)
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. 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."
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; \
For every 50 nanite volume in the host, the production rate is increased by 0.5. The replication has also a chance to corrupt the nanite programming \
due to copy faults - constant cloud sync is highly recommended."
use_rate = 0
rogue_types = list(/datum/nanite_program/toxic)
@@ -306,16 +308,14 @@
/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"))
extra_settings[NES_ICON] = new /datum/nanite_extra_setting/type("power", list("blank","one","two","three","four","five","plus","minus","exclamation","question","cross","info","heart","skull","brain","brain_damage","injection","blood","shield","reaction","network","power","radioactive","electricity","magnetism","scan","repair","id","wireless","say","sleep","bomb"))
/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 = new(src, bn_name.get_value(), bn_icon.get_value())
button.target = host_mob
button.Grant(host_mob)
@@ -339,14 +339,14 @@
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"
button_icon_state = "nanite_power"
var/datum/nanite_program/dermal_button/program
/datum/action/innate/nanite_button/New(datum/nanite_program/dermal_button/_program, _name, _icon, _color)
/datum/action/innate/nanite_button/New(datum/nanite_program/dermal_button/_program, _name, _icon)
..()
program = _program
name = _name
button_icon_state = "[_icon]_[_color]"
button_icon_state = "nanite_[_icon]"
/datum/action/innate/nanite_button/Activate()
program.press()
@@ -45,8 +45,8 @@
/datum/nanite_program/aggressive_replication
name = "Aggressive Replication"
desc = "Nanites will consume organic matter to improve their replication rate, damaging the host. The efficiency increases with the volume of nanites, requiring 200 to break even."
use_rate = 0
desc = "Nanites will consume organic matter to improve their replication rate, damaging the host. The efficiency increases with the volume of nanites, requiring 200 to break even, \
and scaling linearly for a net positive of 0.1 production rate per 20 nanite volume beyond that."
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/aggressive_replication/active_effect()
@@ -87,11 +87,8 @@
addtimer(CALLBACK(src, .proc/boom), clamp((nanites.nanite_volume * 0.35), 25, 150))
/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
explosion(host_mob, 0, heavy_range, light_range)
nanites.delete_nanites()
dyn_explosion(get_turf(host_mob), nanites.nanite_volume / 50)
qdel(nanites)
//TODO make it defuse if triggered again