Files
Bubberstation/code/modules/research/nanites/nanite_programs/utility.dm
T
4e14d06748 [MIRROR] Fixes infective nanite programs not syncing cloud id (#1576)
* Fixes infective nanite programs not syncing cloud id (#54793)

## About The Pull Request

I have always meant to have infective programs copy over every property of the infector nanites, and i've only recently noticed from some log diving that this wasn't the case, and cloud IDs were defaulting to 0 (unsynced).
I probably never updated it since i made cloud nanites the default, assuming that the AddComponent handled it on its own.
Since an unsynced cloud ID causes constant software errors, this makes the infective programs much less useful than they're meant to be.

**Note: I'd also love to make the infectee's cloud ID a customizable parameter to allow for a wider range of possible uses, but avoided doing so to not violate the feature freeze. I'd gladly add that part if a maintainer gives the ok.**

## Why It's Good For The Game

Makes Viral Replica not obligatory for anyone who wants to use a spreading nanite program. Without it, the cloud IDs of infectees are defaulted to 0, causing degenerative software errors due to lack of cloud sync, which are likely to ruin any gimmick that involves infecting unsuspecting victims.

* Fixes infective nanite programs not syncing cloud id

Co-authored-by: XDTM <heliumt@yahoo.it>
2020-11-06 00:43:15 +00:00

360 lines
13 KiB
Plaintext

//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, also overriding or disabling their cloud sync."
use_rate = 0.5
rogue_types = list(/datum/nanite_program/toxic)
var/pulse_cooldown = 0
/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(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"
desc = "The nanites monitor the host's vitals and location, sending them to the suit sensor network."
rogue_types = list(/datum/nanite_program/toxic)
/datum/nanite_program/monitoring/enable_passive_effect()
. = ..()
ADD_TRAIT(host_mob, TRAIT_NANITE_MONITORING, "nanites") //Shows up in diagnostic and medical HUDs as a small blinking icon
if(ishuman(host_mob))
GLOB.nanite_sensors_list |= host_mob
host_mob.hud_set_nanite_indicator()
/datum/nanite_program/monitoring/disable_passive_effect()
. = ..()
REMOVE_TRAIT(host_mob, TRAIT_NANITE_MONITORING, "nanites")
if(ishuman(host_mob))
GLOB.nanite_sensors_list -= host_mob
host_mob.hud_set_nanite_indicator()
/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)
/datum/nanite_program/self_scan/register_extra_settings()
extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Wound", "Nanite"))
/datum/nanite_program/self_scan/on_trigger(comm_message)
if(host_mob.stat == DEAD)
return
var/datum/nanite_extra_setting/NS = extra_settings[NES_SCAN_TYPE]
switch(NS.get_value())
if("Medical")
healthscan(host_mob, host_mob)
if("Chemical")
chemscan(host_mob, host_mob)
if("Wound")
woundscan(host_mob, host_mob)
if("Nanite")
SEND_SIGNAL(host_mob, COMSIG_NANITE_SCAN, host_mob, TRUE)
/datum/nanite_program/stealth
name = "Stealth"
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
/datum/nanite_program/stealth/enable_passive_effect()
. = ..()
nanites.stealth = TRUE
/datum/nanite_program/stealth/disable_passive_effect()
. = ..()
nanites.stealth = FALSE
/datum/nanite_program/nanite_debugging
name = "Nanite Debugging"
desc = "Enables various high-cost diagnostics in the nanites, making them able to communicate their program list to portable scanners. \
Doing so uses some power, slightly decreasing their replication speed."
rogue_types = list(/datum/nanite_program/toxic)
use_rate = 0.1
/datum/nanite_program/nanite_debugging/enable_passive_effect()
. = ..()
nanites.diagnostics = TRUE
/datum/nanite_program/nanite_debugging/disable_passive_effect()
. = ..()
nanites.diagnostics = FALSE
/datum/nanite_program/relay
name = "Relay"
desc = "The nanites receive and relay long-range nanite signals."
rogue_types = list(/datum/nanite_program/toxic)
/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()
. = ..()
SSnanites.nanite_relays |= src
/datum/nanite_program/relay/disable_passive_effect()
. = ..()
SSnanites.nanite_relays -= src
/datum/nanite_program/relay/proc/relay_signal(code, relay_code, source)
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_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."
use_rate = -0.5 //generates nanites
rogue_types = list(/datum/nanite_program/toxic)
/datum/nanite_program/metabolic_synthesis/check_conditions()
if(!iscarbon(host_mob))
return FALSE
var/mob/living/carbon/C = host_mob
if(C.nutrition <= NUTRITION_LEVEL_WELL_FED)
return FALSE
return ..()
/datum/nanite_program/metabolic_synthesis/active_effect()
host_mob.adjust_nutrition(-0.5)
/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/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()
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()
else if(isanimal(host_mob))
var/mob/living/simple_animal/A = host_mob
current_item = A.access_card
if(current_item)
new_access += current_item.GetAccess()
access = new_access
/datum/nanite_program/spreading
name = "Infective Exo-Locomotion"
desc = "The nanites gain the ability to survive for brief periods outside of the human body, as well as the ability to start new colonies without an integration process; \
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(world.time < spread_cooldown)
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)
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
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)
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."
use_rate = 0
rogue_types = list(/datum/nanite_program/toxic)
/datum/nanite_program/mitosis/active_effect()
var/rep_rate = round(nanites.nanite_volume / 50, 1) //0.5 per 50 nanite volume
rep_rate *= 0.5
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_HANDS_BLOCKED|AB_CHECK_IMMOBILE|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()