diff --git a/code/__DEFINES/nanites.dm b/code/__DEFINES/nanites.dm index abd2327dd522..bbedb1ea6530 100644 --- a/code/__DEFINES/nanites.dm +++ b/code/__DEFINES/nanites.dm @@ -29,6 +29,11 @@ ///Nanite Extra Settings - Note that these will also be the names displayed in the UI #define NES_SENT_CODE "Sent Code" +#define NES_SENT_CODE_INVERTED "Sent Code (Inverted)" +#define NES_SENT_CODE_SIGNAL "Sent Code (Signal)" +#define NES_SENT_CODE_SIGNAL_INVERTED "Sent Code (Signal, Inverted)" +#define NES_SENT_CODE_TRIGGER "Sent Code (Trigger)" +#define NES_SENT_CODE_TRIGGER_INVERTED "Sent Code (Trigger, Inverted)" #define NES_DELAY "Delay" #define NES_MODE "Mode" #define NES_COMM_CODE "Comm Code" @@ -36,12 +41,14 @@ #define NES_HEALTH_PERCENT "Health Percent" #define NES_DIRECTION "Direction" #define NES_NANITE_PERCENT "Nanite Percent" +#define NES_BLOOD_PERCENT "Blood Percent" +#define NES_NUTRITION_PERCENT "Nutrition 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_MATCH_MODE "Match Mode" #define NES_RACE "Race" #define NES_HALLUCINATION_TYPE "Hallucination Type" #define NES_HALLUCINATION_DETAIL "Hallucination Detail" diff --git a/monkestation/code/modules/datums/components/nanites.dm b/monkestation/code/modules/datums/components/nanites.dm index 8f700058b4e2..394b9f563612 100644 --- a/monkestation/code/modules/datums/components/nanites.dm +++ b/monkestation/code/modules/datums/components/nanites.dm @@ -61,6 +61,7 @@ if(isliving(parent)) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp)) RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_death)) + RegisterSignal(parent, COMSIG_LIVING_REVIVE, PROC_REF(on_revive)) RegisterSignal(parent, COMSIG_MOB_TRIED_ACCESS, PROC_REF(check_access)) RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(on_shock)) RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(on_minor_shock)) @@ -302,6 +303,12 @@ var/datum/nanite_program/NP = X NP.on_death(gibbed) +/datum/component/nanites/proc/on_revive(datum/source, full_heal, admin_revive) + SIGNAL_HANDLER + + for(var/datum/nanite_program/program in programs) + program.on_revive(full_heal, admin_revive) + /datum/component/nanites/proc/receive_signal(datum/source, code, signal_source = "an unidentified source") SIGNAL_HANDLER diff --git a/monkestation/code/modules/research/designs/nanite_designs.dm b/monkestation/code/modules/research/designs/nanite_designs.dm index a64cc4385b79..17738c1e9494 100644 --- a/monkestation/code/modules/research/designs/nanite_designs.dm +++ b/monkestation/code/modules/research/designs/nanite_designs.dm @@ -80,14 +80,14 @@ name = "Signal Repeater" desc = "When triggered, sends another signal to the nanites, optionally with a delay." id = "repeater_nanites" - program_type = /datum/nanite_program/sensor/repeat + program_type = /datum/nanite_program/repeat category = list("Utility Nanites") /datum/design/nanites/relay_repeater name = "Relay Signal Repeater" desc = "When triggered, sends another signal to a relay channel, optionally with a delay." id = "relay_repeater_nanites" - program_type = /datum/nanite_program/sensor/relay_repeat + program_type = /datum/nanite_program/relay_repeat category = list("Utility Nanites") /datum/design/nanites/emp @@ -478,16 +478,30 @@ program_type = /datum/nanite_program/sensor/damage category = list("Sensor Nanites") +/datum/design/nanites/sensor_blood + name = "Blood Sensor" + desc = "The nanites receive a signal when the host's blood volume is above/below a target percentage." + id = "sensor_blood_nanites" + program_type = /datum/nanite_program/sensor/blood + category = list("Sensor Nanites") + +/datum/design/nanites/sensor_nutrition + name = "Nutrition Sensor" + desc = "The nanites receive a signal when the host's nutrition level is above/below a target percentage." + id = "sensor_nutrition_nanites" + program_type = /datum/nanite_program/sensor/nutrition + category = list("Sensor Nanites") + /datum/design/nanites/sensor_crit name = "Critical Health Sensor" - desc = "The nanites receive a signal when the host first reaches critical health." + desc = "The nanites receive a signal when the host enters/leaves critical condition." id = "sensor_crit_nanites" program_type = /datum/nanite_program/sensor/crit category = list("Sensor Nanites") /datum/design/nanites/sensor_death name = "Death Sensor" - desc = "The nanites receive a signal when they detect the host is dead." + desc = "The nanites receive a signal when the host dies/revives." id = "sensor_death_nanites" program_type = /datum/nanite_program/sensor/death category = list("Sensor Nanites") @@ -508,7 +522,7 @@ /datum/design/nanites/sensor_species name = "Species Sensor" - desc = "When triggered, the nanites scan the host to determine their species and output a signal depending on the conditions set in the settings." + desc = "The nanites receive a singal when they detect that the host is/isn't the target species." id = "sensor_species_nanites" program_type = /datum/nanite_program/sensor/species category = list("Sensor Nanites") diff --git a/monkestation/code/modules/research/nanites/nanite_programs.dm b/monkestation/code/modules/research/nanites/nanite_programs.dm index 0b26b4e79f03..57f25e000ad0 100644 --- a/monkestation/code/modules/research/nanites/nanite_programs.dm +++ b/monkestation/code/modules/research/nanites/nanite_programs.dm @@ -181,12 +181,10 @@ 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) @@ -268,7 +266,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() +/datum/nanite_program/proc/on_death(gibbed) + return + +/datum/nanite_program/proc/on_revive(full_heal, admin_revive) return /datum/nanite_program/proc/software_error(type) @@ -300,6 +301,8 @@ qdel(src) /datum/nanite_program/proc/receive_signal(code, source) + if (!code) // makes code 0 invalid + return if(activation_code && code == activation_code && !activated) activate() host_mob.investigate_log("'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES) @@ -313,6 +316,25 @@ host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES) qdel(src) +/datum/nanite_program/proc/send_code_any(setting) + if (!activated) + return + + var/datum/nanite_extra_setting/code_setting = extra_settings[setting] + SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code_setting.get_value(), "a [name] program") + +/datum/nanite_program/proc/send_code() + send_code_any(NES_SENT_CODE) + +/datum/nanite_program/proc/send_code_inverted() + send_code_any(NES_SENT_CODE_INVERTED) + +/datum/nanite_program/proc/send_trigger_code() + send_code_any(NES_SENT_CODE_TRIGGER) + +/datum/nanite_program/proc/send_trigger_code_inverted() + send_code_any(NES_SENT_CODE_TRIGGER_INVERTED) + ///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once. /datum/nanite_program/protocol name = "Nanite Protocol" diff --git a/monkestation/code/modules/research/nanites/nanite_programs/sensor.dm b/monkestation/code/modules/research/nanites/nanite_programs/sensor.dm index 0f677ee49cb0..a83cf47d76a5 100644 --- a/monkestation/code/modules/research/nanites/nanite_programs/sensor.dm +++ b/monkestation/code/modules/research/nanites/nanite_programs/sensor.dm @@ -2,72 +2,66 @@ name = "Sensor Nanites" desc = "These nanites send a signal code when a certain condition is met." unique = FALSE + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 0.5 SECONDS + var/can_rule = FALSE + var/spent = FALSE + var/spent_inverted = FALSE + var/spendable = TRUE /datum/nanite_program/sensor/register_extra_settings() - extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999) + extra_settings[NES_SENT_CODE_SIGNAL] = new /datum/nanite_extra_setting/number(0, 1, 9999) + extra_settings[NES_SENT_CODE_SIGNAL_INVERTED] = new /datum/nanite_extra_setting/number(0, 1, 9999) + + if (can_trigger) + extra_settings[NES_SENT_CODE_TRIGGER] = new /datum/nanite_extra_setting/number(0, 1, 9999) + extra_settings[NES_SENT_CODE_TRIGGER_INVERTED] = 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) - 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(check_event()) - send_code() + var/event_result = check_event() -/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 - var/spent = FALSE - -/datum/nanite_program/sensor/repeat/register_extra_settings() - . = ..() - extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s") + if (spendable ? check_spent(event_result) : event_result) + send_code() -/datum/nanite_program/sensor/repeat/on_trigger(comm_message) - var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] - addtimer(CALLBACK(src, PROC_REF(send_code)), ES.get_value() * 10) + if (spendable && check_spent_inverted(event_result)) + send_code_inverted() -/datum/nanite_program/sensor/relay_repeat - name = "Relay Signal Repeater" - desc = "When triggered, sends another signal to a relay channel, optionally with a delay." - can_trigger = TRUE - trigger_cost = 0 - trigger_cooldown = 10 - var/spent = FALSE +/datum/nanite_program/sensor/on_trigger(comm_message) + if (check_event()) + send_trigger_code() + else + send_trigger_code_inverted() -/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/proc/make_rule(datum/nanite_program/target) + return -/datum/nanite_program/sensor/relay_repeat/on_trigger(comm_message) - var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] - addtimer(CALLBACK(src, PROC_REF(send_code)), ES.get_value() * 10) +/datum/nanite_program/sensor/proc/check_spent(event_result) + if(check_event()) + if(!spent) + spent = TRUE + return TRUE + return FALSE + spent = FALSE + return FALSE -/datum/nanite_program/sensor/relay_repeat/send_code() - 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 - 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/proc/check_spent_inverted(event_result) + if(!check_event()) + if(!spent_inverted) + spent_inverted = TRUE + return TRUE + return FALSE + spent_inverted = FALSE + return FALSE /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." can_rule = TRUE - var/spent = FALSE /datum/nanite_program/sensor/health/register_extra_settings() . = ..() @@ -78,22 +72,8 @@ 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.get_value()) - if(health_percent >= percent.get_value()) - detected = TRUE - else - if(health_percent < percent.get_value()) - detected = TRUE - if(detected) - if(!spent) - spent = TRUE - return TRUE - return FALSE - else - spent = FALSE - return FALSE + return direction.get_value() == health_percent >= percent.get_value() /datum/nanite_program/sensor/health/make_rule(datum/nanite_program/target) var/datum/nanite_rule/health/rule = new(target) @@ -105,19 +85,17 @@ /datum/nanite_program/sensor/crit name = "Critical Health Sensor" - desc = "The nanites receive a signal when the host first reaches critical health." + desc = "The nanites receive a signal when the host enters/leaves critical condition." can_rule = TRUE - var/spent = FALSE + +/datum/nanite_program/sensor/crit/register_extra_settings() + . = ..() + extra_settings[NES_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Crit", "Stable") /datum/nanite_program/sensor/crit/check_event() - if(HAS_TRAIT(host_mob, TRAIT_CRITICAL_CONDITION)) - if(spent) - return FALSE - spent = TRUE - return TRUE - spent = FALSE - return FALSE + var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] + return mode.get_value() == HAS_TRAIT(host_mob, TRAIT_CRITICAL_CONDITION) /datum/nanite_program/sensor/crit/make_rule(datum/nanite_program/target) var/datum/nanite_rule/crit/rule = new(target) @@ -125,22 +103,29 @@ /datum/nanite_program/sensor/death name = "Death Sensor" - desc = "The nanites receive a signal when they detect the host is dead." + desc = "The nanites receive a signal when the host dies/revives." can_rule = TRUE - var/spent = FALSE -/datum/nanite_program/sensor/death/on_death() - send_code() +/datum/nanite_program/sensor/death/register_extra_settings() + . = ..() + + extra_settings[NES_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Death", "Life") + +/datum/nanite_program/sensor/death/check_event() + var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] + + return mode.get_value() == (host_mob.stat == DEAD) /datum/nanite_program/sensor/death/make_rule(datum/nanite_program/target) var/datum/nanite_rule/death/rule = new(target) + var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] + rule.when_dead = mode.get_value() 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." can_rule = TRUE - var/spent = FALSE /datum/nanite_program/sensor/nanite_volume/register_extra_settings() . = ..() @@ -151,22 +136,8 @@ 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.get_value()) - if(nanite_percent >= percent.get_value()) - detected = TRUE - else - if(nanite_percent < percent.get_value()) - detected = TRUE - if(detected) - if(!spent) - spent = TRUE - return TRUE - return FALSE - else - spent = FALSE - return FALSE + return direction.get_value() == nanite_percent >= percent.get_value() /datum/nanite_program/sensor/nanite_volume/make_rule(datum/nanite_program/target) var/datum/nanite_rule/nanites/rule = new(target) @@ -180,22 +151,27 @@ name = "Damage Sensor" desc = "The nanites receive a signal when a host's specific damage type is above/below a target value." can_rule = TRUE - var/spent = FALSE /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)) + + var/list/damage_list = list() + + for (var/damage_type in list(BRUTE, BURN, TOX, OXY, CLONE, BRAIN)) + damage_list += capitalize(damage_type) + + extra_settings[NES_DAMAGE_TYPE] = new /datum/nanite_extra_setting/type(damage_list[1], damage_list) 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/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/check_above = direction.get_value() var/damage_amt = 0 - switch(type.get_value()) + + switch(lowertext(type.get_value())) if(BRUTE) damage_amt = host_mob.getBruteLoss() if(BURN) @@ -206,22 +182,10 @@ damage_amt = host_mob.getOxyLoss() if(CLONE) damage_amt = host_mob.getCloneLoss() + if(BRAIN) + damage_amt = host_mob.get_organ_loss(ORGAN_SLOT_BRAIN) - if(check_above) - if(damage_amt >= damage.get_value()) - reached_threshold = TRUE - else - if(damage_amt < damage.get_value()) - reached_threshold = TRUE - - if(reached_threshold) - if(!spent) - spent = TRUE - return TRUE - return FALSE - else - spent = FALSE - return FALSE + return check_above == damage_amt >= damage.get_value() /datum/nanite_program/sensor/damage/make_rule(datum/nanite_program/target) var/datum/nanite_rule/damage/rule = new(target) @@ -233,14 +197,78 @@ rule.damage_type = damage_type.get_value() return rule +/datum/nanite_program/sensor/blood + name = "Blood Sensor" + desc = "The nanites receive a signal when the host's blood volume is above/below a target percentage." + can_rule = TRUE + +/datum/nanite_program/sensor/blood/register_extra_settings() + . = ..() + extra_settings[NES_BLOOD_PERCENT] = new /datum/nanite_extra_setting/number(90, 0, 1000, "%") + extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below") + +/datum/nanite_program/sensor/blood/check_event() + var/datum/nanite_extra_setting/blood_percent = extra_settings[NES_BLOOD_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + + var/target_blood_percent = blood_percent.get_value() + var/check_above = direction.get_value() + var/host_blood_percent = host_mob.blood_volume / BLOOD_VOLUME_NORMAL * 100 + + return check_above == host_blood_percent >= target_blood_percent + +/datum/nanite_program/sensor/blood/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/blood/rule = new(target) + + var/datum/nanite_extra_setting/blood_percent = extra_settings[NES_BLOOD_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + + rule.threshold = blood_percent.get_value() + rule.above = direction.get_value() + + return rule + +/datum/nanite_program/sensor/nutrition + name = "Nutrition Sensor" + desc = "The nanites receive a signal when the host's nutrition level is above/below a target percentage." + can_rule = TRUE + +/datum/nanite_program/sensor/nutrition/register_extra_settings() + . = ..() + extra_settings[NES_NUTRITION_PERCENT] = new /datum/nanite_extra_setting/number(90, 0, 1000, "%") + extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below") + +/datum/nanite_program/sensor/nutrition/check_event() + var/datum/nanite_extra_setting/nutrition_percent = extra_settings[NES_NUTRITION_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + + var/target_nutrition_percent = nutrition_percent.get_value() + var/check_above = direction.get_value() + var/host_nutrition_percent = host_mob.nutrition / NUTRITION_LEVEL_FED * 100 + + return check_above == host_nutrition_percent >= target_nutrition_percent + +/datum/nanite_program/sensor/nutrition/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/nutrition/rule = new(target) + + var/datum/nanite_extra_setting/nutrition_percent = extra_settings[NES_NUTRITION_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + + rule.threshold = nutrition_percent.get_value() + rule.above = direction.get_value() + + return rule + /datum/nanite_program/sensor/voice name = "Voice Sensor" desc = "The nanites receive a signal when they detect a specific, preprogrammed word or phrase being said." + spendable = FALSE + can_trigger = FALSE /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") + extra_settings[NES_MATCH_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Includes", "Equals") /datum/nanite_program/sensor/voice/on_mob_add() . = ..() @@ -252,64 +280,77 @@ /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] + var/datum/nanite_extra_setting/match = extra_settings[NES_MATCH_MODE] if(!sentence.get_value()) return - if(inclusive.get_value()) + if(match.get_value()) if(findtext(hearing_args[HEARING_RAW_MESSAGE], sentence.get_value())) send_code() + else + send_code_inverted() else if(lowertext(hearing_args[HEARING_RAW_MESSAGE]) == lowertext(sentence.get_value())) send_code() + else + send_code_inverted() /datum/nanite_program/sensor/species name = "Species Sensor" - desc = "When triggered, the nanites scan the host to determine their species and receive a signal depending on the conditions set in the settings." - can_trigger = TRUE - trigger_cost = 0 - trigger_cooldown = 5 + desc = "The nanites receive a singal when they detect that the host is/isn't the target species." + can_rule = TRUE - var/list/static/allowed_species = list( + var/static/list/species_list = list( "Human" = /datum/species/human, "Lizard" = /datum/species/lizard, "Moth" = /datum/species/moth, "Ethereal" = /datum/species/ethereal, "Pod" = /datum/species/pod, + "Floran" = /datum/species/floran, "Fly" = /datum/species/fly, + "Arachnid" = /datum/species/arachnid, "Jelly" = /datum/species/jelly, + "Oozeling" = /datum/species/oozeling, "IPC" = /datum/species/ipc, + "Monkey" = /datum/species/monkey, "Simian" = /datum/species/simian, + "Zombie" = /datum/species/zombie, + "Shadow" = /datum/species/shadow, ) /datum/nanite_program/sensor/species/register_extra_settings() . = ..() - var/list/species_types = list() - for(var/name in allowed_species) - species_types += name - species_types += "Other" - extra_settings[NES_RACE] = new /datum/nanite_extra_setting/type("Human", species_types) + + var/list/species_names = list() + + for(var/name in species_list) + species_names += name + + species_names += "Other" + + extra_settings[NES_RACE] = new /datum/nanite_extra_setting/type("Human", species_names) extra_settings[NES_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Is", "Is Not") -/datum/nanite_program/sensor/species/on_trigger(comm_message) - var/datum/nanite_extra_setting/species_type = extra_settings[NES_RACE] - var/species = allowed_species[species_type.get_value()] - var/species_match = FALSE - - if(species) - if(is_species(host_mob, species)) - species_match = TRUE - else //this is the check for the "Other" option - species_match = TRUE - for(var/name in allowed_species) - var/species_other = allowed_species[name] - if(is_species(host_mob, species_other)) - species_match = FALSE - break +/datum/nanite_program/sensor/species/check_event() + var/datum/nanite_extra_setting/race = extra_settings[NES_RACE] + var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] + + var/species_type = species_list[race.get_value()] + var/match_species = mode.get_value() + if (!species_type) // "Other" check + for (var/name in species_list) + if (is_species(host_mob, species_type)) + return !match_species + return match_species + + return match_species == is_species(host_mob, species_type) + +/datum/nanite_program/sensor/species/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/species/rule = new(target) + + var/datum/nanite_extra_setting/race = extra_settings[NES_RACE] var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] - if(mode.get_value()) - if(species_match) - send_code() - else - if(!species_match) - send_code() + + rule.when_is_species = mode.get_value() + rule.species_list = species_list + rule.species_name = race.get_value() diff --git a/monkestation/code/modules/research/nanites/nanite_programs/utility.dm b/monkestation/code/modules/research/nanites/nanite_programs/utility.dm index f24f6f5687b5..50752539e754 100644 --- a/monkestation/code/modules/research/nanites/nanite_programs/utility.dm +++ b/monkestation/code/modules/research/nanites/nanite_programs/utility.dm @@ -258,6 +258,49 @@ fault.software_error() host_mob.investigate_log("[fault] nanite program received a software error due to Mitosis program.", INVESTIGATE_NANITES) +/datum/nanite_program/repeat + name = "Signal Repeater" + desc = "When triggered, sends another signal to the nanites, optionally with a delay." + unique = FALSE + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 10 + +/datum/nanite_program/repeat/register_extra_settings() + . = ..() + extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999) + extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s") + +/datum/nanite_program/repeat/on_trigger(comm_message) + var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] + addtimer(CALLBACK(src, PROC_REF(send_code)), ES.get_value() * 10) + +/datum/nanite_program/relay_repeat + name = "Relay Signal Repeater" + desc = "When triggered, sends another signal to a relay channel, optionally with a delay." + unique = FALSE + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 10 + +/datum/nanite_program/relay_repeat/register_extra_settings() + . = ..() + extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999) + 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/relay_repeat/on_trigger(comm_message) + var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] + addtimer(CALLBACK(src, PROC_REF(send_code)), ES.get_value() * 10) + +/datum/nanite_program/relay_repeat/send_code() + 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 + 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/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." diff --git a/monkestation/code/modules/research/nanites/rules.dm b/monkestation/code/modules/research/nanites/rules.dm index 7eb793cd832c..0a70b26567cb 100644 --- a/monkestation/code/modules/research/nanites/rules.dm +++ b/monkestation/code/modules/research/nanites/rules.dm @@ -33,13 +33,8 @@ /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 + + return above == health_percent >= threshold /datum/nanite_rule/health/display() return "[name] [above ? ">" : "<"] [threshold]%" @@ -49,23 +44,37 @@ rule.above = above rule.threshold = threshold -//TODO allow inversion /datum/nanite_rule/crit name = "Crit" desc = "Checks if the host is in critical condition." + var/when_crit = TRUE + /datum/nanite_rule/crit/check_rule() - return HAS_TRAIT(program.host_mob, TRAIT_CRITICAL_CONDITION) + return when_crit == HAS_TRAIT(program.host_mob, TRAIT_CRITICAL_CONDITION) +/datum/nanite_rule/crit/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/crit/rule = new(new_program) + rule.when_crit = when_crit + +/datum/nanite_rule/crit/display() + return when_crit ? name : "Not [name]" /datum/nanite_rule/death name = "Death" desc = "Checks if the host is dead." + var/when_dead = TRUE + /datum/nanite_rule/death/check_rule() - if(program.host_mob.stat == DEAD || HAS_TRAIT(program.host_mob, TRAIT_FAKEDEATH)) - return TRUE - return FALSE + return when_dead == (program.host_mob.stat == DEAD) + +/datum/nanite_rule/death/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/death/rule = new(new_program) + rule.when_dead = when_dead + +/datum/nanite_rule/death/display() + return when_dead ? "Dead" : "Not Dead" /datum/nanite_rule/cloud_sync name = "Cloud Sync" @@ -73,10 +82,7 @@ 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 + return (check_type == "Enabled") == 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) @@ -94,13 +100,8 @@ /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 + + return above == nanite_percent >= threshold /datum/nanite_rule/nanites/copy_to(datum/nanite_program/new_program) var/datum/nanite_rule/nanites/rule = new(new_program) @@ -120,7 +121,8 @@ /datum/nanite_rule/damage/check_rule() var/damage_amt = 0 - switch(damage_type) + + switch(lowertext(damage_type)) if(BRUTE) damage_amt = program.host_mob.getBruteLoss() if(BURN) @@ -131,20 +133,89 @@ damage_amt = program.host_mob.getOxyLoss() if(CLONE) damage_amt = program.host_mob.getCloneLoss() + if(BRAIN) + damage_amt = program.host_mob.get_organ_loss(ORGAN_SLOT_BRAIN) - if(above) - if(damage_amt >= threshold) - return TRUE - else - if(damage_amt < threshold) - return TRUE - return FALSE + return above == damage_amt >= threshold /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]" + +/datum/nanite_rule/blood + name = "Blood" + desc = "Checks the host's blood volume." + + var/threshold = 90 + var/above = TRUE + +/datum/nanite_rule/blood/check_rule() + var/host_blood_percent = program.host_mob.blood_volume / BLOOD_VOLUME_NORMAL * 100 + + return above == host_blood_percent >= threshold + +/datum/nanite_rule/blood/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/blood/rule = new(new_program) + + rule.threshold = threshold + rule.above = above + +/datum/nanite_rule/blood/display() + return "[name] [above ? ">" : "<"] [threshold]%" + +/datum/nanite_rule/nutrition + name = "Nutrition" + desc = "Checks the host's nutrition level." + + var/threshold = 90 + var/above = TRUE + +/datum/nanite_rule/nutrition/check_rule() + var/host_nutrition_percent = program.host_mob.nutrition / NUTRITION_LEVEL_FED * 100 + + return above == host_nutrition_percent >= threshold + +/datum/nanite_rule/nutrition/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/nutrition/rule = new(new_program) + rule.threshold = threshold + rule.above = above + +/datum/nanite_rule/nutrition/display() + return "[name] [above ? ">" : "<"] [threshold]%" + +/datum/nanite_rule/species + name = "Species" + desc = "Checks the host's species." + + var/when_is_species + var/list/species_list + var/species_name + +/datum/nanite_rule/species/check_rule() + var/species_type = species_list[species_name] + + if (!species_type) // "Other" check + for (var/name in species_list) + if (is_species(program.host_mob, species_type)) + return !when_is_species + return when_is_species + + return when_is_species == is_species(program.host_mob, species_type) + +/datum/nanite_rule/species/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/species/rule = new(new_program) + + rule.when_is_species = when_is_species + rule.species_list = species_list + rule.species_name = species_name + + return rule + +/datum/nanite_rule/species/display() + return "[name] [when_is_species ? "Is" : "Isn't"] [species_name]" diff --git a/monkestation/code/modules/research/techweb/all_nodes.dm b/monkestation/code/modules/research/techweb/all_nodes.dm index 7a491327307b..3979855097e1 100644 --- a/monkestation/code/modules/research/techweb/all_nodes.dm +++ b/monkestation/code/modules/research/techweb/all_nodes.dm @@ -79,6 +79,8 @@ "regenerative_nanites", "sensor_crit_nanites", "sensor_damage_nanites", + "sensor_blood_nanites", + "sensor_nutrition_nanites", "sensor_death_nanites", "sensor_health_nanites", "sensor_species_nanites",