diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index d82444a1d0f30..ec6030c87d9b9 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -334,6 +334,7 @@
//Nanites
#define COMSIG_HAS_NANITES "has_nanites" //() returns TRUE if nanites are found
+#define COMSIG_NANITE_IS_STEALTHY "nanite_is_stealthy" //() returns TRUE if nanites have stealth
#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" //(list/nanite_programs) - makes the input list a copy the nanites' program list
#define COMSIG_NANITE_GET_VOLUME "nanite_get_volume" //(amount) Returns nanite amount
#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" //(amount) Sets current nanite volume to the given amount
diff --git a/code/datums/components/nanites.dm b/code/datums/components/nanites.dm
index 7085092326ae8..b98adba3d6d82 100644
--- a/code/datums/components/nanites.dm
+++ b/code/datums/components/nanites.dm
@@ -36,6 +36,7 @@
/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_UI_DATA, .proc/nanite_ui_data)
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
@@ -60,6 +61,7 @@
/datum/component/nanites/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
+ COMSIG_NANITE_IS_STEALTHY,
COMSIG_NANITE_UI_DATA,
COMSIG_NANITE_GET_PROGRAMS,
COMSIG_NANITE_SET_VOLUME,
@@ -192,6 +194,9 @@
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
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index ecda528cbd8c9..4ad096f9bb70a 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -201,3 +201,10 @@
description = "HE'S CUTTING ME OPEN!!\n"
mood_change = -8
+/datum/mood_event/nanite_sadness
+ description = "+++++++HAPPINESS SUPPRESSION+++++++\n"
+ mood_change = -7
+
+/datum/mood_event/nanite_sadness/add_effects(message)
+ description = "+++++++[message]+++++++\n"
+
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
index 17bad400d17a3..bcf6c6db5c921 100644
--- a/code/datums/mood_events/generic_positive_events.dm
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -158,6 +158,13 @@
mood_change = 2
timeout = 3 MINUTES
+/datum/mood_event/nanite_happiness
+ description = "+++++++HAPPINESS ENHANCEMENT+++++++\n"
+ mood_change = 7
+
+/datum/mood_event/nanite_happiness/add_effects(message)
+ description = "+++++++[message]+++++++\n"
+
/datum/mood_event/area
description = "" //Fill this out in the area
mood_change = 0
diff --git a/code/modules/research/designs/nanite_designs.dm b/code/modules/research/designs/nanite_designs.dm
index 7b9a0805fc97d..d020238dccaeb 100644
--- a/code/modules/research/designs/nanite_designs.dm
+++ b/code/modules/research/designs/nanite_designs.dm
@@ -372,7 +372,7 @@
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/triggered/comm/mind_control
category = list("Weaponized Nanites")
////////////////////SUPPRESSION NANITES//////////////////////////////////////
@@ -454,6 +454,20 @@
program_type = /datum/nanite_program/triggered/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//////////////////////////////////////
/datum/design/nanites/sensor_health
diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm
index 538646c267395..812048cf2e6fc 100644
--- a/code/modules/research/nanites/nanite_programs/healing.dm
+++ b/code/modules/research/nanites/nanite_programs/healing.dm
@@ -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, null, BODYPART_ORGANIC))
+ 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"
@@ -108,7 +108,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()
@@ -133,13 +133,13 @@
return
var/update = FALSE
for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(1/parts.len, 1/parts.len, null, BODYPART_ROBOTIC))
+ 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"
diff --git a/code/modules/research/nanites/nanite_programs/suppression.dm b/code/modules/research/nanites/nanite_programs/suppression.dm
index 8a1bcfb38aaa0..385f23672dfc1 100644
--- a/code/modules/research/nanites/nanite_programs/suppression.dm
+++ b/code/modules/research/nanites/nanite_programs/suppression.dm
@@ -359,3 +359,63 @@
target.hal_type = hal_type
target.hal_details = hal_details
target.comm_code = comm_code
+
+/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)
+ extra_settings = list("Mood Message")
+ var/message = "HAPPINESS ENHANCEMENT"
+
+/datum/nanite_program/good_mood/set_extra_setting(user, setting)
+ if(setting == "Mood Message")
+ var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
+ if(!new_message)
+ return
+ message = new_message
+
+/datum/nanite_program/good_mood/get_extra_setting(setting)
+ if(setting == "Mood Message")
+ return message
+
+/datum/nanite_program/good_mood/copy_extra_settings_to(datum/nanite_program/good_mood/target)
+ target.message = message
+
+/datum/nanite_program/good_mood/enable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, 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)
+ extra_settings = list("Mood Message")
+ var/message = "HAPPINESS SUPPRESSION"
+
+/datum/nanite_program/bad_mood/set_extra_setting(user, setting)
+ if(setting == "Mood Message")
+ var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
+ if(!new_message)
+ return
+ message = new_message
+
+/datum/nanite_program/bad_mood/get_extra_setting(setting)
+ if(setting == "Mood Message")
+ return message
+
+/datum/nanite_program/bad_mood/copy_extra_settings_to(datum/nanite_program/bad_mood/target)
+ target.message = message
+
+/datum/nanite_program/bad_mood/enable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, message)
+
+/datum/nanite_program/bad_mood/disable_passive_effect()
+ . = ..()
+ SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_sadness")
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index 8434a17f820d8..d4af485d475aa 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -6,6 +6,7 @@
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
@@ -67,12 +68,16 @@
target.sync_overwrite = sync_overwrite
/datum/nanite_program/viral/active_effect()
+ if(world.time < pulse_cooldown)
+ return
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
+ if(sync_programs)
+ SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
+ if(overwrite_cloud)
+ SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
+ pulse_cooldown = world.time + 75
/datum/nanite_program/monitoring
name = "Monitoring"
@@ -256,22 +261,27 @@
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(!(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)
+ 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/triggered/nanite_sting
name = "Nanite Sting"
diff --git a/code/modules/research/nanites/nanite_programs/weapon.dm b/code/modules/research/nanites/nanite_programs/weapon.dm
index ef7c6464478e2..a5284b0ce6532 100644
--- a/code/modules/research/nanites/nanite_programs/weapon.dm
+++ b/code/modules/research/nanites/nanite_programs/weapon.dm
@@ -161,40 +161,55 @@
/datum/nanite_program/cryo/active_effect()
host_mob.adjust_bodytemperature(-rand(15,25), 50)
-/datum/nanite_program/mind_control
+/datum/nanite_program/triggered/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
+ extra_settings = list("Directive","Comm Code")
var/directive = "..."
-/datum/nanite_program/mind_control/set_extra_setting(user, setting)
+/datum/nanite_program/triggered/comm/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
+ if(setting == "Comm Code")
+ var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
+ if(isnull(new_code))
+ return
+ comm_code = CLAMP(round(new_code, 1), 0, 9999)
-/datum/nanite_program/mind_control/get_extra_setting(setting)
+/datum/nanite_program/triggered/comm/mind_control/get_extra_setting(setting)
if(setting == "Directive")
return directive
+ if(setting == "Comm Code")
+ return comm_code
-/datum/nanite_program/mind_control/copy_extra_settings_to(datum/nanite_program/mind_control/target)
+/datum/nanite_program/triggered/comm/mind_control/copy_extra_settings_to(datum/nanite_program/triggered/comm/mind_control/target)
target.directive = directive
+ target.comm_code = comm_code
-/datum/nanite_program/mind_control/enable_passive_effect()
- if(world.time < cooldown)
+/datum/nanite_program/triggered/comm/mind_control/trigger(comm_message)
+ if(!..())
return
- . = ..()
- brainwash(host_mob, directive)
+ if(host_mob.stat == DEAD)
+ return
+ var/sent_directive = comm_message
+ if(!comm_message)
+ sent_directive = directive
+ brainwash(host_mob, sent_directive)
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
+ addtimer(CALLBACK(src, .proc/end_brainwashing), 600)
-/datum/nanite_program/mind_control/disable_passive_effect()
- . = ..()
+/datum/nanite_program/triggered/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/triggered/comm/mind_control/disable_passive_effect()
+ . = ..()
+ end_brainwashing()
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index a98c562fa6f2b..486f778f85a6b 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -952,7 +952,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