@@ -20,8 +20,11 @@
|
||||
#define DIAG_PATH_HUD "16"//Bot path indicators
|
||||
#define GLAND_HUD "17"//Gland indicators for abductors
|
||||
#define SENTIENT_DISEASE_HUD "18"
|
||||
#define AI_DETECT_HUD "19"
|
||||
#define NANITE_HUD "20"
|
||||
#define DIAG_NANITE_FULL_HUD "21"
|
||||
//for antag huds. these are used at the /mob level
|
||||
#define ANTAG_HUD "19"
|
||||
#define ANTAG_HUD "22"
|
||||
|
||||
//by default everything in the hud_list of an atom is an image
|
||||
//a value in hud_list with one of these will change that behavior
|
||||
@@ -37,22 +40,23 @@
|
||||
#define DATA_HUD_DIAGNOSTIC_ADVANCED 6
|
||||
#define DATA_HUD_ABDUCTOR 7
|
||||
#define DATA_HUD_SENTIENT_DISEASE 8
|
||||
#define DATA_HUD_AI_DETECT 9
|
||||
|
||||
//antag HUD defines
|
||||
#define ANTAG_HUD_CULT 9
|
||||
#define ANTAG_HUD_REV 10
|
||||
#define ANTAG_HUD_OPS 11
|
||||
#define ANTAG_HUD_WIZ 12
|
||||
#define ANTAG_HUD_SHADOW 13
|
||||
#define ANTAG_HUD_TRAITOR 14
|
||||
#define ANTAG_HUD_NINJA 15
|
||||
#define ANTAG_HUD_CHANGELING 16
|
||||
#define ANTAG_HUD_ABDUCTOR 17
|
||||
#define ANTAG_HUD_DEVIL 18
|
||||
#define ANTAG_HUD_SINTOUCHED 19
|
||||
#define ANTAG_HUD_SOULLESS 20
|
||||
#define ANTAG_HUD_CLOCKWORK 21
|
||||
#define ANTAG_HUD_BROTHER 22
|
||||
#define ANTAG_HUD_CULT 10
|
||||
#define ANTAG_HUD_REV 11
|
||||
#define ANTAG_HUD_OPS 12
|
||||
#define ANTAG_HUD_WIZ 13
|
||||
#define ANTAG_HUD_SHADOW 14
|
||||
#define ANTAG_HUD_TRAITOR 15
|
||||
#define ANTAG_HUD_NINJA 16
|
||||
#define ANTAG_HUD_CHANGELING 17
|
||||
#define ANTAG_HUD_ABDUCTOR 18
|
||||
#define ANTAG_HUD_DEVIL 19
|
||||
#define ANTAG_HUD_SINTOUCHED 20
|
||||
#define ANTAG_HUD_SOULLESS 21
|
||||
#define ANTAG_HUD_CLOCKWORK 22
|
||||
#define ANTAG_HUD_BROTHER 23
|
||||
|
||||
// Notification action types
|
||||
#define NOTIFY_JUMP "jump"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
// /datum signals
|
||||
#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
|
||||
#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
|
||||
#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
|
||||
#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
|
||||
#define COMSIG_PARENT_QDELETED "parent_qdeleted" //after a datum's Destroy() is called: (force, qdel_hint), at this point none of the other components chose to interrupt qdel and Destroy has been called
|
||||
|
||||
// /atom signals
|
||||
@@ -62,6 +62,14 @@
|
||||
#define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color)
|
||||
#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" //from base of atom/setDir(): (old_dir, new_dir)
|
||||
#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" //from base of atom/handle_atom_del(): (atom/deleted)
|
||||
#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" //from base of atom/has_gravity(): (turf/location, list/forced_gravities)
|
||||
#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe" //from proc/get_rad_contents(): ()
|
||||
#define COMPONENT_BLOCK_RADIATION 1
|
||||
#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam" //from base of datum/radiation_wave/radiate(): (strength)
|
||||
#define COMPONENT_BLOCK_CONTAMINATION 1
|
||||
#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass" //from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width)
|
||||
#define COMSIG_ATOM_CANREACH "atom_can_reach" //from internal loop in atom/movable/proc/CanReach(): (list/next)
|
||||
#define COMPONENT_BLOCK_REACH 1
|
||||
/////////////////
|
||||
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost)
|
||||
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
|
||||
@@ -72,7 +80,7 @@
|
||||
#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area)
|
||||
#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area)
|
||||
|
||||
#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params)
|
||||
#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params, mob/user)
|
||||
#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob)
|
||||
#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob)
|
||||
#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob)
|
||||
@@ -87,29 +95,40 @@
|
||||
|
||||
// /turf signals
|
||||
#define COMSIG_TURF_CHANGE "turf_change" //from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
|
||||
#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" //from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
|
||||
|
||||
// /atom/movable signals
|
||||
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
|
||||
#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_UNCROSS "movable_uncross" //from base of atom/movable/Uncross(): (/atom/movable)
|
||||
#define COMPONENT_MOVABLE_BLOCK_UNCROSS 1
|
||||
#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed" //from base of atom/movable/Uncrossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_COLLIDE "movable_collide" //from base of atom/movable/Collide(): (/atom)
|
||||
#define COMSIG_MOVABLE_COLLIDE "movable_bump" //from base of atom/movable/Bump(): (/atom) //CIT EDITED BACK TO COLLIDE PENDING SYNC
|
||||
#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
|
||||
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
|
||||
#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
|
||||
#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
|
||||
#define COMSIG_MOVABLE_THROW "movable_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
|
||||
#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z)
|
||||
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
|
||||
#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
|
||||
#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
|
||||
#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw" //from base of atom/movable/throw_at(): (list/args)
|
||||
#define COMPONENT_CANCEL_THROW 1
|
||||
#define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
|
||||
#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z)
|
||||
#define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
|
||||
|
||||
// /mob Signals
|
||||
// /mob signals
|
||||
#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
|
||||
#define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
|
||||
#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (magic, holy, protection_sources)
|
||||
#define COMPONENT_BLOCK_MAGIC 1
|
||||
#define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): ()
|
||||
|
||||
// /mob/living signals
|
||||
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
|
||||
#define COMSIG_LIVING_IGNITED "living_ignite" //from base of mob/living/IgniteMob() (/mob/living)
|
||||
#define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living)
|
||||
#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage)
|
||||
#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: ()
|
||||
|
||||
// /mob/living/carbon signals
|
||||
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
|
||||
@@ -126,11 +145,13 @@
|
||||
#define COMPONENT_NO_ATTACK_OBJ 1
|
||||
#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
|
||||
#define COMPONENT_NO_ATTACK 1
|
||||
#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
|
||||
#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
|
||||
#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
|
||||
#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
|
||||
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
|
||||
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
|
||||
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
|
||||
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
|
||||
|
||||
// /obj/item/clothing signals
|
||||
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
|
||||
@@ -162,6 +183,10 @@
|
||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
|
||||
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
|
||||
|
||||
// /datum/species signals
|
||||
#define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
|
||||
#define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species)
|
||||
|
||||
/*******Component Specific Signals*******/
|
||||
//Janitor
|
||||
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
|
||||
@@ -178,6 +203,23 @@
|
||||
//NTnet
|
||||
#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive" //called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
|
||||
|
||||
//Nanites
|
||||
#define COMSIG_HAS_NANITES "has_nanites" //() returns TRUE if nanites are found
|
||||
#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" //(list/nanite_programs) - makes the input list a copy the nanites' program list
|
||||
#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" //(amount) Sets current nanite volume to the given amount
|
||||
#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust" //(amount) Adjusts nanite volume by the given amount
|
||||
#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume" //(amount) Sets maximum nanite volume to the given amount
|
||||
#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud" //(amount(0-100)) Sets cloud ID to the given amount
|
||||
#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" //(amount) Sets safety threshold to the given amount
|
||||
#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" //(amount) Sets regeneration rate to the given amount
|
||||
#define COMSIG_NANITE_SIGNAL "nanite_signal" //(code(1-9999)) Called when sending a nanite signal to a mob.
|
||||
#define COMSIG_NANITE_SCAN "nanite_scan" //(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
|
||||
#define COMSIG_NANITE_UI_DATA "nanite_ui_data" //(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
|
||||
#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" //(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
|
||||
#define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
|
||||
#define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
|
||||
#define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
|
||||
|
||||
// /datum/component/storage signals
|
||||
#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.
|
||||
#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert" //(obj/item/inserting, mob/user, silent, force) - returns bool
|
||||
@@ -193,6 +235,10 @@
|
||||
#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory" //(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
|
||||
#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip" //(obj/item/insertion_candidate, mob/user, silent) - returns bool
|
||||
|
||||
// /datum/action signals
|
||||
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
|
||||
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
|
||||
|
||||
/*******Non-Signal Component Related Defines*******/
|
||||
|
||||
//Redirection component init flags
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define INVESTIGATE_RADIATION "radiation"
|
||||
#define INVESTIGATE_EXONET "exonet"
|
||||
#define INVESTIGATE_CIRCUIT "circuit"
|
||||
#define INVESTIGATE_NANITES "nanites"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define LIMBGROWER (1<<6) //Uses synthetic flesh
|
||||
#define SMELTER (1<<7) //uses various minerals
|
||||
#define AUTOYLATHE (1<<8) // CITADEL ADD
|
||||
#define NANITE_COMPILER (1<<9) //Prints nanite disks
|
||||
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
|
||||
|
||||
//Modular computer/NTNet defines
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#define NANITE_TIMER_DEACTIVATE 1
|
||||
#define NANITE_TIMER_SELFDELETE 2
|
||||
#define NANITE_TIMER_TRIGGER 3
|
||||
#define NANITE_TIMER_RESET 4
|
||||
|
||||
#define NANITE_SYNC_DELAY 300
|
||||
|
||||
#define NANITE_SHOCK_IMMUNE 1
|
||||
#define NANITE_EMP_IMMUNE 2
|
||||
|
||||
#define NANITE_PROGRAM_LIMIT 20
|
||||
@@ -48,6 +48,7 @@
|
||||
#define TRAIT_NODEATH "nodeath"
|
||||
#define TRAIT_NOHARDCRIT "nohardcrit"
|
||||
#define TRAIT_NOSOFTCRIT "nosoftcrit"
|
||||
#define TRAIT_MINDSHIELD "mindshield"
|
||||
|
||||
|
||||
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(nanites)
|
||||
name = "Nanites"
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
wait = 10
|
||||
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/list/mob/living/nanite_monitored_mobs = list()
|
||||
var/list/datum/nanite_program/relay/nanite_relays = list()
|
||||
|
||||
/datum/controller/subsystem/processing/nanites/proc/check_hardware(datum/nanite_cloud_backup/backup)
|
||||
if(QDELETED(backup.storage) || (backup.storage.stat & (NOPOWER|BROKEN)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/processing/nanites/proc/get_cloud_backup(cloud_id, force = FALSE)
|
||||
for(var/I in cloud_backups)
|
||||
var/datum/nanite_cloud_backup/backup = I
|
||||
if(!force && !check_hardware(backup))
|
||||
return
|
||||
if(backup.cloud_id == cloud_id)
|
||||
return backup
|
||||
@@ -0,0 +1,314 @@
|
||||
/datum/component/nanites
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
var/mob/living/host_mob
|
||||
var/nanite_volume = 100 //amount of nanites in the system, used as fuel for nanite programs
|
||||
var/max_nanites = 500 //maximum amount of nanites in the system
|
||||
var/regen_rate = 0.5 //nanites generated per second
|
||||
var/safety_threshold = 50 //how low nanites will get before they stop processing/triggering
|
||||
var/cloud_id = 0 //0 if not connected to the cloud, 1-100 to set a determined cloud backup to draw from
|
||||
var/next_sync = 0
|
||||
var/list/datum/nanite_program/programs = list()
|
||||
var/max_programs = NANITE_PROGRAM_LIMIT
|
||||
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans, and does not display the program list on nanite scans
|
||||
|
||||
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
|
||||
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
nanite_volume = amount
|
||||
cloud_id = cloud
|
||||
|
||||
//Nanites without hosts are non-interactive through normal means
|
||||
if(isliving(parent))
|
||||
host_mob = parent
|
||||
|
||||
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes)) //Shouldn't happen, but this avoids HUD runtimes in case a silicon gets them somehow.
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
START_PROCESSING(SSnanites, src)
|
||||
|
||||
if(cloud_id)
|
||||
cloud_sync()
|
||||
|
||||
/datum/component/nanites/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
|
||||
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_VOLUME, .proc/set_volume)
|
||||
RegisterSignal(parent, COMSIG_NANITE_ADJUST_VOLUME, .proc/adjust_nanites)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_MAX_VOLUME, .proc/set_max_volume)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_CLOUD, .proc/set_cloud)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_SAFETY, .proc/set_safety)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SET_REGEN, .proc/set_regen)
|
||||
RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SYNC, .proc/sync)
|
||||
|
||||
if(isliving(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
|
||||
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/on_death)
|
||||
RegisterSignal(parent, COMSIG_MOB_ALLOWED, .proc/check_access)
|
||||
RegisterSignal(parent, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_shock)
|
||||
RegisterSignal(parent, COMSIG_LIVING_MINOR_SHOCK, .proc/on_minor_shock)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_HEAR, .proc/on_hear)
|
||||
RegisterSignal(parent, COMSIG_SPECIES_GAIN, .proc/check_viable_biotype)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
|
||||
|
||||
/datum/component/nanites/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
|
||||
COMSIG_NANITE_UI_DATA,
|
||||
COMSIG_NANITE_GET_PROGRAMS,
|
||||
COMSIG_NANITE_SET_VOLUME,
|
||||
COMSIG_NANITE_ADJUST_VOLUME,
|
||||
COMSIG_NANITE_SET_MAX_VOLUME,
|
||||
COMSIG_NANITE_SET_CLOUD,
|
||||
COMSIG_NANITE_SET_SAFETY,
|
||||
COMSIG_NANITE_SET_REGEN,
|
||||
COMSIG_NANITE_ADD_PROGRAM,
|
||||
COMSIG_NANITE_SCAN,
|
||||
COMSIG_NANITE_SYNC,
|
||||
COMSIG_ATOM_EMP_ACT,
|
||||
COMSIG_MOB_DEATH,
|
||||
COMSIG_MOB_ALLOWED,
|
||||
COMSIG_LIVING_ELECTROCUTE_ACT,
|
||||
COMSIG_LIVING_MINOR_SHOCK,
|
||||
COMSIG_MOVABLE_HEAR,
|
||||
COMSIG_SPECIES_GAIN,
|
||||
COMSIG_NANITE_SIGNAL))
|
||||
|
||||
/datum/component/nanites/Destroy()
|
||||
STOP_PROCESSING(SSnanites, src)
|
||||
set_nanite_bar(TRUE)
|
||||
QDEL_LIST(programs)
|
||||
if(host_mob)
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
host_mob = null
|
||||
return ..()
|
||||
|
||||
/datum/component/nanites/InheritComponent(datum/component/nanites/new_nanites, i_am_original, list/arguments)
|
||||
if(new_nanites)
|
||||
adjust_nanites(new_nanites.nanite_volume)
|
||||
else
|
||||
adjust_nanites(arguments[1]) //just add to the nanite volume
|
||||
|
||||
/datum/component/nanites/process()
|
||||
adjust_nanites(regen_rate)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_process()
|
||||
set_nanite_bar()
|
||||
if(cloud_id && world.time > next_sync)
|
||||
cloud_sync()
|
||||
next_sync = world.time + NANITE_SYNC_DELAY
|
||||
|
||||
//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
|
||||
/datum/component/nanites/proc/sync(datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
|
||||
var/list/programs_to_remove = programs.Copy()
|
||||
var/list/programs_to_add = source.programs.Copy()
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
for(var/Y in programs_to_add)
|
||||
var/datum/nanite_program/SNP = Y
|
||||
if(NP.type == SNP.type)
|
||||
programs_to_remove -= NP
|
||||
programs_to_add -= SNP
|
||||
SNP.copy_programming(NP, copy_activation)
|
||||
break
|
||||
if(full_overwrite)
|
||||
for(var/X in programs_to_remove)
|
||||
qdel(X)
|
||||
for(var/X in programs_to_add)
|
||||
var/datum/nanite_program/SNP = X
|
||||
add_program(SNP.copy())
|
||||
|
||||
/datum/component/nanites/proc/cloud_sync()
|
||||
if(!cloud_id)
|
||||
return
|
||||
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
|
||||
if(backup)
|
||||
var/datum/component/nanites/cloud_copy = backup.nanites
|
||||
if(cloud_copy)
|
||||
sync(cloud_copy)
|
||||
|
||||
/datum/component/nanites/proc/add_program(datum/nanite_program/new_program, datum/nanite_program/source_program)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
if(NP.unique && NP.type == new_program.type)
|
||||
qdel(NP)
|
||||
if(programs.len >= max_programs)
|
||||
return COMPONENT_PROGRAM_NOT_INSTALLED
|
||||
if(source_program)
|
||||
source_program.copy_programming(new_program)
|
||||
programs += new_program
|
||||
new_program.on_add(src)
|
||||
return COMPONENT_PROGRAM_INSTALLED
|
||||
|
||||
/datum/component/nanites/proc/consume_nanites(amount, force = FALSE)
|
||||
if(!force && safety_threshold && (nanite_volume - amount < safety_threshold))
|
||||
return FALSE
|
||||
adjust_nanites(-amount)
|
||||
return (nanite_volume > 0)
|
||||
|
||||
/datum/component/nanites/proc/adjust_nanites(amount)
|
||||
nanite_volume = CLAMP(nanite_volume + amount, 0, max_nanites)
|
||||
if(nanite_volume <= 0) //oops we ran out
|
||||
qdel(src)
|
||||
|
||||
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
|
||||
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
|
||||
var/icon/I = icon(host_mob.icon, host_mob.icon_state, host_mob.dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = null
|
||||
if(remove || stealth)
|
||||
return //bye icon
|
||||
var/nanite_percent = (nanite_volume / max_nanites) * 100
|
||||
nanite_percent = CLAMP(CEILING(nanite_percent, 10), 10, 100)
|
||||
holder.icon_state = "nanites[nanite_percent]"
|
||||
|
||||
/datum/component/nanites/proc/on_emp(severity)
|
||||
nanite_volume *= (rand(0.60, 0.90)) //Lose 10-40% of nanites
|
||||
adjust_nanites(-(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
if(prob(40/severity))
|
||||
cloud_id = 0
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_emp(severity)
|
||||
|
||||
/datum/component/nanites/proc/on_shock(shock_damage)
|
||||
nanite_volume *= (rand(0.45, 0.80)) //Lose 20-55% of nanites
|
||||
adjust_nanites(-(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_shock(shock_damage)
|
||||
|
||||
/datum/component/nanites/proc/on_minor_shock()
|
||||
adjust_nanites(-(rand(5, 15))) //Lose 5-15 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_minor_shock()
|
||||
|
||||
/datum/component/nanites/proc/on_death(gibbed)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_death(gibbed)
|
||||
|
||||
/datum/component/nanites/proc/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
/datum/component/nanites/proc/receive_signal(code, source = "an unidentified source")
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.receive_signal(code, source)
|
||||
|
||||
/datum/component/nanites/proc/check_viable_biotype()
|
||||
if(!(MOB_ORGANIC in host_mob.mob_biotypes) && !(MOB_UNDEAD in host_mob.mob_biotypes))
|
||||
qdel(src) //bodytype no longer sustains nanites
|
||||
|
||||
/datum/component/nanites/proc/check_access(obj/O)
|
||||
for(var/datum/nanite_program/triggered/access/access_program in programs)
|
||||
if(access_program.activated)
|
||||
return O.check_access_list(access_program.access)
|
||||
else
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/component/nanites/proc/set_volume(amount)
|
||||
nanite_volume = CLAMP(amount, 0, max_nanites)
|
||||
|
||||
/datum/component/nanites/proc/set_max_volume(amount)
|
||||
max_nanites = max(1, max_nanites)
|
||||
|
||||
/datum/component/nanites/proc/set_cloud(amount)
|
||||
cloud_id = CLAMP(amount, 0, 100)
|
||||
|
||||
/datum/component/nanites/proc/set_safety(amount)
|
||||
safety_threshold = CLAMP(amount, 0, max_nanites)
|
||||
|
||||
/datum/component/nanites/proc/set_regen(amount)
|
||||
regen_rate = amount
|
||||
|
||||
/datum/component/nanites/proc/confirm_nanites()
|
||||
return TRUE //yup i exist
|
||||
|
||||
/datum/component/nanites/proc/get_data(list/nanite_data)
|
||||
nanite_data["nanite_volume"] = nanite_volume
|
||||
nanite_data["max_nanites"] = max_nanites
|
||||
nanite_data["cloud_id"] = cloud_id
|
||||
nanite_data["regen_rate"] = regen_rate
|
||||
nanite_data["safety_threshold"] = safety_threshold
|
||||
nanite_data["stealth"] = stealth
|
||||
|
||||
/datum/component/nanites/proc/get_programs(list/nanite_programs)
|
||||
nanite_programs |= programs
|
||||
|
||||
/datum/component/nanites/proc/nanite_scan(mob/user, full_scan)
|
||||
if(!full_scan)
|
||||
if(!stealth)
|
||||
to_chat(user, "<span class='notice'><b>Nanites Detected</b></span>")
|
||||
to_chat(user, "<span class='notice'>Saturation: [nanite_volume]/[max_nanites]</span>")
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, "<span class='info'>NANITES DETECTED</span>")
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Saturation: [nanite_volume]/[max_nanites]</span>")
|
||||
to_chat(user, "<span class='info'>Safety Threshold: [safety_threshold]</span>")
|
||||
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Program List:</span>")
|
||||
if(stealth)
|
||||
to_chat(user, "<span class='alert'>%#$ENCRYPTED&^@</span>")
|
||||
else
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
to_chat(user, "<span class='info'><b>[NP.name]</b> | [NP.activated ? "Active" : "Inactive"]</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/component/nanites/proc/nanite_ui_data(list/data, scan_level)
|
||||
data["has_nanites"] = TRUE
|
||||
data["nanite_volume"] = nanite_volume
|
||||
data["regen_rate"] = regen_rate
|
||||
data["safety_threshold"] = safety_threshold
|
||||
data["cloud_id"] = cloud_id
|
||||
var/list/mob_programs = list()
|
||||
var/id = 1
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/P = X
|
||||
var/list/mob_program = list()
|
||||
mob_program["name"] = P.name
|
||||
mob_program["desc"] = P.desc
|
||||
mob_program["id"] = id
|
||||
|
||||
if(scan_level >= 2)
|
||||
mob_program["activated"] = P.activated
|
||||
mob_program["use_rate"] = P.use_rate
|
||||
mob_program["can_trigger"] = P.can_trigger
|
||||
mob_program["trigger_cost"] = P.trigger_cost
|
||||
mob_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
if(scan_level >= 3)
|
||||
mob_program["activation_delay"] = P.activation_delay
|
||||
mob_program["timer"] = P.timer
|
||||
mob_program["timer_type"] = P.get_timer_type_text()
|
||||
var/list/extra_settings = list()
|
||||
for(var/Y in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = Y
|
||||
setting["value"] = P.get_extra_setting(Y)
|
||||
extra_settings += list(setting)
|
||||
mob_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
mob_program["has_extra_settings"] = TRUE
|
||||
|
||||
if(scan_level >= 4)
|
||||
mob_program["activation_code"] = P.activation_code
|
||||
mob_program["deactivation_code"] = P.deactivation_code
|
||||
mob_program["kill_code"] = P.kill_code
|
||||
mob_program["trigger_code"] = P.trigger_code
|
||||
id++
|
||||
mob_programs += list(mob_program)
|
||||
data["mob_programs"] = mob_programs
|
||||
@@ -94,7 +94,7 @@
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/attack_self)
|
||||
RegisterSignal(parent, COMSIG_ITEM_PICKUP, .proc/signal_on_pickup)
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_THROW, .proc/close_all)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_PRE_THROW, .proc/close_all)
|
||||
|
||||
RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_alt_click)
|
||||
RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/datum/symptom/nano_boost
|
||||
name = "Nano-symbiosis"
|
||||
desc = "The virus reacts to nanites in the host's bloodstream by enhancing their replication cycle."
|
||||
stealth = 0
|
||||
resistance = 2
|
||||
stage_speed = 2
|
||||
transmittable = -1
|
||||
level = 7
|
||||
severity = 0
|
||||
symptom_delay_min = 1
|
||||
symptom_delay_max = 1
|
||||
var/reverse_boost = FALSE
|
||||
threshold_desc = "<b>Transmission 5:</b> Increases the virus' growth rate while nanites are present.<br>\
|
||||
<b>Stage Speed 7:</b> Increases the replication boost."
|
||||
|
||||
/datum/symptom/nano_boost/Start(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
if(A.properties["transmittable"] >= 5) //reverse boost
|
||||
reverse_boost = TRUE
|
||||
if(A.properties["stage_rate"] >= 7) //more nanites
|
||||
power = 2
|
||||
|
||||
/datum/symptom/nano_boost/Activate(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/carbon/M = A.affected_mob
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_ADJUST_VOLUME, 0.5 * power)
|
||||
if(reverse_boost && SEND_SIGNAL(M, COMSIG_HAS_NANITES))
|
||||
if(prob(A.stage_prob))
|
||||
A.stage = min(A.stage + 1,A.max_stages)
|
||||
|
||||
/datum/symptom/nano_destroy
|
||||
name = "Silicolysis"
|
||||
desc = "The virus reacts to nanites in the host's bloodstream by attacking and consuming them."
|
||||
stealth = 0
|
||||
resistance = 4
|
||||
stage_speed = -1
|
||||
transmittable = 1
|
||||
level = 7
|
||||
severity = 0
|
||||
symptom_delay_min = 1
|
||||
symptom_delay_max = 1
|
||||
var/reverse_boost = FALSE
|
||||
threshold_desc = "<b>Stage Speed 5:</b> Increases the virus' growth rate while nanites are present.<br>\
|
||||
<b>Resistance 7:</b> Severely increases the rate at which the nanites are destroyed."
|
||||
|
||||
/datum/symptom/nano_destroy/Start(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
if(A.properties["stage_rate"] >= 5) //reverse boost
|
||||
reverse_boost = TRUE
|
||||
if(A.properties["resistance"] >= 7) //more nanites
|
||||
power = 3
|
||||
|
||||
/datum/symptom/nano_destroy/Activate(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
var/mob/living/carbon/M = A.affected_mob
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_ADJUST_VOLUME, -0.4 * power)
|
||||
if(reverse_boost && SEND_SIGNAL(M, COMSIG_HAS_NANITES))
|
||||
if(prob(A.stage_prob))
|
||||
A.stage = min(A.stage + 1,A.max_stages)
|
||||
@@ -12,6 +12,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
|
||||
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
|
||||
DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(),
|
||||
DATA_HUD_AI_DETECT = new/datum/atom_hud(), //CIT - EMPTY PLACEHOLDER UNTIL SYNC
|
||||
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
|
||||
@@ -25,7 +26,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden()
|
||||
))
|
||||
|
||||
/datum/atom_hud
|
||||
|
||||
@@ -589,6 +589,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "Engineering Storage"
|
||||
icon_state = "engi_storage"
|
||||
|
||||
/area/engine/storage_shared
|
||||
name = "Shared Engineering Storage"
|
||||
icon_state = "engi_storage"
|
||||
|
||||
/area/engine/transit_tube
|
||||
name = "Transit Tube"
|
||||
icon_state = "transit_tube"
|
||||
@@ -1035,6 +1039,11 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "Toxins Mixing Lab"
|
||||
icon_state = "toxmix"
|
||||
|
||||
/area/science/mixing/chamber
|
||||
name = "Toxins Mixing Chamber"
|
||||
icon_state = "toxmix"
|
||||
valid_territory = FALSE
|
||||
|
||||
/area/science/misc_lab
|
||||
name = "Testing Lab"
|
||||
icon_state = "toxmisc"
|
||||
@@ -1087,6 +1096,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "Abandoned Research Lab"
|
||||
icon_state = "medresearch"
|
||||
|
||||
/area/science/nanite
|
||||
name = "Nanite Lab"
|
||||
icon_state = "toxmisc"
|
||||
|
||||
//Storage
|
||||
|
||||
/area/storage/tools
|
||||
|
||||
@@ -482,11 +482,12 @@
|
||||
if(spin)
|
||||
SpinAnimation(5, 1)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_THROW, TT, spin)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_THROW, TT, spin) //CITADEL - THIS IS BORKED. PENDING SYNC.
|
||||
SSthrowing.processing[src] = TT
|
||||
if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun))
|
||||
SSthrowing.currentrun[src] = TT
|
||||
TT.tick()
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_POST_THROW, TT, spin)
|
||||
|
||||
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
|
||||
for(var/m in buckled_mobs)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/datum/atom_hud/data
|
||||
|
||||
/datum/atom_hud/data/human/medical
|
||||
hud_icons = list(STATUS_HUD, HEALTH_HUD)
|
||||
hud_icons = list(STATUS_HUD, HEALTH_HUD, NANITE_HUD)
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic
|
||||
|
||||
@@ -47,15 +47,15 @@
|
||||
hud_icons = list(ID_HUD)
|
||||
|
||||
/datum/atom_hud/data/human/security/advanced
|
||||
hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD)
|
||||
hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD, NANITE_HUD)
|
||||
|
||||
/datum/atom_hud/data/diagnostic
|
||||
|
||||
/datum/atom_hud/data/diagnostic/basic
|
||||
hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD)
|
||||
hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_NANITE_FULL_HUD)
|
||||
|
||||
/datum/atom_hud/data/diagnostic/advanced
|
||||
hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_PATH_HUD)
|
||||
hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_NANITE_FULL_HUD, DIAG_PATH_HUD)
|
||||
|
||||
/datum/atom_hud/data/bot_path
|
||||
hud_icons = list(DIAG_PATH_HUD)
|
||||
@@ -65,6 +65,16 @@
|
||||
|
||||
/datum/atom_hud/sentient_disease
|
||||
hud_icons = list(SENTIENT_DISEASE_HUD)
|
||||
/*
|
||||
/datum/atom_hud/ai_detector
|
||||
hud_icons = list(AI_DETECT_HUD)
|
||||
|
||||
/datum/atom_hud/ai_detector/add_hud_to(mob/M)
|
||||
..()
|
||||
if(M && (hudusers.len == 1))
|
||||
for(var/V in GLOB.aiEyes)
|
||||
var/mob/camera/aiEye/E = V
|
||||
E.update_ai_detect_hud()*/
|
||||
|
||||
/* MED/SEC/DIAG HUD HOOKS */
|
||||
|
||||
@@ -216,7 +226,7 @@
|
||||
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
|
||||
sec_hud_set_security_status()
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_implants()
|
||||
/mob/living/proc/sec_hud_set_implants()
|
||||
var/image/holder
|
||||
for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD))
|
||||
holder = hud_list[i]
|
||||
@@ -227,16 +237,16 @@
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_tracking"
|
||||
else if(istype(I, /obj/item/implant/mindshield))
|
||||
holder = hud_list[IMPLOYAL_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_loyal"
|
||||
else if(istype(I, /obj/item/implant/chem))
|
||||
holder = hud_list[IMPCHEM_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_chem"
|
||||
if(has_trait(TRAIT_MINDSHIELD))
|
||||
holder = hud_list[IMPLOYAL_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_loyal"
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_security_status()
|
||||
var/image/holder = hud_list[WANTED_HUD]
|
||||
@@ -265,6 +275,14 @@
|
||||
Diagnostic HUDs!
|
||||
************************************************/
|
||||
|
||||
/mob/living/proc/hud_set_nanite_indicator()
|
||||
var/image/holder = hud_list[NANITE_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = null
|
||||
if(src in SSnanites.nanite_monitored_mobs)
|
||||
holder.icon_state = "nanite_ping"
|
||||
|
||||
//For Diag health and cell bars!
|
||||
/proc/RoundDiagBar(value)
|
||||
switch(value * 100)
|
||||
|
||||
@@ -59,8 +59,12 @@ Credit where due:
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
if(iscultist(M) || isconstruct(M) || M.isloyal() || ispAI(M))
|
||||
if(iscultist(M) || isconstruct(M) || ispAI(M))
|
||||
return FALSE
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
if(L.has_trait(TRAIT_MINDSHIELD))
|
||||
return FALSE
|
||||
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab) || istype(M, /mob/camera/eminence))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
if(M.isloyal() || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client)
|
||||
if(M.has_trait(TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client)
|
||||
return FALSE //can't convert machines, shielded, braindead, or ratvar's dogs
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -120,14 +120,17 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
|
||||
var/life_status
|
||||
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
var/nanite_sensors = FALSE
|
||||
if(H in SSnanites.nanite_monitored_mobs)
|
||||
nanite_sensors = TRUE
|
||||
// Check if their z-level is correct and if they are wearing a uniform.
|
||||
// Accept H.z==0 as well in case the mob is inside an object.
|
||||
if ((H.z == 0 || H.z == z) && istype(H.w_uniform, /obj/item/clothing/under))
|
||||
if ((H.z == 0 || H.z == z) && istype(H.w_uniform, /obj/item/clothing/under) || nanite_sensors)
|
||||
U = H.w_uniform
|
||||
|
||||
// Are the suit sensors on?
|
||||
if ((U.has_sensor > 0) && U.sensor_mode)
|
||||
pos = H.z == 0 || U.sensor_mode == SENSOR_COORDS ? get_turf(H) : null
|
||||
if (nanite_sensors || ((U.has_sensor > 0) && U.sensor_mode))
|
||||
pos = H.z == 0 || (nanite_sensors || U.sensor_mode == SENSOR_COORDS) ? get_turf(H) : null
|
||||
|
||||
// Special case: If the mob is inside an object confirm the z-level on turf level.
|
||||
if (H.z == 0 && (!pos || pos.z != z))
|
||||
@@ -144,12 +147,12 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
|
||||
assignment = ""
|
||||
ijob = 80
|
||||
|
||||
if (U.sensor_mode >= SENSOR_LIVING)
|
||||
if (nanite_sensors || U.sensor_mode >= SENSOR_LIVING)
|
||||
life_status = (!H.stat ? TRUE : FALSE)
|
||||
else
|
||||
life_status = null
|
||||
|
||||
if (U.sensor_mode >= SENSOR_VITALS)
|
||||
if (nanite_sensors || U.sensor_mode >= SENSOR_VITALS)
|
||||
oxydam = round(H.getOxyLoss(),1)
|
||||
toxdam = round(H.getToxLoss(),1)
|
||||
burndam = round(H.getFireLoss(),1)
|
||||
@@ -160,7 +163,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
|
||||
burndam = null
|
||||
brutedam = null
|
||||
|
||||
if (U.sensor_mode >= SENSOR_COORDS)
|
||||
if (nanite_sensors || U.sensor_mode >= SENSOR_COORDS)
|
||||
if (!pos)
|
||||
pos = get_turf(H)
|
||||
area = get_area_name(H, TRUE)
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
break
|
||||
if(component_check)
|
||||
P.play_tool_sound(src)
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc, 1)
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc)
|
||||
new_machine.setAnchored(anchored)
|
||||
new_machine.on_construction()
|
||||
for(var/obj/O in new_machine.component_parts)
|
||||
@@ -189,6 +189,9 @@
|
||||
for(var/obj/O in src)
|
||||
O.moveToNullspace()
|
||||
new_machine.component_parts += O
|
||||
if(new_machine.circuit)
|
||||
QDEL_NULL(new_machine.circuit)
|
||||
new_machine.circuit = circuit
|
||||
circuit.moveToNullspace()
|
||||
new_machine.RefreshParts()
|
||||
qdel(src)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
flags_1 |= HEAR_1
|
||||
|
||||
/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!density || !voice_activated || radio_freq)
|
||||
return
|
||||
if(findtext(raw_message,password))
|
||||
|
||||
@@ -408,6 +408,7 @@ Possible to do for anyone motivated enough:
|
||||
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
|
||||
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
|
||||
for(var/mob/living/silicon/ai/master in masters)
|
||||
if(masters[master] && speaker != master)
|
||||
|
||||
@@ -485,7 +485,7 @@
|
||||
threatcount += 4
|
||||
|
||||
if(shoot_unloyal)
|
||||
if (!perp.isloyal())
|
||||
if (!perp.has_trait(TRAIT_MINDSHIELD))
|
||||
threatcount += 4
|
||||
|
||||
return threatcount
|
||||
|
||||
@@ -402,6 +402,7 @@
|
||||
return
|
||||
|
||||
/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker == occupant)
|
||||
if(radio.broadcasting)
|
||||
radio.talk_into(speaker, text, , spans, message_language)
|
||||
|
||||
@@ -342,3 +342,11 @@
|
||||
/obj/item/circuitboard/computer/sat_control
|
||||
name = "Satellite Network Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/sat_control
|
||||
|
||||
/obj/item/circuitboard/computer/nanite_chamber_control
|
||||
name = "Nanite Chamber Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/nanite_chamber_control
|
||||
|
||||
/obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
name = "Nanite Cloud Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/nanite_cloud_controller
|
||||
|
||||
@@ -741,6 +741,47 @@
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_chamber
|
||||
name = "Nanite Chamber (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_chamber
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber
|
||||
name = "Public Nanite Chamber (Machine Board)"
|
||||
build_path = /obj/machinery/public_nanite_chamber
|
||||
var/cloud_id = 1
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber/multitool_act(mob/living/user)
|
||||
var/new_cloud = input("Set the public nanite chamber's Cloud ID (1-100).", "Cloud ID", cloud_id) as num|null
|
||||
if(new_cloud == null)
|
||||
return
|
||||
cloud_id = CLAMP(round(new_cloud, 1), 1, 100)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber/examine(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "Cloud ID is currently set to [cloud_id].")
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_program_hub
|
||||
name = "Nanite Program Hub (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_program_hub
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_programmer
|
||||
name = "Nanite Programmer (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_programmer
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/scanning_module = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe
|
||||
name = "Protolathe (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/protolathe
|
||||
|
||||
@@ -520,6 +520,7 @@
|
||||
add_logs(user, H, "overloaded the heart of", defib)
|
||||
H.Knockdown(100)
|
||||
H.Jitter(100)
|
||||
SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK)
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
cooldown = TRUE
|
||||
@@ -602,6 +603,7 @@
|
||||
H.set_heartattack(FALSE)
|
||||
H.revive()
|
||||
H.emote("gasp")
|
||||
SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK)
|
||||
H.Jitter(100)
|
||||
if(tplus > tloss)
|
||||
H.adjustBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100))), 150)
|
||||
|
||||
@@ -114,11 +114,11 @@
|
||||
|
||||
|
||||
/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if (message_mode == MODE_INTERCOM)
|
||||
return // Avoid hearing the same thing twice
|
||||
if(!anyai && !(speaker in ai))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/radio/intercom/process()
|
||||
if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0))
|
||||
|
||||
@@ -276,6 +276,7 @@
|
||||
signal.broadcast()
|
||||
|
||||
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
|
||||
return
|
||||
|
||||
|
||||
@@ -328,6 +328,7 @@ SLIME SCANNER
|
||||
if(cyberimp_detect)
|
||||
to_chat(user, "<span class='notice'>Detected cybernetic modifications:</span>")
|
||||
to_chat(user, "<span class='notice'>[cyberimp_detect]</span>")
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE)
|
||||
|
||||
/proc/chemscan(mob/living/user, mob/living/M)
|
||||
if(istype(M))
|
||||
@@ -603,3 +604,29 @@ SLIME SCANNER
|
||||
to_chat(user, "<span class='notice'>Core mutation in progress: [T.effectmod]</span>")
|
||||
to_chat(user, "<span_class = 'notice'>Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]</span>")
|
||||
to_chat(user, "========================")
|
||||
|
||||
/obj/item/nanite_scanner
|
||||
name = "nanite scanner"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_scanner"
|
||||
item_state = "nanite_remote"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
desc = "A hand-held body scanner able to detect nanites and their programming."
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
throwforce = 3
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=200)
|
||||
|
||||
/obj/item/nanite_scanner/attack(mob/living/M, mob/living/carbon/human/user)
|
||||
user.visible_message("<span class='notice'>[user] has analyzed [M]'s nanites.</span>")
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
var/response = SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, TRUE)
|
||||
if(!response)
|
||||
to_chat(user, "<span class='info'>No nanites detected in the subject.</span>")
|
||||
@@ -95,6 +95,7 @@
|
||||
|
||||
|
||||
/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
. = ..()
|
||||
if(mytape && recording)
|
||||
mytape.timestamp += mytape.used_capacity
|
||||
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [message]"
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/eightball/haunted/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
. = ..()
|
||||
last_message = raw_message
|
||||
|
||||
/obj/item/toy/eightball/haunted/start_shaking(mob/user)
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
/obj/item/implant/mindshield/implant(mob/living/target, mob/user, silent = FALSE)
|
||||
if(..())
|
||||
if(!target.mind)
|
||||
target.add_trait(TRAIT_MINDSHIELD, "implant")
|
||||
target.sec_hud_set_implants()
|
||||
return TRUE
|
||||
|
||||
if(target.mind.has_antag_datum(/datum/antagonist/brainwashed))
|
||||
@@ -39,6 +41,8 @@
|
||||
to_chat(target, "<span class='warning'>You feel something interfering with your mental conditioning, but you resist it!</span>")
|
||||
else
|
||||
to_chat(target, "<span class='notice'>You feel a sense of peace and security. You are now protected from brainwashing.</span>")
|
||||
target.add_trait(TRAIT_MINDSHIELD, "implant")
|
||||
target.sec_hud_set_implants()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -46,8 +50,12 @@
|
||||
if(..())
|
||||
if(target.stat != DEAD && !silent)
|
||||
to_chat(target, "<span class='boldnotice'>Your mind suddenly feels terribly vulnerable. You are no longer safe from brainwashing.</span>")
|
||||
return 1
|
||||
return 0
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
L.remove_trait(TRAIT_MINDSHIELD, "implant")
|
||||
L.sec_hud_set_implants()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/implanter/mindshield
|
||||
name = "implanter (mindshield)"
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
objective = stripped_input(usr,"What order do you want to imprint on [C]?","Enter the order","",120)
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] set brainwash machine objective to '[objective]'.")
|
||||
log_game("[key_name(user)] set brainwash machine objective to '[objective]'.")
|
||||
if(C.isloyal())
|
||||
if(C.has_trait(TRAIT_MINDSHIELD))
|
||||
return FALSE
|
||||
brainwash(C, objective)
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
inspiration_available = FALSE
|
||||
|
||||
/obj/item/banner/command/check_inspiration(mob/living/carbon/human/H)
|
||||
return H.isloyal() //Command is stalwart but rewards their allies.
|
||||
return H.has_trait(TRAIT_MINDSHIELD) //Command is stalwart but rewards their allies.
|
||||
|
||||
/datum/crafting_recipe/command_banner
|
||||
name = "Command Banner"
|
||||
|
||||
@@ -1008,3 +1008,11 @@
|
||||
new /obj/item/stock_parts/matter_bin/bluespace(src)
|
||||
new /obj/item/stock_parts/matter_bin/bluespace(src)
|
||||
new /obj/item/stock_parts/matter_bin/bluespace(src)
|
||||
|
||||
/obj/item/storage/box/disks_nanite
|
||||
name = "nanite program disks box"
|
||||
illustration = "disk_kit"
|
||||
|
||||
/obj/item/storage/box/disks_nanite/PopulateContents()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/disk/nanite_program(src)
|
||||
@@ -165,6 +165,7 @@
|
||||
L.Knockdown(stunforce)
|
||||
L.adjustStaminaLoss(stunforce*0.1)//CIT CHANGE - makes stunbatons deal extra staminaloss. Todo: make this also deal pain when pain gets implemented.
|
||||
L.apply_effect(EFFECT_STUTTER, stunforce)
|
||||
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
|
||||
if(user)
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
user.visible_message("<span class='danger'>[user] accidentally hits [user.p_them()]self with [src]!</span>", \
|
||||
"<span class='userdanger'>You accidentally hit yourself with [src]!</span>")
|
||||
if(do_teleport(user, get_turf(user), 50))//honk honk
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
|
||||
user.Knockdown(stunforce*3)
|
||||
deductcharge(hitcost)
|
||||
else
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
|
||||
user.Knockdown(stunforce*3)
|
||||
deductcharge(hitcost/4)
|
||||
return
|
||||
@@ -23,6 +25,7 @@
|
||||
if(!istype(M) && M.anchored)
|
||||
return .
|
||||
else
|
||||
SEND_SIGNAL(M, COMSIG_LIVING_MINOR_SHOCK)
|
||||
do_teleport(M, get_turf(M), 15)
|
||||
|
||||
/obj/item/melee/baton/cattleprod/attackby(obj/item/I, mob/user, params)//handles sticking a crystal onto a stunprod to make a teleprod
|
||||
|
||||
@@ -29,7 +29,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
send_speech(message, 7, src, , spans, message_language=language)
|
||||
|
||||
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
return
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
/atom/movable/proc/can_speak()
|
||||
return 1
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
WRITE_FILE(F, "<small>[time_stamp()] [REF(src)] ([x],[y],[z])</small> || [src] [message]<br>")
|
||||
|
||||
/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT) )
|
||||
/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES) )
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
if(!holder)
|
||||
|
||||
@@ -35,9 +35,9 @@ GLOBAL_VAR(antag_prototypes)
|
||||
var/data_part = antag_panel_data()
|
||||
var/objective_part = antag_panel_objectives()
|
||||
var/memory_part = antag_panel_memory()
|
||||
|
||||
|
||||
var/list/parts = listtrim(list(command_part,data_part,objective_part,memory_part))
|
||||
|
||||
|
||||
return parts.Join("<br>")
|
||||
|
||||
/datum/antagonist/proc/antag_panel_objectives()
|
||||
@@ -80,7 +80,7 @@ GLOBAL_VAR(antag_prototypes)
|
||||
var/list/result = list()
|
||||
if(!current)
|
||||
result += "<span class='bad'>No body!</span>"
|
||||
if(current && current.isloyal())
|
||||
if(current && current.has_trait(TRAIT_MINDSHIELD))
|
||||
result += "<span class='good'>Mindshielded</span>"
|
||||
//Move these to mob
|
||||
if(iscyborg(current))
|
||||
@@ -155,8 +155,8 @@ GLOBAL_VAR(antag_prototypes)
|
||||
priority_sections |= antag_category
|
||||
antag_header_parts += "<span class='bad'>[current_antag.name]</span>"
|
||||
antag_header_parts += "<a href='?src=[REF(src)];remove_antag=[REF(current_antag)]'>Remove</a>"
|
||||
|
||||
|
||||
|
||||
|
||||
//We aren't antag of this category, grab first prototype to check the prefs (This is pretty vague but really not sure how else to do this)
|
||||
var/datum/antagonist/pref_source = current_antag
|
||||
if(!pref_source)
|
||||
@@ -167,7 +167,7 @@ GLOBAL_VAR(antag_prototypes)
|
||||
break
|
||||
if(pref_source.job_rank)
|
||||
antag_header_parts += pref_source.enabled_in_preferences(src) ? "Enabled in Prefs" : "Disabled in Prefs"
|
||||
|
||||
|
||||
//Traitor : None | Traitor | IAA
|
||||
// Command1 | Command2 | Command3
|
||||
// Secret Word : Banana
|
||||
@@ -180,12 +180,12 @@ GLOBAL_VAR(antag_prototypes)
|
||||
if(current_antag)
|
||||
cat_section += current_antag.antag_panel()
|
||||
sections[antag_category] = cat_section
|
||||
|
||||
|
||||
for(var/s in priority_sections)
|
||||
out += sections[s]
|
||||
for(var/s in sections - priority_sections)
|
||||
out += sections[s]
|
||||
|
||||
|
||||
out += "<br>"
|
||||
|
||||
//Uplink
|
||||
@@ -201,7 +201,7 @@ GLOBAL_VAR(antag_prototypes)
|
||||
else
|
||||
uplink_info += "<a href='?src=[REF(src)];common=uplink'>give</a>"
|
||||
uplink_info += "." //hiel grammar
|
||||
|
||||
|
||||
out += uplink_info + "<br>"
|
||||
//Common Memory
|
||||
var/common_memory = "<span>Common Memory:</span>"
|
||||
@@ -210,7 +210,7 @@ GLOBAL_VAR(antag_prototypes)
|
||||
out += common_memory + "<br>"
|
||||
//Other stuff
|
||||
out += get_common_admin_commands()
|
||||
|
||||
|
||||
var/datum/browser/panel = new(usr, "traitorpanel", "", 600, 600)
|
||||
panel.set_content(out)
|
||||
panel.open()
|
||||
|
||||
@@ -502,6 +502,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
|
||||
L.Knockdown(140)
|
||||
L.apply_effect(EFFECT_STUTTER, 7)
|
||||
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
|
||||
|
||||
L.visible_message("<span class='danger'>[user] has stunned [L] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has stunned you with [src]!</span>")
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
T.visible_message("<span class='warning'>[T] suddenly emits a ringing sound!</span>", null, null, null, src)
|
||||
playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
|
||||
last_failed_turf = T
|
||||
if((world.time - lastWarning) >= 30)
|
||||
if((world.time - lastWarning) >= 30)
|
||||
lastWarning = world.time
|
||||
to_chat(src, "<span class='warning'>This turf is consecrated and can't be crossed!</span>")
|
||||
return
|
||||
if(istype(get_area(T), /area/chapel))
|
||||
if((world.time - lastWarning) >= 30)
|
||||
if((world.time - lastWarning) >= 30)
|
||||
lastWarning = world.time
|
||||
to_chat(src, "<span class='warning'>The Chapel is hallowed ground under a heretical deity, and can't be accessed!</span>")
|
||||
return
|
||||
@@ -99,6 +99,7 @@
|
||||
to_chat(M, message)
|
||||
|
||||
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
|
||||
to_chat(src, message)
|
||||
return
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
return FALSE
|
||||
if(new_owner.unconvertable)
|
||||
return FALSE
|
||||
if(new_owner.current && new_owner.current.isloyal())
|
||||
if(new_owner.current && new_owner.current.has_trait(TRAIT_MINDSHIELD))
|
||||
return FALSE
|
||||
|
||||
/datum/antagonist/rev/apply_innate_effects(mob/living/mob_override)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
to_chat(user, "<span class='notice'>Use a multitool to swap between \"inclusive\", \"exclusive\", \"recognizer\", and \"voice sensor\" mode.</span>")
|
||||
|
||||
/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker == src)
|
||||
return
|
||||
|
||||
|
||||
@@ -625,7 +625,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/fake_door_lock
|
||||
layer = CLOSED_DOOR_LAYER + 1 //for Collide priority
|
||||
layer = CLOSED_DOOR_LAYER + 1 //for Bump priority
|
||||
var/image/bolt_light
|
||||
var/obj/machinery/door/airlock/airlock
|
||||
|
||||
@@ -771,13 +771,13 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
..()
|
||||
var/turf/source = random_far_turf()
|
||||
if(!sound_type)
|
||||
sound_type = pick("airlock","airlock_pry","console","explosion","far_explosion","mech","glass","alarm","beepsky","mech","wall_decon","door_hack","tesla")
|
||||
sound_type = pick("airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
|
||||
feedback_details += "Type: [sound_type]"
|
||||
//Strange audio
|
||||
switch(sound_type)
|
||||
if("airlock")
|
||||
target.playsound_local(source,'sound/machines/airlock.ogg', 30, 1)
|
||||
if("airlock_pry")
|
||||
if("airlock pry")
|
||||
target.playsound_local(source,'sound/machines/airlock_alien_prying.ogg', 100, 1)
|
||||
sleep(50)
|
||||
target.playsound_local(source, 'sound/machines/airlockforced.ogg', 30, 1)
|
||||
@@ -788,7 +788,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
target.playsound_local(source,'sound/effects/explosion1.ogg', 50, 1)
|
||||
else
|
||||
target.playsound_local(source, 'sound/effects/explosion2.ogg', 50, 1)
|
||||
if("far_explosion")
|
||||
if("far explosion")
|
||||
target.playsound_local(source, 'sound/effects/explosionfar.ogg', 50, 1)
|
||||
if("glass")
|
||||
target.playsound_local(source, pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg'), 50, 1)
|
||||
@@ -807,14 +807,14 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
mech_dir = pick(GLOB.cardinals)
|
||||
sleep(10)
|
||||
//Deconstructing a wall
|
||||
if("wall_decon")
|
||||
if("wall decon")
|
||||
target.playsound_local(source, 'sound/items/welder.ogg', 50, 1)
|
||||
sleep(105)
|
||||
target.playsound_local(source, 'sound/items/welder2.ogg', 50, 1)
|
||||
sleep(15)
|
||||
target.playsound_local(source, 'sound/items/ratchet.ogg', 50, 1)
|
||||
//Hacking a door
|
||||
if("door_hack")
|
||||
if("door hack")
|
||||
target.playsound_local(source, 'sound/items/screwdriver.ogg', 50, 1)
|
||||
sleep(rand(40,80))
|
||||
target.playsound_local(source, 'sound/machines/airlockforced.ogg', 30, 1)
|
||||
@@ -827,7 +827,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
..()
|
||||
var/turf/source = random_far_turf()
|
||||
if(!sound_type)
|
||||
sound_type = pick("phone","hallelujah","highlander","hyperspace","game_over","creepy","tesla")
|
||||
sound_type = pick("phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla")
|
||||
feedback_details += "Type: [sound_type]"
|
||||
//Strange audio
|
||||
switch(sound_type)
|
||||
@@ -845,7 +845,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
target.playsound_local(source, 'sound/effects/pray_chaplain.ogg', 50)
|
||||
if("highlander")
|
||||
target.playsound_local(null, 'sound/misc/highlander.ogg', 50)
|
||||
if("game_over")
|
||||
if("game over")
|
||||
target.playsound_local(source, 'sound/misc/compiler-failure.ogg', 50)
|
||||
if("laughter")
|
||||
if(prob(50))
|
||||
@@ -870,10 +870,10 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
set waitfor = FALSE
|
||||
..()
|
||||
if(!message)
|
||||
message = pick("ratvar","shuttle_dock","blob_alert","malf_ai","meteors","supermatter")
|
||||
message = pick("ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter")
|
||||
feedback_details += "Type: [message]"
|
||||
switch(message)
|
||||
if("blob_alert")
|
||||
if("blob alert")
|
||||
to_chat(target, "<h1 class='alert'>Biohazard Alert</h1>")
|
||||
to_chat(target, "<br><br><span class='alert'>Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.</span><br><br>")
|
||||
SEND_SOUND(target, 'sound/ai/outbreak5.ogg')
|
||||
@@ -882,11 +882,11 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
target.playsound_local(target, 'sound/effects/clockcult_gateway_disrupted.ogg', 50, FALSE, pressure_affected = FALSE)
|
||||
sleep(27)
|
||||
target.playsound_local(target, 'sound/effects/explosion_distant.ogg', 50, FALSE, pressure_affected = FALSE)
|
||||
if("shuttle_dock")
|
||||
if("shuttle dock")
|
||||
to_chat(target, "<h1 class='alert'>Priority Announcement</h1>")
|
||||
to_chat(target, "<br><br><span class='alert'>The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.</span><br><br>")
|
||||
SEND_SOUND(target, 'sound/ai/shuttledock.ogg')
|
||||
if("malf_ai") //AI is doomsdaying!
|
||||
if("malf ai") //AI is doomsdaying!
|
||||
to_chat(target, "<h1 class='alert'>Anomaly Alert</h1>")
|
||||
to_chat(target, "<br><br><span class='alert'>Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.</span><br><br>")
|
||||
SEND_SOUND(target, 'sound/ai/aimalf.ogg')
|
||||
@@ -900,11 +900,14 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
|
||||
/datum/hallucination/hudscrew
|
||||
|
||||
/datum/hallucination/hudscrew/New(mob/living/carbon/C, forced = TRUE)
|
||||
/datum/hallucination/hudscrew/New(mob/living/carbon/C, forced = TRUE, screwyhud_type)
|
||||
set waitfor = FALSE
|
||||
..()
|
||||
//Screwy HUD
|
||||
target.set_screwyhud(pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY))
|
||||
var/chosen_screwyhud = screwyhud_type
|
||||
if(!chosen_screwyhud)
|
||||
chosen_screwyhud = pick(SCREWYHUD_CRIT,SCREWYHUD_DEAD,SCREWYHUD_HEALTHY)
|
||||
target.set_screwyhud(chosen_screwyhud)
|
||||
feedback_details += "Type: [target.hal_screwyhud]"
|
||||
sleep(rand(100,250))
|
||||
target.set_screwyhud(SCREWYHUD_NONE)
|
||||
|
||||
@@ -865,6 +865,7 @@
|
||||
power_draw_per_use = 5
|
||||
|
||||
/obj/item/integrated_circuit/input/microphone/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
. = ..()
|
||||
var/translated = FALSE
|
||||
if(speaker && message)
|
||||
if(raw_message)
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
if(IsAdminGhost(M))
|
||||
//Access can't stop the abuse
|
||||
return TRUE
|
||||
else if(SEND_SIGNAL(M, COMSIG_MOB_ALLOWED, src))
|
||||
return TRUE
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
//if they are holding or wearing a card that has access, that works
|
||||
@@ -59,7 +61,6 @@
|
||||
/obj/proc/check_access(obj/item/I)
|
||||
return check_access_list(I ? I.GetAccess() : null)
|
||||
|
||||
|
||||
/obj/proc/check_access_list(list/access_list)
|
||||
gen_access()
|
||||
|
||||
@@ -166,7 +167,7 @@
|
||||
if(6) //supply
|
||||
return list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_CARGO, ACCESS_QM, ACCESS_VAULT)
|
||||
if(7) //command
|
||||
return list(ACCESS_HEADS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_TELEPORTER, ACCESS_EVA, ACCESS_GATEWAY, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_HOP, ACCESS_CAPTAIN)
|
||||
return list(ACCESS_HEADS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_TELEPORTER, ACCESS_EVA, ACCESS_GATEWAY, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_HOP, ACCESS_CAPTAIN, ACCESS_VAULT)
|
||||
|
||||
/proc/get_region_accesses_name(code)
|
||||
switch(code)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
var/atom/movable/virtualspeaker/V = speaker
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
return
|
||||
|
||||
/mob/proc/death(gibbed)
|
||||
return
|
||||
SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
gender = MALE
|
||||
pressure_resistance = 15
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_HARM)
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD)
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD)
|
||||
has_limbs = 1
|
||||
held_items = list(null, null)
|
||||
var/list/stomach_contents = list()
|
||||
|
||||
@@ -116,10 +116,12 @@
|
||||
////////////////////////////////////////////
|
||||
|
||||
//Returns a list of damaged bodyparts
|
||||
/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, stamina = FALSE)
|
||||
/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, stamina = FALSE, status)
|
||||
var/list/obj/item/bodypart/parts = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(!isnull(status) && (BP.status != status))
|
||||
continue
|
||||
if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam))
|
||||
parts += BP
|
||||
return parts
|
||||
|
||||
@@ -619,7 +619,7 @@
|
||||
threatcount += 1
|
||||
|
||||
//mindshield implants imply trustworthyness
|
||||
if(isloyal())
|
||||
if(has_trait(TRAIT_MINDSHIELD))
|
||||
threatcount -= 1
|
||||
|
||||
//Agent cards lower threatlevel.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/mob/living/carbon/human
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD)
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD)
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
|
||||
pressure_resistance = 25
|
||||
can_buckle = TRUE
|
||||
|
||||
@@ -289,6 +289,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
if(TRAIT_VIRUSIMMUNE in inherent_traits)
|
||||
for(var/datum/disease/A in C.diseases)
|
||||
A.cure(FALSE)
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
|
||||
|
||||
//CITADEL EDIT
|
||||
if(NOAROUSAL in species_traits)
|
||||
@@ -305,6 +306,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
C.Digitigrade_Leg_Swap(TRUE)
|
||||
for(var/X in inherent_traits)
|
||||
C.remove_trait(X, SPECIES_TRAIT)
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
|
||||
|
||||
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
H.remove_overlay(HAIR_LAYER)
|
||||
|
||||
@@ -122,13 +122,13 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/dullahan_relay/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!QDELETED(owner))
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
to_chat(owner,message)
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/item/dullahan_relay/Destroy()
|
||||
if(!QDELETED(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
|
||||
@@ -594,7 +594,7 @@
|
||||
/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
|
||||
if(QDELETED(M) || M.stat == DEAD)
|
||||
return FALSE
|
||||
if(M.isloyal()) //mindshield implant, no dice
|
||||
if(M.has_trait(TRAIT_MINDSHIELD)) //mindshield implant, no dice
|
||||
return FALSE
|
||||
if(M in linked_mobs)
|
||||
return FALSE
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
threatcount += 4 //trigger look_for_perp() since they're nonhuman and very likely hostile
|
||||
|
||||
//mindshield implants imply trustworthyness
|
||||
if(isloyal())
|
||||
if(has_trait(TRAIT_MINDSHIELD))
|
||||
threatcount -= 1
|
||||
|
||||
return threatcount
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
. = initial(dt.flags) & TONGUELESS_SPEECH
|
||||
|
||||
/mob/living/carbon/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!client)
|
||||
return
|
||||
for(var/T in get_traumas())
|
||||
var/datum/brain_trauma/trauma = T
|
||||
message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq)
|
||||
return ..()
|
||||
@@ -76,7 +76,7 @@
|
||||
med_hud_set_status()
|
||||
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
|
||||
stop_pulling()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
if (client)
|
||||
client.move_delay = initial(client.move_delay)
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
real_name = name
|
||||
var/datum/atom_hud/data/human/medical/advanced/medhud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
medhud.add_to_hud(src)
|
||||
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
||||
diag_hud.add_to_hud(src)
|
||||
faction += "[REF(src)]"
|
||||
GLOB.mob_living_list += src
|
||||
|
||||
|
||||
/mob/living/prepare_huds()
|
||||
..()
|
||||
prepare_data_huds()
|
||||
|
||||
@@ -302,6 +302,7 @@
|
||||
return 1
|
||||
|
||||
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage)
|
||||
if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
|
||||
return FALSE
|
||||
if(has_trait(TRAIT_SHOCKIMMUNE))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
sight = 0
|
||||
see_in_dark = 2
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD)
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD)
|
||||
pressure_resistance = 10
|
||||
|
||||
var/resize = 1 //Badminnery resize
|
||||
|
||||
@@ -217,6 +217,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
return 1
|
||||
|
||||
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!client)
|
||||
return
|
||||
var/deaf_message
|
||||
|
||||
@@ -129,5 +129,6 @@
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
@@ -379,7 +379,7 @@ Difficulty: Very Hard
|
||||
to_chat(user, "It is activated by [activation_method].")
|
||||
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
..()
|
||||
. = ..()
|
||||
if(isliving(speaker))
|
||||
ActivationReaction(speaker, ACTIVATE_SPEECH)
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
stat("Mode",a_intent)
|
||||
|
||||
/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker != src && prob(50)) //Dont imitate ourselves
|
||||
if(!radio_freq || prob(10))
|
||||
if(speech_buffer.len >= 500)
|
||||
@@ -151,7 +152,6 @@
|
||||
speech_buffer |= html_decode(raw_message)
|
||||
if(speaker == src && !client) //If a parrot squawks in the woods and no one is around to hear it, does it make a sound? This code says yes!
|
||||
return message
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/parrot/radio(message, message_mode, list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be.
|
||||
. = ..()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker != src && !radio_freq && !stat)
|
||||
if (speaker in Friends)
|
||||
speech_buffer = list()
|
||||
speech_buffer += speaker
|
||||
speech_buffer += lowertext(html_decode(message))
|
||||
..()
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
|
||||
// see _DEFINES/is_helpers.dm for mob type checks
|
||||
|
||||
/mob/proc/isloyal() //Checks to see if the person contains a mindshield implant, then checks that the implant is actually inside of them
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/isloyal()
|
||||
for(var/obj/item/implant/mindshield/L in implants)
|
||||
return TRUE
|
||||
|
||||
/mob/proc/lowest_buckled_mob()
|
||||
. = src
|
||||
if(buckled && ismob(buckled))
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
else if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
SEND_SIGNAL(C, COMSIG_ADD_MOOD_EVENT, "tased", /datum/mood_event/tased)
|
||||
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
|
||||
if(C.dna && C.dna.check_mutation(HULK))
|
||||
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
|
||||
else if((C.status_flags & CANKNOCKDOWN) && !C.has_trait(TRAIT_STUNIMMUNE))
|
||||
|
||||
@@ -68,11 +68,11 @@
|
||||
..()
|
||||
. = 1
|
||||
|
||||
/datum/reagent/medicine/adminordrazine/nanites
|
||||
name = "Nanites"
|
||||
id = "nanites"
|
||||
description = "Tiny nanomachines capable of rapid cellular regeneration."
|
||||
taste_description = "sludge"
|
||||
/datum/reagent/medicine/adminordrazine/quantum_heal
|
||||
name = "Quantum Medicine"
|
||||
id = "quantum_heal"
|
||||
description = "Rare and experimental particles, that apparently swap the user's body with one from an alternate dimension where it's completely healthy."
|
||||
taste_description = "science"
|
||||
|
||||
/datum/reagent/medicine/synaptizine
|
||||
name = "Synaptizine"
|
||||
@@ -1104,20 +1104,20 @@
|
||||
..()
|
||||
return TRUE
|
||||
|
||||
/datum/reagent/medicine/miningnanites
|
||||
name = "Nanites"
|
||||
id = "miningnanites"
|
||||
description = "It's mining magic. We don't have to explain it."
|
||||
/datum/reagent/medicine/lavaland_extract
|
||||
name = "Lavaland Extract"
|
||||
id = "lavaland_extract"
|
||||
description = "An extract of lavaland atmospheric and mineral elements. Heals the user in small doses, but is extremely toxic otherwise."
|
||||
color = "#C8A5DC" // rgb: 200, 165, 220
|
||||
overdose_threshold = 3 //To prevent people stacking massive amounts of a very strong healing reagent
|
||||
can_synth = FALSE
|
||||
|
||||
/datum/reagent/medicine/miningnanites/on_mob_life(mob/living/carbon/M)
|
||||
/datum/reagent/medicine/lavaland_extract/on_mob_life(mob/living/carbon/M)
|
||||
M.heal_bodypart_damage(5,5)
|
||||
..()
|
||||
return TRUE
|
||||
|
||||
/datum/reagent/medicine/miningnanites/overdose_process(mob/living/M)
|
||||
/datum/reagent/medicine/lavaland_extract/overdose_process(mob/living/M)
|
||||
M.adjustBruteLoss(3*REM, 0)
|
||||
M.adjustFireLoss(3*REM, 0)
|
||||
M.adjustToxLoss(3*REM, 0)
|
||||
|
||||
@@ -1091,7 +1091,7 @@
|
||||
M.emote("drool")
|
||||
..()
|
||||
|
||||
/datum/reagent/nanites
|
||||
/datum/reagent/nanomachines
|
||||
name = "Nanomachines"
|
||||
id = "nanomachines"
|
||||
description = "Microscopic construction robots."
|
||||
@@ -1099,7 +1099,7 @@
|
||||
can_synth = FALSE
|
||||
taste_description = "sludge"
|
||||
|
||||
/datum/reagent/nanites/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0)
|
||||
/datum/reagent/nanomachines/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0)
|
||||
if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection))))
|
||||
L.ForceContractDisease(new /datum/disease/transformation/robot(), FALSE, TRUE)
|
||||
|
||||
|
||||
@@ -64,9 +64,9 @@
|
||||
list_reagents = list("epinephrine" = 30, "omnizine" = 30, "leporazine" = 15, "atropine" = 15)
|
||||
|
||||
/obj/item/reagent_containers/hypospray/combat/nanites
|
||||
desc = "A modified air-needle autoinjector for use in combat situations. Prefilled with expensive medical nanites for rapid healing."
|
||||
desc = "A modified air-needle autoinjector for use in combat situations. Prefilled with experimental medical compounds for rapid healing."
|
||||
volume = 100
|
||||
list_reagents = list("nanites" = 80, "synaptizine" = 20)
|
||||
list_reagents = list("quantum_heal" = 80, "synaptizine" = 20)
|
||||
|
||||
/obj/item/reagent_containers/hypospray/magillitis
|
||||
name = "experimental autoinjector"
|
||||
@@ -158,7 +158,7 @@
|
||||
icon_state = "stimpen"
|
||||
volume = 57
|
||||
amount_per_transfer_from_this = 57
|
||||
list_reagents = list("salbutamol" = 10, "leporazine" = 15, "tricordrazine" = 15, "epinephrine" = 10, "miningnanites" = 2, "omnizine" = 5)
|
||||
list_reagents = list("salbutamol" = 10, "leporazine" = 15, "tricordrazine" = 15, "epinephrine" = 10, "lavaland_extract" = 2, "omnizine" = 5)
|
||||
|
||||
/obj/item/reagent_containers/hypospray/medipen/species_mutator
|
||||
name = "species mutator medipen"
|
||||
|
||||
@@ -285,3 +285,19 @@
|
||||
build_path = /obj/item/circuitboard/computer/apc_control
|
||||
category = list("Computer Boards")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/board/nanite_chamber_control
|
||||
name = "Computer Design (Nanite Chamber Control)"
|
||||
desc = "Allows for the construction of circuit boards used to build a new nanite chamber control console."
|
||||
id = "nanite_chamber_control"
|
||||
build_path = /obj/item/circuitboard/computer/nanite_chamber_control
|
||||
category = list("Computer Boards")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/board/nanite_cloud_control
|
||||
name = "Computer Design (Nanite Cloud Control)"
|
||||
desc = "Allows for the construction of circuit boards used to build a new nanite cloud control console."
|
||||
id = "nanite_cloud_control"
|
||||
build_path = /obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
category = list("Computer Boards")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
@@ -23,6 +23,29 @@
|
||||
category = list("Electronics")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ALL
|
||||
|
||||
///////////////////////////////////
|
||||
//////////Nanite Devices///////////
|
||||
///////////////////////////////////
|
||||
/datum/design/nanite_remote
|
||||
name = "Nanite Remote"
|
||||
desc = "Allows for the construction of a nanite remote."
|
||||
id = "nanite_remote"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_GLASS = 500, MAT_METAL = 500)
|
||||
build_path = /obj/item/nanite_remote
|
||||
category = list("Electronics")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/nanite_scanner
|
||||
name = "Nanite Scanner"
|
||||
desc = "Allows for the construction of a nanite scanner."
|
||||
id = "nanite_scanner"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_GLASS = 500, MAT_METAL = 500)
|
||||
build_path = /obj/item/nanite_scanner
|
||||
category = list("Electronics")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
////////////////////////////////////////
|
||||
//////////Disk Construction Disks///////
|
||||
////////////////////////////////////////
|
||||
@@ -56,6 +79,16 @@
|
||||
category = list("Electronics")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/nanite_disk
|
||||
name = "Nanite Program Disk"
|
||||
desc = "Stores nanite programs."
|
||||
id = "nanite_disk"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 300, MAT_GLASS = 100)
|
||||
build_path = /obj/item/disk/nanite_program
|
||||
category = list("Electronics")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/integrated_printer
|
||||
name = "Integrated circuit printer"
|
||||
desc = "This machine provides all necessary things for circuitry."
|
||||
|
||||
@@ -521,4 +521,36 @@
|
||||
id = "stack_machine"
|
||||
build_path = /obj/item/circuitboard/machine/stacking_machine
|
||||
category = list ("Misc. Machinery")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/board/nanite_chamber
|
||||
name = "Machine Design (Nanite Chamber Board)"
|
||||
desc = "The circuit board for a Nanite Chamber."
|
||||
id = "nanite_chamber"
|
||||
build_path = /obj/item/circuitboard/machine/nanite_chamber
|
||||
category = list("Research Machinery")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/board/public_nanite_chamber
|
||||
name = "Machine Design (Public Nanite Chamber Board)"
|
||||
desc = "The circuit board for a Public Nanite Chamber."
|
||||
id = "public_nanite_chamber"
|
||||
build_path = /obj/item/circuitboard/machine/public_nanite_chamber
|
||||
category = list("Research Machinery")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/board/nanite_programmer
|
||||
name = "Machine Design (Nanite Programmer Board)"
|
||||
desc = "The circuit board for a Nanite Programmer."
|
||||
id = "nanite_programmer"
|
||||
build_path = /obj/item/circuitboard/machine/nanite_programmer
|
||||
category = list("Research Machinery")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/board/nanite_program_hub
|
||||
name = "Machine Design (Nanite Program Hub Board)"
|
||||
desc = "The circuit board for a Nanite Program Hub."
|
||||
id = "nanite_program_hub"
|
||||
build_path = /obj/item/circuitboard/machine/nanite_program_hub
|
||||
category = list("Research Machinery")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
/datum/design/nanites
|
||||
name = "None"
|
||||
desc = "Warn a coder if you see this."
|
||||
id = "default_nanites"
|
||||
build_type = NANITE_COMPILER
|
||||
construction_time = 50
|
||||
category = list()
|
||||
//research_icon = 'icons/obj/device.dmi'
|
||||
//research_icon_state = "nanite_program"
|
||||
var/program_type = /datum/nanite_program
|
||||
|
||||
////////////////////UTILITY NANITES//////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/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."
|
||||
id = "metabolic_nanites"
|
||||
program_type = /datum/nanite_program/metabolic_synthesis
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/viral
|
||||
name = "Viral Replica"
|
||||
desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters."
|
||||
id = "viral_nanites"
|
||||
program_type = /datum/nanite_program/viral
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/monitoring
|
||||
name = "Monitoring"
|
||||
desc = "The nanites monitor the host's vitals and location, sending them to the suit sensor network."
|
||||
id = "monitoring_nanites"
|
||||
program_type = /datum/nanite_program/monitoring
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/self_scan
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
id = "selfscan_nanites"
|
||||
program_type = /datum/nanite_program/triggered/self_scan
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/stealth
|
||||
name = "Stealth"
|
||||
desc = "The nanites hide their activity and programming from superficial scans."
|
||||
id = "stealth_nanites"
|
||||
program_type = /datum/nanite_program/stealth
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/access
|
||||
name = "Subdermal ID"
|
||||
desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access."
|
||||
id = "access_nanites"
|
||||
program_type = /datum/nanite_program/triggered/access
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/relay
|
||||
name = "Relay"
|
||||
desc = "The nanites receive and relay long-range nanite signals."
|
||||
id = "relay_nanites"
|
||||
program_type = /datum/nanite_program/relay
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/repeater
|
||||
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
|
||||
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
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
id = "emp_nanites"
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/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."
|
||||
id = "spreading_nanites"
|
||||
program_type = /datum/nanite_program/spreading
|
||||
category = list("Utility Nanites")
|
||||
|
||||
/datum/design/nanites/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
but it causes occasional software errors due to faulty copies. Not compatible with cloud sync."
|
||||
id = "mitosis_nanites"
|
||||
program_type = /datum/nanite_program/mitosis
|
||||
category = list("Utility Nanites")
|
||||
|
||||
////////////////////MEDICAL NANITES//////////////////////////////////////
|
||||
/datum/design/nanites/regenerative
|
||||
name = "Accelerated Regeneration"
|
||||
desc = "The nanites boost the host's natural regeneration, increasing their healing speed."
|
||||
id = "regenerative_nanites"
|
||||
program_type = /datum/nanite_program/regenerative
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/regenerative_advanced
|
||||
name = "Bio-Reconstruction"
|
||||
desc = "The nanites manually repair and replace organic cells, acting much faster than normal regeneration. \
|
||||
However, this program cannot detect the difference between harmed and unharmed, causing it to consume nanites even if it has no effect."
|
||||
id = "regenerative_plus_nanites"
|
||||
program_type = /datum/nanite_program/regenerative_advanced
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/temperature
|
||||
name = "Temperature Adjustment"
|
||||
desc = "The nanites adjust the host's internal temperature to an ideal level."
|
||||
id = "temperature_nanites"
|
||||
program_type = /datum/nanite_program/temperature
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/purging
|
||||
name = "Blood Purification"
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream."
|
||||
id = "purging_nanites"
|
||||
program_type = /datum/nanite_program/purging
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/purging_advanced
|
||||
name = "Selective Blood Purification"
|
||||
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate."
|
||||
id = "purging_plus_nanites"
|
||||
program_type = /datum/nanite_program/purging_advanced
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/brain_heal
|
||||
name = "Neural Regeneration"
|
||||
desc = "The nanites fix neural connections in the host's brain, reversing brain damage and minor traumas."
|
||||
id = "brainheal_nanites"
|
||||
program_type = /datum/nanite_program/brain_heal
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/brain_heal_advanced
|
||||
name = "Neural Reimaging"
|
||||
desc = "The nanites are able to backup and restore the host's neural connections, potentially replacing entire chunks of missing or damaged brain matter."
|
||||
id = "brainheal_plus_nanites"
|
||||
program_type = /datum/nanite_program/brain_heal_advanced
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/blood_restoring
|
||||
name = "Blood Regeneration"
|
||||
desc = "The nanites stimulate and boost blood cell production in the host."
|
||||
id = "bloodheal_nanites"
|
||||
program_type = /datum/nanite_program/blood_restoring
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/repairing
|
||||
name = "Mechanical Repair"
|
||||
desc = "The nanites fix damage in the host's mechanical limbs."
|
||||
id = "repairing_nanites"
|
||||
program_type = /datum/nanite_program/repairing
|
||||
category = list("Medical Nanites")
|
||||
|
||||
/datum/design/nanites/defib
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites, when triggered, send a defibrillating shock to the host's heart."
|
||||
id = "defib_nanites"
|
||||
program_type = /datum/nanite_program/triggered/defib
|
||||
category = list("Medical Nanites")
|
||||
|
||||
|
||||
////////////////////AUGMENTATION NANITES//////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/nervous
|
||||
name = "Nerve Support"
|
||||
desc = "The nanites act as a secondary nervous system, reducing the amount of time the host is stunned."
|
||||
id = "nervous_nanites"
|
||||
program_type = /datum/nanite_program/nervous
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/hardening
|
||||
name = "Dermal Hardening"
|
||||
desc = "The nanites form a mesh under the host's skin, protecting them from melee and bullet impacts."
|
||||
id = "hardening_nanites"
|
||||
program_type = /datum/nanite_program/hardening
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/refractive
|
||||
name = "Dermal Refractive Surface"
|
||||
desc = "The nanites form a membrane above the host's skin, reducing the effect of laser and energy impacts."
|
||||
id = "refractive_nanites"
|
||||
program_type = /datum/nanite_program/refractive
|
||||
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."
|
||||
id = "coagulating_nanites"
|
||||
program_type = /datum/nanite_program/coagulating
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/conductive
|
||||
name = "Electric Conduction"
|
||||
desc = "The nanites act as a grounding rod for electric shocks, protecting the host. Shocks can still damage the nanites themselves."
|
||||
id = "conductive_nanites"
|
||||
program_type = /datum/nanite_program/conductive
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/adrenaline
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
id = "adrenaline_nanites"
|
||||
program_type = /datum/nanite_program/triggered/adrenaline
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
/datum/design/nanites/mindshield
|
||||
name = "Mental Barrier"
|
||||
desc = "The nanites form a protective membrane around the host's brain, shielding them from abnormal influences while they're active."
|
||||
id = "mindshield_nanites"
|
||||
program_type = /datum/nanite_program/mindshield
|
||||
category = list("Augmentation Nanites")
|
||||
|
||||
////////////////////DEFECTIVE NANITES//////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/glitch
|
||||
name = "Glitch"
|
||||
desc = "A heavy software corruption that causes nanites to gradually break down."
|
||||
id = "glitch_nanites"
|
||||
program_type = /datum/nanite_program/glitch
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/necrotic
|
||||
name = "Necrosis"
|
||||
desc = "The nanites attack internal tissues indiscriminately, causing widespread damage."
|
||||
id = "necrotic_nanites"
|
||||
program_type = /datum/nanite_program/necrotic
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/toxic
|
||||
name = "Toxin Buildup"
|
||||
desc = "The nanites cause a slow but constant toxin buildup inside the host."
|
||||
id = "toxic_nanites"
|
||||
program_type = /datum/nanite_program/toxic
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/suffocating
|
||||
name = "Hypoxemia"
|
||||
desc = "The nanites prevent the host's blood from absorbing oxygen efficiently."
|
||||
id = "suffocating_nanites"
|
||||
program_type = /datum/nanite_program/suffocating
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/brain_misfire
|
||||
name = "Brain Misfire"
|
||||
desc = "The nanites interfere with neural pathways, causing minor psychological disturbances."
|
||||
id = "brainmisfire_nanites"
|
||||
program_type = /datum/nanite_program/brain_misfire
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/skin_decay
|
||||
name = "Dermalysis"
|
||||
desc = "The nanites attack skin cells, causing irritation, rashes, and minor damage."
|
||||
id = "skindecay_nanites"
|
||||
program_type = /datum/nanite_program/skin_decay
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/nerve_decay
|
||||
name = "Nerve Decay"
|
||||
desc = "The nanites attack the host's nerves, causing lack of coordination and short bursts of paralysis."
|
||||
id = "nervedecay_nanites"
|
||||
program_type = /datum/nanite_program/nerve_decay
|
||||
category = list("Defective Nanites")
|
||||
|
||||
/datum/design/nanites/brain_decay
|
||||
name = "Brain-Eating Nanites"
|
||||
desc = "Damages brain cells, gradually decreasing the host's cognitive functions."
|
||||
id = "braindecay_nanites"
|
||||
program_type = /datum/nanite_program/brain_decay
|
||||
category = list("Defective Nanites")
|
||||
|
||||
////////////////////WEAPONIZED NANITES/////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/flesh_eating
|
||||
name = "Cellular Breakdown"
|
||||
desc = "The nanites destroy cellular structures in the host's body, causing brute damage."
|
||||
id = "flesheating_nanites"
|
||||
program_type = /datum/nanite_program/flesh_eating
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/poison
|
||||
name = "Poisoning"
|
||||
desc = "The nanites deliver poisonous chemicals to the host's internal organs, causing toxin damage and vomiting."
|
||||
id = "poison_nanites"
|
||||
program_type = /datum/nanite_program/poison
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/memory_leak
|
||||
name = "Memory Leak"
|
||||
desc = "This program invades the memory space used by other programs, causing frequent corruptions and errors."
|
||||
id = "memleak_nanites"
|
||||
program_type = /datum/nanite_program/memory_leak
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/aggressive_replication
|
||||
name = "Aggressive Replication"
|
||||
desc = "Nanites will consume organic matter to improve their replication rate, damaging the host."
|
||||
id = "aggressive_nanites"
|
||||
program_type = /datum/nanite_program/aggressive_replication
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/meltdown
|
||||
name = "Meltdown"
|
||||
desc = "Causes an internal meltdown inside the nanites, causing internal burns inside the host as well as rapidly destroying the nanite population.\
|
||||
Sets the nanites' safety threshold to 0 when activated."
|
||||
id = "meltdown_nanites"
|
||||
program_type = /datum/nanite_program/meltdown
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/cryo
|
||||
name = "Cryogenic Treatment"
|
||||
desc = "The nanites rapidly skin heat through the host's skin, lowering their temperature."
|
||||
id = "cryo_nanites"
|
||||
program_type = /datum/nanite_program/cryo
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/pyro
|
||||
name = "Sub-Dermal Combustion"
|
||||
desc = "The nanites cause buildup of flammable fluids under the host's skin, then ignites them."
|
||||
id = "pyro_nanites"
|
||||
program_type = /datum/nanite_program/pyro
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/heart_stop
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
id = "heartstop_nanites"
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Blows up all the nanites inside the host in a chain reaction when triggered."
|
||||
id = "explosive_nanites"
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
/datum/design/nanites/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
id = "mindcontrol_nanites"
|
||||
program_type = /datum/nanite_program/mind_control
|
||||
category = list("Weaponized Nanites")
|
||||
|
||||
////////////////////SUPPRESSION NANITES//////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/shock
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
id = "shock_nanites"
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
id = "stun_nanites"
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
id = "sleep_nanites"
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/paralyzing
|
||||
name = "Paralysis"
|
||||
desc = "The nanites actively suppress nervous pulses, effectively paralyzing the host."
|
||||
id = "paralyzing_nanites"
|
||||
program_type = /datum/nanite_program/paralyzing
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/fake_death
|
||||
name = "Death Simulation"
|
||||
desc = "The nanites induce a death-like coma into the host, able to fool most medical scans."
|
||||
id = "fakedeath_nanites"
|
||||
program_type = /datum/nanite_program/fake_death
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/pacifying
|
||||
name = "Pacification"
|
||||
desc = "The nanites suppress the aggression center of the brain, preventing the host from causing direct harm to others."
|
||||
id = "pacifying_nanites"
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/blinding
|
||||
name = "Blindness"
|
||||
desc = "The nanites suppress the host's ocular nerves, blinding them while they're active."
|
||||
id = "blinding_nanites"
|
||||
program_type = /datum/nanite_program/blinding
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/mute
|
||||
name = "Mute"
|
||||
desc = "The nanites suppress the host's speech, making them mute while they're active."
|
||||
id = "mute_nanites"
|
||||
program_type = /datum/nanite_program/mute
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/voice
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
id = "voice_nanites"
|
||||
program_type = /datum/nanite_program/triggered/voice
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
id = "speech_nanites"
|
||||
program_type = /datum/nanite_program/triggered/speech
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
/datum/design/nanites/hallucination
|
||||
name = "Hallucination"
|
||||
desc = "The nanites make the host see and hear things that aren't real."
|
||||
id = "hallucination_nanites"
|
||||
program_type = /datum/nanite_program/triggered/hallucination
|
||||
category = list("Suppression Nanites")
|
||||
|
||||
////////////////////SENSOR NANITES//////////////////////////////////////
|
||||
|
||||
/datum/design/nanites/sensor_health
|
||||
name = "Health Sensor"
|
||||
desc = "The nanites receive a signal when the host's health is above/below a certain percentage."
|
||||
id = "sensor_health_nanites"
|
||||
program_type = /datum/nanite_program/sensor/health
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor_damage
|
||||
name = "Damage Sensor"
|
||||
desc = "The nanites receive a signal when a host's specific damage type is above/below a target value."
|
||||
id = "sensor_damage_nanites"
|
||||
program_type = /datum/nanite_program/sensor/damage
|
||||
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."
|
||||
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."
|
||||
id = "sensor_death_nanites"
|
||||
program_type = /datum/nanite_program/sensor/death
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor_voice
|
||||
name = "Voice Sensor"
|
||||
desc = "Sends a signal when the nanites hear a determined word or sentence."
|
||||
id = "sensor_voice_nanites"
|
||||
program_type = /datum/nanite_program/sensor/voice
|
||||
category = list("Sensor Nanites")
|
||||
|
||||
/datum/design/nanites/sensor__nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
id = "sensor_nanite_volume"
|
||||
program_type = /datum/nanite_program/sensor/nanite_volume
|
||||
category = list("Sensor Nanites")
|
||||
@@ -0,0 +1,227 @@
|
||||
/obj/machinery/nanite_chamber
|
||||
name = "nanite chamber"
|
||||
desc = "A device that can scan, reprogram, and inject nanites."
|
||||
circuit = /obj/item/circuitboard/machine/nanite_chamber
|
||||
icon = 'icons/obj/machines/nanite_chamber.dmi'
|
||||
icon_state = "nanite_chamber"
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
idle_power_usage = 50
|
||||
active_power_usage = 300
|
||||
occupant_typecache = list(/mob/living)
|
||||
|
||||
var/obj/machinery/computer/nanite_chamber_control/console
|
||||
var/locked = FALSE
|
||||
var/breakout_time = 1200
|
||||
var/scan_level
|
||||
var/busy = FALSE
|
||||
var/busy_icon_state
|
||||
var/busy_message
|
||||
var/message_cooldown = 0
|
||||
|
||||
/obj/machinery/nanite_chamber/RefreshParts()
|
||||
scan_level = 0
|
||||
for(var/obj/item/stock_parts/scanning_module/P in component_parts)
|
||||
scan_level += P.rating
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/set_busy(status, message, working_icon)
|
||||
busy = status
|
||||
busy_message = message
|
||||
busy_icon_state = working_icon
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/set_safety(threshold)
|
||||
if(!occupant)
|
||||
return
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_SAFETY, threshold)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/set_cloud(cloud_id)
|
||||
if(!occupant)
|
||||
return
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/inject_nanites()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO OMINOUS MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing injection protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Analyzing host bio-structure...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Priming nanites...", "[initial(icon_state)]_active"),40)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Injecting...", "[initial(icon_state)]_active"),70)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Activating nanites...", "[initial(icon_state)]_falling"),110)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state),130)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_injection(locked_state)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
occupant.AddComponent(/datum/component/nanites, 100)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/install_program(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing installation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Installing program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_installation, locked_state, NP),55)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_installation(locked_state, datum/nanite_program/NP)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
|
||||
SEND_SIGNAL(occupant, COMSIG_NANITE_ADD_PROGRAM, NP.copy())
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/uninstall_program(datum/nanite_program/NP)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO COMPUTERY MACHINE SOUNDS
|
||||
set_busy(TRUE, "Initializing uninstallation protocol...", "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Connecting to nanite framework...", "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Uninstalling program...", "[initial(icon_state)]_falling"),35)
|
||||
addtimer(CALLBACK(src, .proc/complete_uninstallation, locked_state, NP),55)
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/complete_uninstallation(locked_state, datum/nanite_program/NP)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
qdel(NP)
|
||||
|
||||
/obj/machinery/nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
/obj/machinery/nanite_chamber/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
if(state_open)
|
||||
close_machine()
|
||||
return
|
||||
|
||||
else if(locked)
|
||||
to_chat(user, "<span class='notice'>The bolts are locked down, securing the door shut.</span>")
|
||||
return
|
||||
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/nanite_chamber/container_resist(mob/living/user)
|
||||
if(!locked)
|
||||
open_machine()
|
||||
return
|
||||
if(busy)
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
locked = FALSE
|
||||
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
|
||||
"<span class='notice'>You successfully break out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/nanite_chamber/close_machine(mob/living/carbon/user)
|
||||
if(!state_open)
|
||||
return FALSE
|
||||
|
||||
..(user)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/nanite_chamber/open_machine()
|
||||
if(state_open)
|
||||
return FALSE
|
||||
|
||||
..()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/nanite_chamber/relaymove(mob/user as mob)
|
||||
if(user.stat || locked)
|
||||
if(message_cooldown <= world.time)
|
||||
message_cooldown = world.time + 50
|
||||
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
|
||||
return
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/nanite_chamber/attackby(obj/item/I, mob/user, params)
|
||||
if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant...
|
||||
update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed
|
||||
return
|
||||
|
||||
if(default_pry_open(I))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(I))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/nanite_chamber/interact(mob/user)
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
return
|
||||
close_machine(target)
|
||||
@@ -0,0 +1,158 @@
|
||||
/obj/machinery/computer/nanite_chamber_control
|
||||
name = "nanite chamber control console"
|
||||
desc = "Controls a connected nanite chamber. Can inoculate nanites, load programs, and analyze existing nanite swarms."
|
||||
var/obj/machinery/nanite_chamber/chamber
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
|
||||
icon_screen = "nanite_chamber_control"
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/Initialize()
|
||||
. = ..()
|
||||
find_chamber()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/proc/find_chamber()
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/C = locate(/obj/machinery/nanite_chamber, get_step(src, direction))
|
||||
if(C)
|
||||
var/obj/machinery/nanite_chamber/NC = C
|
||||
chamber = NC
|
||||
NC.console = src
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/interact()
|
||||
if(!chamber)
|
||||
find_chamber()
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_chamber_control", name, 550, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
|
||||
if(!chamber)
|
||||
data["status_msg"] = "No chamber detected."
|
||||
return data
|
||||
|
||||
if(!chamber.occupant)
|
||||
data["status_msg"] = "No occupant detected."
|
||||
return data
|
||||
|
||||
var/mob/living/L = chamber.occupant
|
||||
|
||||
if(!(MOB_ORGANIC in L.mob_biotypes) && !(MOB_UNDEAD in L.mob_biotypes))
|
||||
data["status_msg"] = "Occupant not compatible with nanites."
|
||||
return data
|
||||
|
||||
if(chamber.busy)
|
||||
data["status_msg"] = chamber.busy_message
|
||||
return data
|
||||
|
||||
data["scan_level"] = chamber.scan_level
|
||||
data["locked"] = chamber.locked
|
||||
data["occupant_name"] = chamber.occupant.name
|
||||
|
||||
SEND_SIGNAL(L, COMSIG_NANITE_UI_DATA, data, chamber.scan_level)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/nanite_chamber_control/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("toggle_lock")
|
||||
chamber.locked = !chamber.locked
|
||||
chamber.update_icon()
|
||||
. = TRUE
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("set_safety")
|
||||
var/threshold = input("Set safety threshold (0-500):", name, null) as null|num
|
||||
if(!isnull(threshold))
|
||||
chamber.set_safety(CLAMP(round(threshold, 1),0,500))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' safety threshold was set to [threshold] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("set_cloud")
|
||||
var/cloud_id = input("Set cloud ID (1-100, 0 to disable):", name, null) as null|num
|
||||
if(!isnull(cloud_id))
|
||||
chamber.set_cloud(CLAMP(round(cloud_id, 1),0,100))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
investigate_log("[key_name(chamber.occupant)]'s nanites' cloud id was set to [cloud_id] by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("connect_chamber")
|
||||
find_chamber()
|
||||
. = TRUE
|
||||
if("nanite_injection")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
chamber.inject_nanites()
|
||||
investigate_log("[key_name(chamber.occupant)] was injected with nanites by [key_name(usr)] using a nanite chamber.", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("add_program")
|
||||
if(!disk || !chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
chamber.install_program(disk.program)
|
||||
investigate_log("Program of type [disk.program.type] was installed into [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_program")
|
||||
if(!chamber || !chamber.occupant)
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
var/list/nanite_programs = list()
|
||||
SEND_SIGNAL(chamber.occupant, COMSIG_NANITE_GET_PROGRAMS, nanite_programs)
|
||||
if(LAZYLEN(nanite_programs))
|
||||
var/datum/nanite_program/P = nanite_programs[text2num(params["program_id"])]
|
||||
chamber.uninstall_program(P)
|
||||
investigate_log("Program of type [P.type] was uninstalled from [key_name(chamber.occupant)]'s nanites with a nanite chamber by [key_name(usr)].", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
@@ -0,0 +1,196 @@
|
||||
/obj/machinery/computer/nanite_cloud_controller
|
||||
name = "nanite cloud controller"
|
||||
desc = "Stores and controls nanite cloud backups."
|
||||
circuit = /obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_cloud_controller"
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/current_view = 0 //0 is the main menu, any other number is the page of the backup with that ID
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/Destroy()
|
||||
QDEL_LIST(cloud_backups) //rip backups
|
||||
eject()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) ||!user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/proc/get_backup(cloud_id)
|
||||
for(var/I in cloud_backups)
|
||||
var/datum/nanite_cloud_backup/backup = I
|
||||
if(backup.cloud_id == cloud_id)
|
||||
return backup
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/proc/generate_backup(cloud_id, mob/user)
|
||||
if(SSnanites.get_cloud_backup(cloud_id, TRUE))
|
||||
to_chat(user, "<span class='warning'>Cloud ID already registered.</span>")
|
||||
return
|
||||
|
||||
var/datum/nanite_cloud_backup/backup = new(src)
|
||||
var/datum/component/nanites/cloud_copy = new(backup)
|
||||
backup.cloud_id = cloud_id
|
||||
backup.nanites = cloud_copy
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_cloud_control", name, 600, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
disk_data["use_rate"] = P.use_rate
|
||||
disk_data["can_trigger"] = P.can_trigger
|
||||
disk_data["trigger_cost"] = P.trigger_cost
|
||||
disk_data["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
|
||||
disk_data["activated"] = P.activated
|
||||
disk_data["activation_delay"] = P.activation_delay
|
||||
disk_data["timer"] = P.timer
|
||||
disk_data["activation_code"] = P.activation_code
|
||||
disk_data["deactivation_code"] = P.deactivation_code
|
||||
disk_data["kill_code"] = P.kill_code
|
||||
disk_data["trigger_code"] = P.trigger_code
|
||||
disk_data["timer_type"] = P.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
disk_data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
disk_data["has_extra_settings"] = TRUE
|
||||
data["disk"] = disk_data
|
||||
|
||||
data["current_view"] = current_view
|
||||
if(current_view)
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
data["cloud_backup"] = TRUE
|
||||
var/list/cloud_programs = list()
|
||||
var/id = 1
|
||||
for(var/datum/nanite_program/P in nanites.programs)
|
||||
var/list/cloud_program = list()
|
||||
cloud_program["name"] = P.name
|
||||
cloud_program["desc"] = P.desc
|
||||
cloud_program["id"] = id
|
||||
cloud_program["use_rate"] = P.use_rate
|
||||
cloud_program["can_trigger"] = P.can_trigger
|
||||
cloud_program["trigger_cost"] = P.trigger_cost
|
||||
cloud_program["trigger_cooldown"] = P.trigger_cooldown / 10
|
||||
cloud_program["activated"] = P.activated
|
||||
cloud_program["activation_delay"] = P.activation_delay
|
||||
cloud_program["timer"] = P.timer
|
||||
cloud_program["timer_type"] = P.get_timer_type_text()
|
||||
cloud_program["activation_code"] = P.activation_code
|
||||
cloud_program["deactivation_code"] = P.deactivation_code
|
||||
cloud_program["kill_code"] = P.kill_code
|
||||
cloud_program["trigger_code"] = P.trigger_code
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in P.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = P.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
cloud_program["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
cloud_program["has_extra_settings"] = TRUE
|
||||
id++
|
||||
cloud_programs += list(cloud_program)
|
||||
data["cloud_programs"] = cloud_programs
|
||||
else
|
||||
var/list/backup_list = list()
|
||||
for(var/X in cloud_backups)
|
||||
var/datum/nanite_cloud_backup/backup = X
|
||||
var/list/cloud_backup = list()
|
||||
cloud_backup["cloud_id"] = backup.cloud_id
|
||||
backup_list += list(cloud_backup)
|
||||
data["cloud_backups"] = backup_list
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("set_view")
|
||||
current_view = text2num(params["view"])
|
||||
. = TRUE
|
||||
if("create_backup")
|
||||
var/cloud_id = input("Choose a cloud ID (1-100):", name, null) as null|num
|
||||
if(!isnull(cloud_id))
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
cloud_id = CLAMP(round(cloud_id, 1),1,100)
|
||||
generate_backup(cloud_id, usr)
|
||||
. = TRUE
|
||||
if("delete_backup")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
qdel(backup)
|
||||
investigate_log("[key_name(usr)] deleted the nanite cloud backup #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("upload_program")
|
||||
if(disk && disk.program)
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
nanites.add_program(disk.program.copy())
|
||||
investigate_log("[key_name(usr)] uploaded program [disk.program.name] to cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_program")
|
||||
var/datum/nanite_cloud_backup/backup = get_backup(current_view)
|
||||
if(backup)
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
investigate_log("[key_name(usr)] deleted program [P.name] from cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
qdel(P)
|
||||
. = TRUE
|
||||
|
||||
/datum/nanite_cloud_backup
|
||||
var/cloud_id = 0
|
||||
var/datum/component/nanites/nanites
|
||||
var/obj/machinery/computer/nanite_cloud_controller/storage
|
||||
|
||||
/datum/nanite_cloud_backup/New(obj/machinery/computer/nanite_cloud_controller/_storage)
|
||||
storage = _storage
|
||||
storage.cloud_backups += src
|
||||
SSnanites.cloud_backups += src
|
||||
|
||||
/datum/nanite_cloud_backup/Destroy()
|
||||
storage.cloud_backups -= src
|
||||
SSnanites.cloud_backups -= src
|
||||
return ..()
|
||||
@@ -0,0 +1,151 @@
|
||||
/obj/item/nanite_hijacker
|
||||
name = "nanite remote control" //fake name
|
||||
desc = "A device that can load nanite programming disks, edit them at will, and imprint them to nanites remotely."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
item_flags = NOBLUDGEON
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/obj/item/nanite_hijacker/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(disk)
|
||||
eject()
|
||||
|
||||
/obj/item/nanite_hijacker/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/disk/nanite_program))
|
||||
var/obj/item/disk/nanite_program/N = I
|
||||
if(disk)
|
||||
eject()
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/nanite_hijacker/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
program = null
|
||||
|
||||
/obj/item/nanite_hijacker/afterattack(atom/target, mob/user, etc)
|
||||
if(!disk || !disk.program)
|
||||
return
|
||||
if(isliving(target))
|
||||
var/success = SEND_SIGNAL(target, COMSIG_NANITE_ADD_PROGRAM, program.copy())
|
||||
switch(success)
|
||||
if(NONE)
|
||||
to_chat(user, "<span class='notice'>You don't detect any nanites in [target].</span>")
|
||||
if(COMPONENT_PROGRAM_INSTALLED)
|
||||
to_chat(user, "<span class='notice'>You insert the currently loaded program into [target]'s nanites.</span>")
|
||||
if(COMPONENT_PROGRAM_NOT_INSTALLED)
|
||||
to_chat(user, "<span class='warning'>You try to insert the currently loaded program into [target]'s nanites, but the installation fails.</span>")
|
||||
|
||||
//Same UI as the nanite programmer, as it pretty much does the same
|
||||
/obj/item/nanite_hijacker/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", "Internal Nanite Programmer", 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_hijacker/ui_data()
|
||||
var/list/data = list()
|
||||
data["has_disk"] = istype(disk)
|
||||
data["has_program"] = istype(program)
|
||||
if(program)
|
||||
data["name"] = program.name
|
||||
data["desc"] = program.desc
|
||||
data["use_rate"] = program.use_rate
|
||||
data["can_trigger"] = program.can_trigger
|
||||
data["trigger_cost"] = program.trigger_cost
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_hijacker/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
program.activation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("deactivation")
|
||||
program.deactivation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("kill")
|
||||
program.kill_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("trigger")
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if(!isnull(timer))
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
@@ -0,0 +1,9 @@
|
||||
/obj/item/nanite_injector
|
||||
name = "nanite injector (FOR TESTING)"
|
||||
desc = "Injects nanites into the user."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
|
||||
/obj/item/nanite_injector/attack_self(mob/user)
|
||||
user.AddComponent(/datum/component/nanites, 150)
|
||||
@@ -0,0 +1,118 @@
|
||||
/obj/machinery/nanite_program_hub
|
||||
name = "nanite program hub"
|
||||
desc = "Compiles nanite programs from the techweb servers and downloads them into disks."
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_program_hub"
|
||||
circuit = /obj/item/circuitboard/machine/nanite_program_hub
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/techweb/linked_techweb
|
||||
var/current_category = "Main"
|
||||
var/detail_view = FALSE
|
||||
var/categories = list(
|
||||
list(name = "Utility Nanites"),
|
||||
list(name = "Medical Nanites"),
|
||||
list(name = "Sensor Nanites"),
|
||||
list(name = "Augmentation Nanites"),
|
||||
list(name = "Suppression Nanites"),
|
||||
list(name = "Weaponized Nanites")
|
||||
)
|
||||
|
||||
/obj/machinery/nanite_program_hub/Initialize()
|
||||
. = ..()
|
||||
linked_techweb = SSresearch.science_tech
|
||||
|
||||
/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
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/nanite_program_hub/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_program_hub", name, 500, 700, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //to avoid making the whole program list every second
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_data()
|
||||
var/list/data = list()
|
||||
if(disk)
|
||||
data["has_disk"] = TRUE
|
||||
var/list/disk_data = list()
|
||||
var/datum/nanite_program/P = disk.program
|
||||
if(P)
|
||||
data["has_program"] = TRUE
|
||||
disk_data["name"] = P.name
|
||||
disk_data["desc"] = P.desc
|
||||
data["disk"] = disk_data
|
||||
|
||||
data["detail_view"] = detail_view
|
||||
data["category"] = current_category
|
||||
|
||||
if(current_category != "Main")
|
||||
var/list/program_list = list()
|
||||
for(var/i in linked_techweb.researched_designs)
|
||||
var/datum/design/nanites/D = linked_techweb.researched_designs[i]
|
||||
if(!istype(D))
|
||||
continue
|
||||
if(current_category in D.category)
|
||||
var/list/program_design = list()
|
||||
program_design["id"] = D.id
|
||||
program_design["name"] = D.name
|
||||
program_design["desc"] = D.desc
|
||||
program_list += list(program_design)
|
||||
data["program_list"] = program_list
|
||||
else
|
||||
data["categories"] = categories
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/nanite_program_hub/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("download")
|
||||
if(!disk)
|
||||
return
|
||||
var/datum/design/nanites/downloaded = linked_techweb.isDesignResearchedID(params["program_id"]) //check if it's a valid design
|
||||
if(!istype(downloaded))
|
||||
return
|
||||
if(disk.program)
|
||||
qdel(disk.program)
|
||||
disk.program = new downloaded.program_type
|
||||
disk.name = "[initial(disk.name)] \[[disk.program.name]\]"
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
|
||||
. = TRUE
|
||||
if("set_category")
|
||||
var/new_category = params["category"]
|
||||
current_category = new_category
|
||||
. = TRUE
|
||||
if("toggle_details")
|
||||
detail_view = !detail_view
|
||||
. = TRUE
|
||||
if("clear")
|
||||
if(disk && disk.program)
|
||||
qdel(disk.program)
|
||||
disk.program = null
|
||||
disk.name = initial(disk.name)
|
||||
. = TRUE
|
||||
@@ -0,0 +1,140 @@
|
||||
/obj/machinery/nanite_programmer
|
||||
name = "nanite programmer"
|
||||
desc = "A device that can edit nanite program disks to adjust their functionality."
|
||||
var/obj/item/disk/nanite_program/disk
|
||||
var/datum/nanite_program/program
|
||||
circuit = /obj/item/circuitboard/machine/nanite_programmer
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "nanite_programmer"
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
|
||||
/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
|
||||
if(disk)
|
||||
eject(user)
|
||||
if(user.transferItemToLoc(N, src))
|
||||
to_chat(user, "<span class='notice'>You insert [N] into [src]</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
disk = N
|
||||
program = N.program
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/nanite_programmer/proc/eject(mob/living/user)
|
||||
if(!disk)
|
||||
return
|
||||
if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(disk))
|
||||
disk.forceMove(drop_location())
|
||||
disk = null
|
||||
program = null
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_programmer", name, 600, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_data()
|
||||
var/list/data = list()
|
||||
data["has_disk"] = istype(disk)
|
||||
data["has_program"] = istype(program)
|
||||
if(program)
|
||||
data["name"] = program.name
|
||||
data["desc"] = program.desc
|
||||
data["use_rate"] = program.use_rate
|
||||
data["can_trigger"] = program.can_trigger
|
||||
data["trigger_cost"] = program.trigger_cost
|
||||
data["trigger_cooldown"] = program.trigger_cooldown / 10
|
||||
|
||||
data["activated"] = program.activated
|
||||
data["activation_delay"] = program.activation_delay
|
||||
data["timer"] = program.timer
|
||||
data["activation_code"] = program.activation_code
|
||||
data["deactivation_code"] = program.deactivation_code
|
||||
data["kill_code"] = program.kill_code
|
||||
data["trigger_code"] = program.trigger_code
|
||||
data["timer_type"] = program.get_timer_type_text()
|
||||
|
||||
var/list/extra_settings = list()
|
||||
for(var/X in program.extra_settings)
|
||||
var/list/setting = list()
|
||||
setting["name"] = X
|
||||
setting["value"] = program.get_extra_setting(X)
|
||||
extra_settings += list(setting)
|
||||
data["extra_settings"] = extra_settings
|
||||
if(LAZYLEN(extra_settings))
|
||||
data["has_extra_settings"] = TRUE
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/nanite_programmer/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
eject(usr)
|
||||
. = TRUE
|
||||
if("toggle_active")
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
program.activated = !program.activated //we don't use the activation procs since we aren't in a mob
|
||||
if(program.activated)
|
||||
program.activation_delay = 0
|
||||
. = TRUE
|
||||
if("set_code")
|
||||
var/new_code = input("Set code (0000-9999):", name, null) as null|num
|
||||
if(!isnull(new_code))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
else
|
||||
return
|
||||
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
var/target_code = params["target_code"]
|
||||
switch(target_code)
|
||||
if("activation")
|
||||
program.activation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("deactivation")
|
||||
program.deactivation_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("kill")
|
||||
program.kill_code = CLAMP(round(new_code, 1),0,9999)
|
||||
if("trigger")
|
||||
program.trigger_code = CLAMP(round(new_code, 1),0,9999)
|
||||
. = TRUE
|
||||
if("set_extra_setting")
|
||||
program.set_extra_setting(usr, params["target_setting"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
if("set_activation_delay")
|
||||
var/delay = input("Set activation delay in seconds (0-1800):", name, program.activation_delay) as null|num
|
||||
if(!isnull(delay))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
delay = CLAMP(round(delay, 1),0,1800)
|
||||
program.activation_delay = delay
|
||||
if(delay)
|
||||
program.activated = FALSE
|
||||
. = TRUE
|
||||
if("set_timer")
|
||||
var/timer = input("Set timer in seconds (10-3600):", name, program.timer) as null|num
|
||||
if(!isnull(timer))
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!timer == 0)
|
||||
timer = CLAMP(round(timer, 1),10,3600)
|
||||
program.timer = timer
|
||||
. = TRUE
|
||||
if("set_timer_type")
|
||||
var/new_type = input("Choose the timer effect","Timer Effect") as null|anything in list("Deactivate","Self-Delete","Trigger","Reset Activation Timer")
|
||||
if(new_type)
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
switch(new_type)
|
||||
if("Deactivate")
|
||||
program.timer_type = NANITE_TIMER_DEACTIVATE
|
||||
if("Self-Delete")
|
||||
program.timer_type = NANITE_TIMER_SELFDELETE
|
||||
if("Trigger")
|
||||
program.timer_type = NANITE_TIMER_TRIGGER
|
||||
if("Reset Activation Timer")
|
||||
program.timer_type = NANITE_TIMER_RESET
|
||||
. = TRUE
|
||||
@@ -0,0 +1,254 @@
|
||||
/datum/nanite_program
|
||||
var/name = "Generic Nanite Program"
|
||||
var/desc = "Warn a coder if you can read this."
|
||||
|
||||
var/datum/component/nanites/nanites
|
||||
var/mob/living/host_mob
|
||||
|
||||
var/use_rate = 0 //Amount of nanites used while active
|
||||
var/unique = TRUE //If there can be more than one copy in the same nanites
|
||||
var/can_trigger = FALSE //If the nanites have a trigger function (used for the programming UI)
|
||||
var/trigger_cost = 0 //Amount of nanites required to trigger
|
||||
var/trigger_cooldown = 50 //Deciseconds required between each trigger activation
|
||||
var/next_trigger = 0 //World time required for the next trigger activation
|
||||
var/timer_counter = 0 //Counts up while active. Used for the timer and the activation delay.
|
||||
var/program_flags = NONE
|
||||
var/passive_enabled = FALSE //If the nanites have an on/off-style effect, it's tracked by this var
|
||||
|
||||
var/list/rogue_types = list(/datum/nanite_program/glitch) //What this can turn into if it glitches.
|
||||
//As a rule of thumb, these should be:
|
||||
//A: simpler
|
||||
//B: negative
|
||||
//C: affecting the same parts of the body, roughly
|
||||
//B is mostly a consequence of A: it's always going to be simpler to cause damage than to repair it, so a software bug will not randomly make the flesh eating
|
||||
//nanites learn how to repair cells.
|
||||
//Given enough glitch-swapping you'll end up with stuff like necrotic or toxic nanites, which are very simple as they just try to eat what's in front of them
|
||||
//or just lie around polluting the blood
|
||||
|
||||
|
||||
//The following vars are customizable
|
||||
var/activated = TRUE //If FALSE, the program won't process, disables passive effects, can't trigger and doesn't consume nanites
|
||||
var/activation_delay = 0 //Seconds before the program self-activates.
|
||||
var/timer = 0 //Seconds before the timer effect activates. Starts counting AFTER the activation delay
|
||||
var/timer_type = NANITE_TIMER_DEACTIVATE //What happens when the timer runs out
|
||||
|
||||
//Signal codes, these handle remote input to the nanites. If set to 0 they'll ignore signals.
|
||||
var/activation_code = 0 //Code that activates the program [1-9999]
|
||||
var/deactivation_code = 0 //Code that deactivates the program [1-9999]
|
||||
var/kill_code = 0 //Code that permanently removes the program [1-9999]
|
||||
var/trigger_code = 0 //Code that triggers the program (if available) [1-9999]
|
||||
|
||||
//Extra settings
|
||||
//Must be listed in text form, with the same title they'll be displayed in the programmer UI
|
||||
//Changing these values is handled by set_extra_setting()
|
||||
//Viewing these values is handled by get_extra_setting()
|
||||
//Copying these values is handled by copy_extra_settings_to()
|
||||
var/list/extra_settings = list()
|
||||
|
||||
/datum/nanite_program/triggered
|
||||
use_rate = 0
|
||||
trigger_cost = 5
|
||||
trigger_cooldown = 50
|
||||
can_trigger = TRUE
|
||||
|
||||
/datum/nanite_program/Destroy()
|
||||
if(host_mob)
|
||||
if(activated)
|
||||
deactivate()
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
if(nanites)
|
||||
nanites.programs -= src
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/proc/copy()
|
||||
var/datum/nanite_program/new_program = new type()
|
||||
|
||||
new_program.activated = activated
|
||||
new_program.activation_delay = activation_delay
|
||||
new_program.timer = timer
|
||||
new_program.timer_type = timer_type
|
||||
new_program.activation_code = activation_code
|
||||
new_program.deactivation_code = deactivation_code
|
||||
new_program.kill_code = kill_code
|
||||
new_program.trigger_code = trigger_code
|
||||
copy_extra_settings_to(new_program)
|
||||
|
||||
return new_program
|
||||
|
||||
/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE)
|
||||
if(copy_activated)
|
||||
target.activated = activated
|
||||
target.activation_delay = activation_delay
|
||||
target.timer = timer
|
||||
target.timer_type = timer_type
|
||||
target.activation_code = activation_code
|
||||
target.deactivation_code = deactivation_code
|
||||
target.kill_code = kill_code
|
||||
target.trigger_code = trigger_code
|
||||
copy_extra_settings_to(target)
|
||||
|
||||
/datum/nanite_program/proc/set_extra_setting(user, setting)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/get_extra_setting(setting)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/copy_extra_settings_to(datum/nanite_program/target)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/on_add(datum/component/nanites/_nanites)
|
||||
nanites = _nanites
|
||||
if(nanites.host_mob)
|
||||
on_mob_add()
|
||||
|
||||
/datum/nanite_program/proc/on_mob_add()
|
||||
host_mob = nanites.host_mob
|
||||
if(activated) //apply activation effects if it starts active
|
||||
activate()
|
||||
|
||||
/datum/nanite_program/proc/toggle()
|
||||
if(!activated)
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
|
||||
/datum/nanite_program/proc/activate()
|
||||
activated = TRUE
|
||||
|
||||
/datum/nanite_program/proc/deactivate()
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
activated = FALSE
|
||||
|
||||
/datum/nanite_program/proc/on_process()
|
||||
timer_counter++
|
||||
|
||||
if(activation_delay)
|
||||
if(activated && timer_counter < activation_delay)
|
||||
deactivate()
|
||||
else if(!activated && timer_counter >= activation_delay)
|
||||
activate()
|
||||
if(!activated)
|
||||
return
|
||||
|
||||
if(timer && timer_counter > timer)
|
||||
if(timer_type == NANITE_TIMER_DEACTIVATE)
|
||||
deactivate()
|
||||
else if(timer_type == NANITE_TIMER_SELFDELETE)
|
||||
qdel(src)
|
||||
else if(can_trigger && timer_type == NANITE_TIMER_TRIGGER)
|
||||
trigger()
|
||||
timer_counter = activation_delay
|
||||
else if(timer_type == NANITE_TIMER_RESET)
|
||||
timer_counter = 0
|
||||
if(check_conditions() && consume_nanites(use_rate))
|
||||
if(!passive_enabled)
|
||||
enable_passive_effect()
|
||||
active_effect()
|
||||
else
|
||||
if(passive_enabled)
|
||||
disable_passive_effect()
|
||||
|
||||
//If false, disables active and passive effects, but doesn't consume nanites
|
||||
//Can be used to avoid consuming nanites for nothing
|
||||
/datum/nanite_program/proc/check_conditions()
|
||||
return TRUE
|
||||
|
||||
//Constantly procs as long as the program is active
|
||||
/datum/nanite_program/proc/active_effect()
|
||||
return
|
||||
|
||||
//Procs once when the program activates
|
||||
/datum/nanite_program/proc/enable_passive_effect()
|
||||
passive_enabled = TRUE
|
||||
|
||||
//Procs once when the program deactivates
|
||||
/datum/nanite_program/proc/disable_passive_effect()
|
||||
passive_enabled = FALSE
|
||||
|
||||
/datum/nanite_program/proc/trigger()
|
||||
if(!activated)
|
||||
return FALSE
|
||||
if(world.time < next_trigger)
|
||||
return FALSE
|
||||
if(!consume_nanites(trigger_cost))
|
||||
return FALSE
|
||||
next_trigger = world.time + trigger_cooldown
|
||||
return TRUE
|
||||
|
||||
/datum/nanite_program/proc/consume_nanites(amount, force = FALSE)
|
||||
return nanites.consume_nanites(amount, force)
|
||||
|
||||
/datum/nanite_program/proc/on_emp(severity)
|
||||
if(program_flags & NANITE_EMP_IMMUNE)
|
||||
return
|
||||
if(prob(80 / severity))
|
||||
software_error()
|
||||
|
||||
/datum/nanite_program/proc/on_shock(shock_damage)
|
||||
if(!program_flags & NANITE_SHOCK_IMMUNE)
|
||||
if(prob(10))
|
||||
software_error()
|
||||
else if(prob(33))
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_program/proc/on_minor_shock()
|
||||
if(!program_flags & NANITE_SHOCK_IMMUNE)
|
||||
if(prob(10))
|
||||
software_error()
|
||||
|
||||
/datum/nanite_program/proc/on_death()
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
return
|
||||
|
||||
/datum/nanite_program/proc/software_error(type)
|
||||
if(!type)
|
||||
type = rand(1,5)
|
||||
switch(type)
|
||||
if(1)
|
||||
qdel(src) //kill switch
|
||||
return
|
||||
if(2) //deprogram codes
|
||||
activation_code = 0
|
||||
deactivation_code = 0
|
||||
kill_code = 0
|
||||
trigger_code = 0
|
||||
if(3)
|
||||
toggle() //enable/disable
|
||||
if(4)
|
||||
if(can_trigger)
|
||||
trigger()
|
||||
if(5) //Program is scrambled and does something different
|
||||
var/rogue_type = pick(rogue_types)
|
||||
var/datum/nanite_program/rogue = new rogue_type
|
||||
nanites.add_program(rogue, src)
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_program/proc/receive_signal(code, source)
|
||||
if(activation_code && code == activation_code && !activated)
|
||||
activate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
else if(deactivation_code && code == deactivation_code && activated)
|
||||
deactivate()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deactivated by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(can_trigger && trigger_code && code == trigger_code)
|
||||
trigger()
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
if(kill_code && code == kill_code)
|
||||
host_mob.investigate_log("[host_mob]'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES)
|
||||
qdel(src)
|
||||
|
||||
/datum/nanite_program/proc/get_timer_type_text()
|
||||
switch(timer_type)
|
||||
if(NANITE_TIMER_DEACTIVATE)
|
||||
return "Deactivate"
|
||||
if(NANITE_TIMER_SELFDELETE)
|
||||
return "Self-Delete"
|
||||
if(NANITE_TIMER_TRIGGER)
|
||||
return "Trigger"
|
||||
if(NANITE_TIMER_RESET)
|
||||
return "Reset Activation Timer"
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//Programs that buff the host in generally passive ways.
|
||||
|
||||
/datum/nanite_program/nervous
|
||||
name = "Nerve Support"
|
||||
desc = "The nanites act as a secondary nervous system, reducing the amount of time the host is stunned."
|
||||
use_rate = 1.5
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/nervous/enable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.stun_mod *= 0.5
|
||||
|
||||
/datum/nanite_program/nervous/active_effect()
|
||||
. = ..()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.adjustStaminaLoss(-2)
|
||||
|
||||
/datum/nanite_program/nervous/disable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.stun_mod *= 2
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline
|
||||
name = "Adrenaline Burst"
|
||||
desc = "The nanites cause a burst of adrenaline when triggered, waking the host from stuns and temporarily increasing their speed."
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/toxic, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/adrenaline/trigger()
|
||||
if(!..())
|
||||
return
|
||||
to_chat(host_mob, "<span class='notice'>You feel a sudden surge of energy!</span>")
|
||||
host_mob.SetStun(0)
|
||||
host_mob.SetKnockdown(0)
|
||||
host_mob.SetUnconscious(0)
|
||||
host_mob.adjustStaminaLoss(-75)
|
||||
host_mob.lying = 0
|
||||
host_mob.update_canmove()
|
||||
host_mob.reagents.add_reagent("stimulants", 1.5)
|
||||
|
||||
/datum/nanite_program/hardening
|
||||
name = "Dermal Hardening"
|
||||
desc = "The nanites form a mesh under the host's skin, protecting them from melee and bullet impacts."
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
|
||||
//TODO on_hit effect that turns skin grey for a moment
|
||||
|
||||
/datum/nanite_program/hardening/enable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.armor.melee += 50
|
||||
H.physiology.armor.bullet += 35
|
||||
|
||||
/datum/nanite_program/hardening/disable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.armor.melee -= 50
|
||||
H.physiology.armor.bullet -= 35
|
||||
|
||||
/datum/nanite_program/refractive
|
||||
name = "Dermal Refractive Surface"
|
||||
desc = "The nanites form a membrane above the host's skin, reducing the effect of laser and energy impacts."
|
||||
use_rate = 0.50
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
|
||||
/datum/nanite_program/refractive/enable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.armor.laser += 50
|
||||
H.physiology.armor.energy += 35
|
||||
|
||||
/datum/nanite_program/refractive/disable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.armor.laser -= 50
|
||||
H.physiology.armor.energy -= 35
|
||||
|
||||
/datum/nanite_program/coagulating
|
||||
name = "Rapid Coagulation"
|
||||
desc = "The nanites induce rapid coagulation when the host is wounded, dramatically reducing bleeding rate."
|
||||
use_rate = 0.10
|
||||
rogue_types = list(/datum/nanite_program/suffocating)
|
||||
|
||||
/datum/nanite_program/coagulating/enable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.bleed_mod *= 0.1
|
||||
|
||||
/datum/nanite_program/coagulating/disable_passive_effect()
|
||||
. = ..()
|
||||
if(ishuman(host_mob))
|
||||
var/mob/living/carbon/human/H = host_mob
|
||||
H.physiology.bleed_mod *= 10
|
||||
|
||||
/datum/nanite_program/conductive
|
||||
name = "Electric Conduction"
|
||||
desc = "The nanites act as a grounding rod for electric shocks, protecting the host. Shocks can still damage the nanites themselves."
|
||||
use_rate = 0.20
|
||||
program_flags = NANITE_SHOCK_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/conductive/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.add_trait(TRAIT_SHOCKIMMUNE, "nanites")
|
||||
|
||||
/datum/nanite_program/conductive/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.remove_trait(TRAIT_SHOCKIMMUNE, "nanites")
|
||||
|
||||
/datum/nanite_program/mindshield
|
||||
name = "Mental Barrier"
|
||||
desc = "The nanites form a protective membrane around the host's brain, shielding them from abnormal influences while they're active."
|
||||
use_rate = 0.40
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/mindshield/enable_passive_effect()
|
||||
. = ..()
|
||||
if(!host_mob.mind.has_antag_datum(/datum/antagonist/rev)) //won't work if on a rev, to avoid having implanted revs
|
||||
host_mob.add_trait(TRAIT_MINDSHIELD, "nanites")
|
||||
host_mob.sec_hud_set_implants()
|
||||
|
||||
/datum/nanite_program/mindshield/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.remove_trait(TRAIT_MINDSHIELD, "nanites")
|
||||
host_mob.sec_hud_set_implants()
|
||||
@@ -0,0 +1,250 @@
|
||||
//Programs that heal the host in some way.
|
||||
|
||||
/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
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/regenerative/check_conditions()
|
||||
if(!host_mob.getBruteLoss() && !host_mob.getFireLoss())
|
||||
return FALSE
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = BODYPART_ORGANIC)
|
||||
if(!parts.len)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/regenerative/active_effect()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = BODYPART_ORGANIC)
|
||||
if(!parts.len)
|
||||
return
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1/parts.len, 1/parts.len))
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-1, TRUE)
|
||||
host_mob.adjustFireLoss(-1, TRUE)
|
||||
|
||||
/datum/nanite_program/temperature
|
||||
name = "Temperature Adjustment"
|
||||
desc = "The nanites adjust the host's internal temperature to an ideal level."
|
||||
use_rate = 3.5
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
|
||||
/datum/nanite_program/temperature/check_conditions()
|
||||
if(host_mob.bodytemperature > (BODYTEMP_NORMAL - 30) && host_mob.bodytemperature < (BODYTEMP_NORMAL + 30))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/temperature/active_effect()
|
||||
if(host_mob.bodytemperature > BODYTEMP_NORMAL)
|
||||
host_mob.adjust_bodytemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT, BODYTEMP_NORMAL)
|
||||
else if(host_mob.bodytemperature < (BODYTEMP_NORMAL + 1))
|
||||
host_mob.adjust_bodytemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
|
||||
|
||||
/datum/nanite_program/purging
|
||||
name = "Blood Purification"
|
||||
desc = "The nanites purge toxins and chemicals from the host's bloodstream."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/purging/check_conditions()
|
||||
var/foreign_reagent = LAZYLEN(host_mob.reagents.reagent_list)
|
||||
if(!host_mob.getToxLoss() && !foreign_reagent)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/purging/active_effect()
|
||||
host_mob.adjustToxLoss(-1)
|
||||
for(var/datum/reagent/R in host_mob.reagents.reagent_list)
|
||||
host_mob.reagents.remove_reagent(R.id,1)
|
||||
|
||||
/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."
|
||||
use_rate = 1.5
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/brain_heal/check_conditions()
|
||||
if(!host_mob.getBrainLoss())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/brain_heal/active_effect()
|
||||
host_mob.adjustBrainLoss(-1, TRUE)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
|
||||
/datum/nanite_program/blood_restoring
|
||||
name = "Blood Regeneration"
|
||||
desc = "The nanites stimulate and boost blood cell production in the host."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/suffocating)
|
||||
|
||||
/datum/nanite_program/blood_restoring/check_conditions()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(C.blood_volume >= BLOOD_VOLUME_SAFE)
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/blood_restoring/active_effect()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.blood_volume += 2
|
||||
|
||||
/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
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/repairing/check_conditions()
|
||||
if(!host_mob.getBruteLoss() && !host_mob.getFireLoss())
|
||||
return FALSE
|
||||
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = BODYPART_ROBOTIC)
|
||||
if(!parts.len)
|
||||
return FALSE
|
||||
else
|
||||
if(!(MOB_ROBOTIC in host_mob.mob_biotypes))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/repairing/active_effect(mob/living/M)
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/list/parts = C.get_damaged_bodyparts(TRUE, TRUE, status = BODYPART_ROBOTIC)
|
||||
if(!parts.len)
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(1/parts.len, 1/parts.len))
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-1, TRUE)
|
||||
host_mob.adjustFireLoss(-1, TRUE)
|
||||
|
||||
/datum/nanite_program/purging_advanced
|
||||
name = "Selective Blood Purification"
|
||||
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
|
||||
The added processing power required to analyze the chemicals severely increases the nanite consumption rate."
|
||||
use_rate = 2
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/purging_advanced/check_conditions()
|
||||
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)
|
||||
for(var/datum/reagent/toxin/R in host_mob.reagents.reagent_list)
|
||||
host_mob.reagents.remove_reagent(R.id,1)
|
||||
|
||||
/datum/nanite_program/regenerative_advanced
|
||||
name = "Bio-Reconstruction"
|
||||
desc = "The nanites manually repair and replace organic cells, acting much faster than normal regeneration. \
|
||||
However, this program cannot detect the difference between harmed and unharmed, causing it to consume nanites even if it has no effect."
|
||||
use_rate = 5.5
|
||||
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/regenerative_advanced/active_effect()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/list/parts = C.get_damaged_bodyparts(TRUE,TRUE, status = BODYPART_ORGANIC)
|
||||
if(!parts.len)
|
||||
return
|
||||
var/update = FALSE
|
||||
for(var/obj/item/bodypart/L in parts)
|
||||
if(L.heal_damage(3/parts.len, 3/parts.len))
|
||||
update = TRUE
|
||||
if(update)
|
||||
host_mob.update_damage_overlays()
|
||||
else
|
||||
host_mob.adjustBruteLoss(-3, TRUE)
|
||||
host_mob.adjustFireLoss(-3, TRUE)
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced
|
||||
name = "Neural Reimaging"
|
||||
desc = "The nanites are able to backup and restore the host's neural connections, potentially replacing entire chunks of missing or damaged brain matter."
|
||||
use_rate = 3
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/check_conditions()
|
||||
if(!host_mob.getBrainLoss())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/brain_heal_advanced/active_effect()
|
||||
host_mob.adjustBrainLoss(-2, TRUE)
|
||||
if(iscarbon(host_mob) && prob(10))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
|
||||
/datum/nanite_program/triggered/defib
|
||||
name = "Defibrillation"
|
||||
desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it."
|
||||
trigger_cost = 25
|
||||
trigger_cooldown = 120
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking)
|
||||
|
||||
/datum/nanite_program/triggered/defib/trigger()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
playsound(host_mob, 'sound/machines/defib_zap.ogg', 75, 1, -1)
|
||||
if(check_revivable())
|
||||
host_mob.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src)
|
||||
addtimer(CALLBACK(src, .proc/zap), 30)
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/check_revivable()
|
||||
if(!iscarbon(host_mob)) //nonstandard biology
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(C.suiciding || C.has_trait(TRAIT_NOCLONE) || C.hellbound) //can't revive
|
||||
return FALSE
|
||||
if((world.time - C.timeofdeath) < 1800) //too late
|
||||
return FALSE
|
||||
if((C.getBruteLoss() > 180) || (C.getFireLoss() > 180)) //too damaged
|
||||
return FALSE
|
||||
if(!C.getorgan(/obj/item/organ/heart)) //what are we even shocking
|
||||
return FALSE
|
||||
var/obj/item/organ/brain/BR = C.getorgan(/obj/item/organ/brain)
|
||||
if(QDELETED(BR) || BR.damaged_brain)
|
||||
return FALSE
|
||||
if(!C.ckey && !C.get_ghost())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/nanite_program/triggered/defib/proc/zap()
|
||||
if(check_revivable() && host_mob.ckey)
|
||||
var/mob/living/carbon/C = host_mob
|
||||
playsound(C, 'sound/machines/defib_success.ogg', 50, 0)
|
||||
C.set_heartattack(FALSE)
|
||||
C.revive()
|
||||
C.emote("gasp")
|
||||
C.Jitter(100)
|
||||
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
|
||||
var/tplus = world.time - C.timeofdeath
|
||||
if(tplus > 600)
|
||||
C.adjustBrainLoss( max(0, ((1800 - tplus) / 1800 * 150)), 150)
|
||||
log_game("[C] has been successfully defibrillated by nanites.")
|
||||
else
|
||||
playsound(host_mob, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//Programs generated through degradation of other complex programs.
|
||||
//They generally cause minor damage or annoyance.
|
||||
|
||||
//Last stop of the error train
|
||||
/datum/nanite_program/glitch
|
||||
name = "Glitch"
|
||||
desc = "A heavy software corruption that causes nanites to gradually break down."
|
||||
use_rate = 1.5
|
||||
unique = FALSE
|
||||
rogue_types = list()
|
||||
|
||||
//Generic body-affecting programs will decay into this
|
||||
/datum/nanite_program/necrotic
|
||||
name = "Necrosis"
|
||||
desc = "The nanites attack internal tissues indiscriminately, causing widespread damage."
|
||||
use_rate = 0.75
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/glitch)
|
||||
|
||||
/datum/nanite_program/necrotic/active_effect()
|
||||
host_mob.adjustBruteLoss(0.75, TRUE)
|
||||
if(prob(1))
|
||||
to_chat(host_mob, "<span class='warning'>You feel a mild ache from somewhere inside you.</span>")
|
||||
|
||||
//Programs that don't directly interact with the body will decay into this
|
||||
/datum/nanite_program/toxic
|
||||
name = "Toxin Buildup"
|
||||
desc = "The nanites cause a slow but constant toxin buildup inside the host."
|
||||
use_rate = 0.25
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/glitch)
|
||||
|
||||
/datum/nanite_program/toxic/active_effect()
|
||||
host_mob.adjustToxLoss(0.5)
|
||||
if(prob(1))
|
||||
to_chat(host_mob, "<span class='warning'>You feel a bit sick.</span>")
|
||||
|
||||
//Generic blood-affecting programs will decay into this
|
||||
/datum/nanite_program/suffocating
|
||||
name = "Hypoxemia"
|
||||
desc = "The nanites prevent the host's blood from absorbing oxygen efficiently."
|
||||
use_rate = 0.75
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/glitch)
|
||||
|
||||
/datum/nanite_program/suffocating/active_effect()
|
||||
host_mob.adjustOxyLoss(3, 0)
|
||||
if(prob(1))
|
||||
to_chat(host_mob, "<span class='warning'>You feel short of breath.</span>")
|
||||
|
||||
//Generic brain-affecting programs will decay into this
|
||||
/datum/nanite_program/brain_decay
|
||||
name = "Neuro-Necrosis"
|
||||
desc = "The nanites seek and attack brain cells, causing extensive neural damage to the host."
|
||||
use_rate = 0.75
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/brain_decay/active_effect()
|
||||
if(prob(4))
|
||||
host_mob.hallucination = min(15, host_mob.hallucination)
|
||||
host_mob.adjustBrainLoss(1)
|
||||
|
||||
//Generic brain-affecting programs can also decay into this
|
||||
/datum/nanite_program/brain_misfire
|
||||
name = "Brain Misfire"
|
||||
desc = "The nanites interfere with neural pathways, causing minor psychological disturbances."
|
||||
use_rate = 0.50
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/brain_misfire/active_effect()
|
||||
if(prob(10))
|
||||
switch(rand(1,4))
|
||||
if(1)
|
||||
host_mob.hallucination += 15
|
||||
if(2)
|
||||
host_mob.confused += 10
|
||||
if(3)
|
||||
host_mob.drowsyness += 10
|
||||
if(4)
|
||||
host_mob.slurring += 10
|
||||
|
||||
//Generic skin-affecting programs will decay into this
|
||||
/datum/nanite_program/skin_decay
|
||||
name = "Dermalysis"
|
||||
desc = "The nanites attack skin cells, causing irritation, rashes, and minor damage."
|
||||
use_rate = 0.25
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/skin_decay/active_effect()
|
||||
host_mob.adjustBruteLoss(0.25)
|
||||
if(prob(5)) //itching
|
||||
var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
|
||||
var/obj/item/bodypart/bodypart = host_mob.get_bodypart(picked_bodypart)
|
||||
var/can_scratch = !host_mob.incapacitated() && get_location_accessible(host_mob, picked_bodypart)
|
||||
|
||||
host_mob.visible_message("[can_scratch ? "<span class='warning'>[host_mob] scratches [host_mob.p_their()] [bodypart.name].</span>" : ""]",\
|
||||
"<span class='warning'>Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]</span>")
|
||||
|
||||
//Generic nerve-affecting programs will decay into this
|
||||
/datum/nanite_program/nerve_decay
|
||||
name = "Nerve Decay"
|
||||
desc = "The nanites attack the host's nerves, causing lack of coordination and short bursts of paralysis."
|
||||
use_rate = 1
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/nerve_decay/active_effect()
|
||||
if(prob(5))
|
||||
to_chat(host_mob, "<span class='warning'>You feel unbalanced!</span>")
|
||||
host_mob.confused += 10
|
||||
else if(prob(4))
|
||||
to_chat(host_mob, "<span class='warning'>You can't feel your hands!</span>")
|
||||
host_mob.drop_all_held_items()
|
||||
else if(prob(4))
|
||||
to_chat(host_mob, "<span class='warning'>You can't feel your legs!</span>")
|
||||
host_mob.Knockdown(30)
|
||||
@@ -0,0 +1,392 @@
|
||||
/datum/nanite_program/sensor
|
||||
name = "Sensor Nanites"
|
||||
desc = "These nanites send a signal code when a certain condition is met."
|
||||
unique = FALSE
|
||||
extra_settings = list("Sent Code")
|
||||
|
||||
var/sent_code = 0
|
||||
|
||||
/datum/nanite_program/sensor/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/sensor/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
|
||||
/datum/nanite_program/sensor/copy_extra_settings_to(datum/nanite_program/sensor/target)
|
||||
target.sent_code = sent_code
|
||||
|
||||
/datum/nanite_program/sensor/proc/check_event()
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/proc/send_code()
|
||||
if(activated)
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code, "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/active_effect()
|
||||
if(sent_code && check_event())
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/repeat
|
||||
name = "Signal Repeater"
|
||||
desc = "When triggered, sends another signal to the nanites, optionally with a delay."
|
||||
can_trigger = TRUE
|
||||
trigger_cost = 0
|
||||
trigger_cooldown = 10
|
||||
extra_settings = list("Sent Code","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
|
||||
/datum/nanite_program/sensor/repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
|
||||
/datum/nanite_program/sensor/repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/repeat/copy_extra_settings_to(datum/nanite_program/sensor/repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
|
||||
/datum/nanite_program/sensor/repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
|
||||
/datum/nanite_program/sensor/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
|
||||
extra_settings = list("Sent Code","Relay Channel","Delay")
|
||||
var/spent = FALSE
|
||||
var/delay = 0
|
||||
var/relay_channel = 0
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
if(setting == "Delay")
|
||||
var/new_delay = input(user, "Set the delay in seconds:", name, null) as null|num
|
||||
if(isnull(new_delay))
|
||||
return
|
||||
delay = (CLAMP(round(new_delay, 1), 0, 3600)) * 10 //max 1 hour
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
if(setting == "Delay")
|
||||
return "[delay/10] seconds"
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/copy_extra_settings_to(datum/nanite_program/sensor/relay_repeat/target)
|
||||
target.sent_code = sent_code
|
||||
target.delay = delay
|
||||
target.relay_channel = relay_channel
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/trigger()
|
||||
if(!..())
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/send_code), delay)
|
||||
|
||||
/datum/nanite_program/sensor/relay_repeat/send_code()
|
||||
if(activated && relay_channel)
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_signal(sent_code, relay_channel, "a [name] program")
|
||||
|
||||
/datum/nanite_program/sensor/health
|
||||
name = "Health Sensor"
|
||||
desc = "The nanites receive a signal when the host's health is above/below a target percentage."
|
||||
extra_settings = list("Sent Code","Health Percent","Direction")
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Health Percent")
|
||||
var/new_percent = input(user, "Set the health percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), -99, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/health/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Health Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/health/copy_extra_settings_to(datum/nanite_program/sensor/health/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
|
||||
/datum/nanite_program/sensor/health/check_event()
|
||||
var/health_percent = host_mob.health / host_mob.maxHealth * 100
|
||||
var/detected = FALSE
|
||||
if(direction == "Above")
|
||||
if(health_percent >= percent)
|
||||
detected = TRUE
|
||||
else
|
||||
if(health_percent < percent)
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
if(!spent)
|
||||
spent = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
else
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit
|
||||
name = "Critical Health Sensor"
|
||||
desc = "The nanites receive a signal when the host first reaches critical health."
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/crit/check_event()
|
||||
if(host_mob.InCritical())
|
||||
if(!spent)
|
||||
spent = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
else
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/death
|
||||
name = "Death Sensor"
|
||||
desc = "The nanites receive a signal when they detect the host is dead."
|
||||
var/spent = FALSE
|
||||
|
||||
/datum/nanite_program/sensor/death/on_death()
|
||||
send_code()
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume
|
||||
name = "Nanite Volume Sensor"
|
||||
desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage."
|
||||
extra_settings = list("Sent Code","Nanite Percent","Direction")
|
||||
var/spent = FALSE
|
||||
var/percent = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Nanite Percent")
|
||||
var/new_percent = input(user, "Set the nanite percentage:", name, null) as null|num
|
||||
if(isnull(new_percent))
|
||||
return
|
||||
percent = CLAMP(round(new_percent, 1), 1, 100)
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Nanite Percent")
|
||||
return "[percent]%"
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/copy_extra_settings_to(datum/nanite_program/sensor/nanite_volume/target)
|
||||
target.sent_code = sent_code
|
||||
target.percent = percent
|
||||
target.direction = direction
|
||||
|
||||
/datum/nanite_program/sensor/nanite_volume/check_event()
|
||||
var/nanite_percent = (nanites.nanite_volume - nanites.safety_threshold)/(nanites.max_nanites - nanites.safety_threshold)*100
|
||||
var/detected = FALSE
|
||||
|
||||
if(direction == "Above")
|
||||
if(nanite_percent >= percent)
|
||||
detected = TRUE
|
||||
else
|
||||
if(nanite_percent < percent)
|
||||
detected = TRUE
|
||||
|
||||
if(detected)
|
||||
if(!spent)
|
||||
spent = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
else
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/damage
|
||||
name = "Damage Sensor"
|
||||
desc = "The nanites receive a signal when a host's specific damage type is above/below a target value."
|
||||
extra_settings = list("Sent Code","Damage Type","Damage","Direction")
|
||||
var/spent = FALSE
|
||||
var/damage_type = "Brute"
|
||||
var/damage = 50
|
||||
var/direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Damage")
|
||||
var/new_damage = input(user, "Set the damage threshold:", name, null) as null|num
|
||||
if(isnull(new_damage))
|
||||
return
|
||||
damage = CLAMP(round(new_damage, 1), 0, 500)
|
||||
if(setting == "Damage Type")
|
||||
var/list/damage_types = list("Brute","Burn","Toxin","Oxygen","Cellular")
|
||||
var/new_damage_type = input("Choose the damage type", name) as null|anything in damage_types
|
||||
if(!new_damage_type)
|
||||
return
|
||||
damage_type = new_damage_type
|
||||
if(setting == "Direction")
|
||||
if(direction == "Above")
|
||||
direction = "Below"
|
||||
else
|
||||
direction = "Above"
|
||||
|
||||
/datum/nanite_program/sensor/damage/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Damage")
|
||||
return damage
|
||||
if(setting == "Damage Type")
|
||||
return damage_type
|
||||
if(setting == "Direction")
|
||||
return direction
|
||||
|
||||
/datum/nanite_program/sensor/damage/copy_extra_settings_to(datum/nanite_program/sensor/damage/target)
|
||||
target.sent_code = sent_code
|
||||
target.damage = damage
|
||||
target.damage_type = damage_type
|
||||
target.direction = direction
|
||||
|
||||
/datum/nanite_program/sensor/damage/check_event()
|
||||
var/reached_threshold = FALSE
|
||||
var/check_above = (direction == "Above")
|
||||
var/damage_amt = 0
|
||||
switch(damage_type)
|
||||
if("Brute")
|
||||
damage_amt = host_mob.getBruteLoss()
|
||||
if("Burn")
|
||||
damage_amt = host_mob.getFireLoss()
|
||||
if("Toxin")
|
||||
damage_amt = host_mob.getToxLoss()
|
||||
if("Oxygen")
|
||||
damage_amt = host_mob.getOxyLoss()
|
||||
if("Cellular")
|
||||
damage_amt = host_mob.getCloneLoss()
|
||||
|
||||
if(damage_amt >= damage)
|
||||
if(check_above)
|
||||
reached_threshold = TRUE
|
||||
else if(!check_above)
|
||||
reached_threshold = TRUE
|
||||
|
||||
if(reached_threshold)
|
||||
if(!spent)
|
||||
spent = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
else
|
||||
spent = FALSE
|
||||
return FALSE
|
||||
|
||||
/datum/nanite_program/sensor/voice
|
||||
name = "Voice Sensor"
|
||||
desc = "Sends a signal when the nanites hear a determined word or sentence."
|
||||
extra_settings = list("Sent Code","Sentence","Inclusive Mode")
|
||||
var/spent = FALSE
|
||||
var/sentence = ""
|
||||
var/inclusive = TRUE
|
||||
|
||||
/datum/nanite_program/sensor/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Sent Code")
|
||||
var/new_code = input(user, "Set the sent code (1-9999):", name, null) as null|num
|
||||
if(isnull(new_code))
|
||||
return
|
||||
sent_code = CLAMP(round(new_code, 1), 1, 9999)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that triggers the sensor.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
sentence = new_sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
var/new_inclusive = input("Should the sensor detect the sentence if contained within another sentence?", name) as null|anything in list("Inclusive","Exclusive")
|
||||
if(!new_inclusive)
|
||||
return
|
||||
inclusive = (new_inclusive == "Inclusive")
|
||||
|
||||
/datum/nanite_program/sensor/voice/get_extra_setting(setting)
|
||||
if(setting == "Sent Code")
|
||||
return sent_code
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
if(setting == "Inclusive Mode")
|
||||
if(inclusive)
|
||||
return "Inclusive"
|
||||
else
|
||||
return "Exclusive"
|
||||
|
||||
/datum/nanite_program/sensor/voice/copy_extra_settings_to(datum/nanite_program/sensor/voice/target)
|
||||
target.sent_code = sent_code
|
||||
target.sentence = sentence
|
||||
target.inclusive = inclusive
|
||||
|
||||
/datum/nanite_program/sensor/voice/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(!sentence)
|
||||
return
|
||||
//To make it not case sensitive
|
||||
var/low_message = lowertext(raw_message)
|
||||
var/low_sentence = lowertext(sentence)
|
||||
if(inclusive)
|
||||
if(findtext(low_message, low_sentence))
|
||||
send_code()
|
||||
else
|
||||
if(low_message == low_sentence)
|
||||
send_code()
|
||||
@@ -0,0 +1,311 @@
|
||||
//Programs that are generally useful for population control and non-harmful suppression.
|
||||
|
||||
/datum/nanite_program/triggered/sleepy
|
||||
name = "Sleep Induction"
|
||||
desc = "The nanites cause rapid narcolepsy when triggered."
|
||||
trigger_cost = 15
|
||||
trigger_cooldown = 1200
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/triggered/sleepy/trigger()
|
||||
if(!..())
|
||||
return
|
||||
to_chat(host_mob, "<span class='warning'>You start to feel very sleepy...</span>")
|
||||
host_mob.drowsyness += 20
|
||||
addtimer(CALLBACK(host_mob, /mob/living.proc/Sleeping, 200), rand(60,200))
|
||||
|
||||
/datum/nanite_program/paralyzing
|
||||
name = "Paralysis"
|
||||
desc = "The nanites force muscle contraction, effectively paralyzing the host."
|
||||
use_rate = 3
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/paralyzing/active_effect()
|
||||
host_mob.Stun(40)
|
||||
|
||||
/datum/nanite_program/paralyzing/enable_passive_effect()
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='warning'>Your muscles seize! You can't move!</span>")
|
||||
|
||||
/datum/nanite_program/paralyzing/disable_passive_effect()
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='notice'>Your muscles relax, and you can move again.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/shocking
|
||||
name = "Electric Shock"
|
||||
desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!"
|
||||
trigger_cost = 10
|
||||
trigger_cooldown = 300
|
||||
program_flags = NANITE_SHOCK_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/shocking/trigger()
|
||||
if(!..())
|
||||
return
|
||||
host_mob.electrocute_act(rand(5,10), "shock nanites", TRUE, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/stun
|
||||
name = "Neural Shock"
|
||||
desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period."
|
||||
trigger_cost = 4
|
||||
trigger_cooldown = 300
|
||||
rogue_types = list(/datum/nanite_program/triggered/shocking, /datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/stun/trigger()
|
||||
if(!..())
|
||||
return
|
||||
playsound(host_mob, "sparks", 75, 1, -1)
|
||||
host_mob.Knockdown(80)
|
||||
|
||||
/datum/nanite_program/pacifying
|
||||
name = "Pacification"
|
||||
desc = "The nanites suppress the aggression center of the brain, preventing the host from causing direct harm to others."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/pacifying/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.add_trait(TRAIT_PACIFISM, "nanites")
|
||||
|
||||
/datum/nanite_program/pacifying/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.remove_trait(TRAIT_PACIFISM, "nanites")
|
||||
|
||||
/datum/nanite_program/blinding
|
||||
name = "Blindness"
|
||||
desc = "The nanites suppress the host's ocular nerves, blinding them while they're active."
|
||||
use_rate = 1.5
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/blinding/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.become_blind("nanites")
|
||||
|
||||
/datum/nanite_program/blinding/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.cure_blind("nanites")
|
||||
|
||||
/datum/nanite_program/mute
|
||||
name = "Mute"
|
||||
desc = "The nanites suppress the host's speech, making them mute while they're active."
|
||||
use_rate = 0.75
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
/datum/nanite_program/mute/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.add_trait(TRAIT_MUTE, "nanites")
|
||||
|
||||
/datum/nanite_program/mute/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.remove_trait(TRAIT_MUTE, "nanites")
|
||||
|
||||
/datum/nanite_program/fake_death
|
||||
name = "Death Simulation"
|
||||
desc = "The nanites induce a death-like coma into the host, able to fool most medical scans."
|
||||
use_rate = 3.5
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay, /datum/nanite_program/necrotic, /datum/nanite_program/brain_decay)
|
||||
|
||||
/datum/nanite_program/fake_death/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.emote("deathgasp")
|
||||
host_mob.fakedeath("nanites")
|
||||
|
||||
/datum/nanite_program/fake_death/disable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.cure_fakedeath("nanites")
|
||||
|
||||
/datum/nanite_program/triggered/speech
|
||||
name = "Forced Speech"
|
||||
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
|
||||
unique = FALSE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
extra_settings = list("Sentence")
|
||||
var/sentence = ""
|
||||
|
||||
/datum/nanite_program/triggered/speech/set_extra_setting(user, setting)
|
||||
if(setting == "Sentence")
|
||||
var/new_sentence = stripped_input(user, "Choose the sentence that the host will be forced to say.", "Sentence", sentence, MAX_MESSAGE_LEN)
|
||||
if(!new_sentence)
|
||||
return
|
||||
if(copytext(new_sentence, 1, 2) == "*") //emotes are abusable, like surrender
|
||||
return
|
||||
sentence = new_sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/get_extra_setting(setting)
|
||||
if(setting == "Sentence")
|
||||
return sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/copy_extra_settings_to(datum/nanite_program/triggered/speech/target)
|
||||
target.sentence = sentence
|
||||
|
||||
/datum/nanite_program/triggered/speech/trigger()
|
||||
if(!..())
|
||||
return
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
to_chat(host_mob, "<span class='warning'>You feel compelled to speak...</span>")
|
||||
host_mob.say(sentence)
|
||||
|
||||
/datum/nanite_program/triggered/voice
|
||||
name = "Skull Echo"
|
||||
desc = "The nanites echo a synthesized message inside the host's skull."
|
||||
unique = FALSE
|
||||
trigger_cost = 1
|
||||
trigger_cooldown = 20
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
|
||||
|
||||
extra_settings = list("Message")
|
||||
var/message = ""
|
||||
|
||||
/datum/nanite_program/triggered/voice/set_extra_setting(user, setting)
|
||||
if(setting == "Message")
|
||||
var/new_message = stripped_input(user, "Choose the message sent to the host.", "Message", message, MAX_MESSAGE_LEN)
|
||||
if(!new_message)
|
||||
return
|
||||
message = new_message
|
||||
|
||||
/datum/nanite_program/triggered/voice/get_extra_setting(setting)
|
||||
if(setting == "Message")
|
||||
return message
|
||||
|
||||
/datum/nanite_program/triggered/voice/copy_extra_settings_to(datum/nanite_program/triggered/voice/target)
|
||||
target.message = message
|
||||
|
||||
/datum/nanite_program/triggered/voice/trigger()
|
||||
if(!..())
|
||||
return
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[message]</span>\"")
|
||||
|
||||
/datum/nanite_program/triggered/hallucination
|
||||
name = "Hallucination"
|
||||
desc = "The nanites make the host hallucinate something when triggered."
|
||||
trigger_cost = 4
|
||||
trigger_cooldown = 80
|
||||
unique = FALSE
|
||||
rogue_types = list(/datum/nanite_program/brain_misfire)
|
||||
extra_settings = list("Hallucination Type")
|
||||
var/hal_type
|
||||
var/hal_details
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/trigger()
|
||||
if(!..())
|
||||
return
|
||||
if(!iscarbon(host_mob))
|
||||
return
|
||||
var/mob/living/carbon/C = host_mob
|
||||
if(!hal_type)
|
||||
C.hallucination += 15
|
||||
else
|
||||
switch(hal_type)
|
||||
if("Message")
|
||||
new /datum/hallucination/chat(C, TRUE, null, hal_details)
|
||||
if("Battle")
|
||||
new /datum/hallucination/battle(C, TRUE, hal_details)
|
||||
if("Sound")
|
||||
new /datum/hallucination/sounds(C, TRUE, hal_details)
|
||||
if("Weird Sound")
|
||||
new /datum/hallucination/weird_sounds(C, TRUE, hal_details)
|
||||
if("Station Message")
|
||||
new /datum/hallucination/stationmessage(C, TRUE, hal_details)
|
||||
if("Health")
|
||||
new /datum/hallucination/hudscrew(C, TRUE, hal_details)
|
||||
if("Alert")
|
||||
new /datum/hallucination/fake_alert(C, TRUE, hal_details)
|
||||
if("Fire")
|
||||
new /datum/hallucination/fire(C, TRUE)
|
||||
if("Shock")
|
||||
new /datum/hallucination/shock(C, TRUE)
|
||||
if("Plasma Flood")
|
||||
new /datum/hallucination/fake_flood(C, TRUE)
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/set_extra_setting(user, setting)
|
||||
if(setting == "Hallucination Type")
|
||||
var/list/possible_hallucinations = list("Random","Message","Battle","Sound","Weird Sound","Station Message","Health","Alert","Fire","Shock","Plasma Flood")
|
||||
var/hal_type_choice = input("Choose the hallucination type", name) as null|anything in possible_hallucinations
|
||||
if(!hal_type_choice)
|
||||
return
|
||||
switch(hal_type_choice)
|
||||
if("Random")
|
||||
hal_type = null
|
||||
hal_details = null
|
||||
if("Message")
|
||||
hal_type = "Message"
|
||||
var/hal_chat = stripped_input(user, "Choose the message the host will hear, or leave empty for random messages.", "Message", hal_details, MAX_MESSAGE_LEN)
|
||||
if(hal_chat)
|
||||
hal_details = hal_chat
|
||||
if("Battle")
|
||||
hal_type = "Battle"
|
||||
var/sound_list = list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb")
|
||||
var/hal_choice = input("Choose the hallucination battle type", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Sound")
|
||||
hal_type = "Sound"
|
||||
var/sound_list = list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Weird Sound")
|
||||
hal_type = "Weird Sound"
|
||||
var/sound_list = list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla")
|
||||
var/hal_choice = input("Choose the hallucination sound", name) as null|anything in sound_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Station Message")
|
||||
hal_type = "Station Message"
|
||||
var/msg_list = list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter")
|
||||
var/hal_choice = input("Choose the hallucination station message", name) as null|anything in msg_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Health")
|
||||
hal_type = "Health"
|
||||
var/health_list = list("random","critical","dead","healthy")
|
||||
var/hal_choice = input("Choose the health status", name) as null|anything in health_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
switch(hal_choice)
|
||||
if("critical")
|
||||
hal_details = SCREWYHUD_CRIT
|
||||
if("dead")
|
||||
hal_details = SCREWYHUD_DEAD
|
||||
if("healthy")
|
||||
hal_details = SCREWYHUD_HEALTHY
|
||||
if("Alert")
|
||||
hal_type = "Alert"
|
||||
var/alert_list = list("random","not_enough_oxy","not_enough_tox","not_enough_co2","too_much_oxy","too_much_co2","too_much_tox","newlaw","nutrition","charge","gravity","fire","locked","hacked","temphot","tempcold","pressure")
|
||||
var/hal_choice = input("Choose the alert", name) as null|anything in alert_list
|
||||
if(!hal_choice || hal_choice == "random")
|
||||
hal_details = null
|
||||
else
|
||||
hal_details = hal_choice
|
||||
if("Fire")
|
||||
hal_type = "Fire"
|
||||
if("Shock")
|
||||
hal_type = "Shock"
|
||||
if("Plasma Flood")
|
||||
hal_type = "Plasma Flood"
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/get_extra_setting(setting)
|
||||
if(setting == "Hallucination Type")
|
||||
if(!hal_type)
|
||||
return "Random"
|
||||
else
|
||||
return hal_type
|
||||
|
||||
/datum/nanite_program/triggered/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/hallucination/target)
|
||||
target.hal_type = hal_type
|
||||
target.hal_details = hal_details
|
||||
@@ -0,0 +1,265 @@
|
||||
//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."
|
||||
use_rate = 0.5
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
extra_settings = list("Program Overwrite","Cloud Overwrite")
|
||||
|
||||
var/sync_programs = TRUE
|
||||
var/sync_overwrite = FALSE
|
||||
var/overwrite_cloud = FALSE
|
||||
var/set_cloud = 0
|
||||
|
||||
/datum/nanite_program/viral/set_extra_setting(user, setting)
|
||||
if(setting == "Program Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's programs", name) as null|anything in list("Overwrite","Add To","Ignore")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Ignore") //Do not affect programs (if you only want to set the cloud ID)
|
||||
sync_programs = FALSE
|
||||
sync_overwrite = FALSE
|
||||
if("Add To") //Add to existing programs (so the target does not notice theirs are missing)
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = FALSE
|
||||
if("Overwrite") //Replace target's programs with the source
|
||||
sync_programs = TRUE
|
||||
sync_overwrite = TRUE
|
||||
if(setting == "Cloud Overwrite")
|
||||
var/overwrite_type = input("Choose what to do with the target's Cloud ID", name) as null|anything in list("Overwrite","Disable","Keep")
|
||||
if(!overwrite_type)
|
||||
return
|
||||
switch(overwrite_type)
|
||||
if("Keep") //Don't change the cloud ID
|
||||
overwrite_cloud = FALSE
|
||||
set_cloud = 0
|
||||
if("Disable") //Set the cloud ID to disabled
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = 0
|
||||
if("Overwrite") //Set the cloud ID to what we choose
|
||||
var/new_cloud = input(user, "Choose the Cloud ID to set on infected nanites (1-100)", name, null) as null|num
|
||||
if(isnull(new_cloud))
|
||||
return
|
||||
overwrite_cloud = TRUE
|
||||
set_cloud = CLAMP(round(new_cloud, 1), 1, 100)
|
||||
|
||||
/datum/nanite_program/viral/get_extra_setting(setting)
|
||||
if(setting == "Program Overwrite")
|
||||
if(!sync_programs)
|
||||
return "Ignore"
|
||||
else if(sync_overwrite)
|
||||
return "Overwrite"
|
||||
else
|
||||
return "Add To"
|
||||
if(setting == "Cloud Overwrite")
|
||||
if(!overwrite_cloud)
|
||||
return "None"
|
||||
else if(set_cloud == 0)
|
||||
return "Disable"
|
||||
else
|
||||
return set_cloud
|
||||
|
||||
/datum/nanite_program/viral/copy_extra_settings_to(datum/nanite_program/viral/target)
|
||||
target.overwrite_cloud = overwrite_cloud
|
||||
target.set_cloud = set_cloud
|
||||
target.sync_programs = sync_programs
|
||||
target.sync_overwrite = sync_overwrite
|
||||
|
||||
/datum/nanite_program/viral/active_effect()
|
||||
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)
|
||||
|
||||
/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()
|
||||
. = ..()
|
||||
SSnanites.nanite_monitored_mobs |= host_mob
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
|
||||
/datum/nanite_program/monitoring/disable_passive_effect()
|
||||
. = ..()
|
||||
SSnanites.nanite_monitored_mobs -= host_mob
|
||||
host_mob.hud_set_nanite_indicator()
|
||||
|
||||
/datum/nanite_program/triggered/self_scan
|
||||
name = "Host Scan"
|
||||
desc = "The nanites display a detailed readout of a body scan to the host."
|
||||
unique = FALSE
|
||||
trigger_cost = 3
|
||||
trigger_cooldown = 50
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Scan Type")
|
||||
var/scan_type = "Medical"
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/set_extra_setting(user, setting)
|
||||
if(setting == "Scan Type")
|
||||
var/list/scan_types = list("Medical","Chemical","Nanite")
|
||||
var/new_scan_type = input("Choose the scan type", name) as null|anything in scan_types
|
||||
if(!new_scan_type)
|
||||
return
|
||||
scan_type = new_scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/get_extra_setting(setting)
|
||||
if(setting == "Scan Type")
|
||||
return scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/copy_extra_settings_to(datum/nanite_program/triggered/self_scan/target)
|
||||
target.scan_type = scan_type
|
||||
|
||||
/datum/nanite_program/triggered/self_scan/trigger()
|
||||
if(!..())
|
||||
return
|
||||
if(host_mob.stat == DEAD)
|
||||
return
|
||||
switch(scan_type)
|
||||
if("Medical")
|
||||
healthscan(host_mob, host_mob)
|
||||
if("Chemical")
|
||||
chemscan(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 hide their activity and programming from superficial scans."
|
||||
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/relay
|
||||
name = "Relay"
|
||||
desc = "The nanites receive and relay long-range nanite signals."
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
extra_settings = list("Relay Channel")
|
||||
var/relay_channel = 1
|
||||
|
||||
/datum/nanite_program/relay/set_extra_setting(user, setting)
|
||||
if(setting == "Relay Channel")
|
||||
var/new_channel = input(user, "Set the relay channel (1-9999):", name, null) as null|num
|
||||
if(isnull(new_channel))
|
||||
return
|
||||
relay_channel = CLAMP(round(new_channel, 1), 1, 9999)
|
||||
|
||||
/datum/nanite_program/relay/get_extra_setting(setting)
|
||||
if(setting == "Relay Channel")
|
||||
return relay_channel
|
||||
|
||||
/datum/nanite_program/relay/copy_extra_settings_to(datum/nanite_program/relay/target)
|
||||
target.relay_channel = relay_channel
|
||||
|
||||
/datum/nanite_program/relay/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
|
||||
if(relay_code != relay_channel)
|
||||
return
|
||||
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source)
|
||||
|
||||
/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.nutrition -= 0.5
|
||||
|
||||
/datum/nanite_program/triggered/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."
|
||||
rogue_types = list(/datum/nanite_program/skin_decay)
|
||||
var/access = list()
|
||||
|
||||
//Syncs the nanites with the cumulative current mob's access level. Can potentially wipe existing access.
|
||||
/datum/nanite_program/triggered/access/trigger()
|
||||
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)
|
||||
|
||||
/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))
|
||||
target_hosts += L
|
||||
var/mob/living/infectee = pick(target_hosts)
|
||||
if(prob(100 - (infectee.get_permeability_protection() * 100)))
|
||||
//this will potentially take over existing nanites!
|
||||
infectee.AddComponent(/datum/component/nanites, 10)
|
||||
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
|
||||
infectee.investigate_log("[key_name(infectee)] was infected by spreading nanites by [key_name(host_mob)]", INVESTIGATE_NANITES)
|
||||
|
||||
/datum/nanite_program/mitosis
|
||||
name = "Mitosis"
|
||||
desc = "The nanites gain the ability to self-replicate, using bluespace to power the process, instead of drawing from a template. This rapidly speeds up the replication rate,\
|
||||
but it causes occasional software errors due to faulty copies. Not compatible with cloud sync."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/mitosis/active_effect()
|
||||
if(nanites.cloud_id)
|
||||
return
|
||||
var/rep_rate = round(nanites.nanite_volume / 50, 1) //0.5 per 50 nanite volume
|
||||
rep_rate *= 0.5
|
||||
nanites.adjust_nanites(rep_rate)
|
||||
if(prob(rep_rate))
|
||||
var/datum/nanite_program/fault = pick(nanites.programs)
|
||||
if(fault == src)
|
||||
return
|
||||
fault.software_error()
|
||||
@@ -0,0 +1,200 @@
|
||||
//Programs specifically engineered to cause harm to either the user or its surroundings (as opposed to ones that only do it due to broken programming)
|
||||
//Very dangerous!
|
||||
|
||||
/datum/nanite_program/flesh_eating
|
||||
name = "Cellular Breakdown"
|
||||
desc = "The nanites destroy cellular structures in the host's body, causing brute damage."
|
||||
use_rate = 1.5
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/flesh_eating/active_effect()
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.take_bodypart_damage(1, 0, 0)
|
||||
else
|
||||
host_mob.adjustBruteLoss(1, TRUE)
|
||||
if(prob(3))
|
||||
to_chat(host_mob, "<span class='warning'>You feel a stab of pain from somewhere inside you.</span>")
|
||||
|
||||
/datum/nanite_program/poison
|
||||
name = "Poisoning"
|
||||
desc = "The nanites deliver poisonous chemicals to the host's internal organs, causing toxin damage and vomiting."
|
||||
use_rate = 1.5
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/poison/active_effect()
|
||||
host_mob.adjustToxLoss(1)
|
||||
if(prob(2))
|
||||
to_chat(host_mob, "<span class='warning'>You feel nauseous.</span>")
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
C.vomit(20)
|
||||
|
||||
/datum/nanite_program/memory_leak
|
||||
name = "Memory Leak"
|
||||
desc = "This program invades the memory space used by other programs, causing frequent corruptions and errors."
|
||||
use_rate = 0
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/memory_leak/active_effect()
|
||||
if(prob(6))
|
||||
var/datum/nanite_program/target = pick(nanites.programs)
|
||||
if(target == src)
|
||||
return
|
||||
target.software_error()
|
||||
|
||||
/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 = 1
|
||||
rogue_types = list(/datum/nanite_program/necrotic)
|
||||
|
||||
/datum/nanite_program/aggressive_replication/active_effect()
|
||||
var/extra_regen = round(nanites.nanite_volume / 200, 0.1)
|
||||
nanites.adjust_nanites(extra_regen)
|
||||
host_mob.adjustBruteLoss(extra_regen / 2, TRUE)
|
||||
|
||||
/datum/nanite_program/meltdown
|
||||
name = "Meltdown"
|
||||
desc = "Causes an internal meltdown inside the nanites, causing internal burns inside the host as well as rapidly destroying the nanite population.\
|
||||
Sets the nanites' safety threshold to 0 when activated."
|
||||
use_rate = 10
|
||||
rogue_types = list(/datum/nanite_program/glitch)
|
||||
|
||||
/datum/nanite_program/meltdown/active_effect()
|
||||
host_mob.adjustFireLoss(3.5)
|
||||
|
||||
/datum/nanite_program/meltdown/enable_passive_effect()
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='userdanger'>Your blood is burning!</span>")
|
||||
nanites.safety_threshold = 0
|
||||
|
||||
/datum/nanite_program/meltdown/disable_passive_effect()
|
||||
. = ..()
|
||||
to_chat(host_mob, "<span class='warning'>Your blood cools down, and the pain gradually fades.</span>")
|
||||
|
||||
/datum/nanite_program/triggered/explosive
|
||||
name = "Chain Detonation"
|
||||
desc = "Detonates all the nanites inside the host in a chain reaction when triggered."
|
||||
trigger_cost = 25 //plus every idle nanite left afterwards
|
||||
trigger_cooldown = 100 //Just to avoid double-triggering
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/explosive/trigger()
|
||||
if(!..())
|
||||
return
|
||||
host_mob.visible_message("<span class='warning'>[host_mob] starts emitting a high-pitched buzzing, and [host_mob.p_their()] skin begins to glow...</span>",\
|
||||
"<span class='userdanger'>You start emitting a high-pitched buzzing, and your skin begins to glow...</span>")
|
||||
addtimer(CALLBACK(src, .proc/boom), CLAMP((nanites.nanite_volume * 0.35), 25, 150))
|
||||
|
||||
/datum/nanite_program/triggered/explosive/proc/boom()
|
||||
var/nanite_amount = nanites.nanite_volume
|
||||
var/dev_range = FLOOR(nanite_amount/200, 1) - 1
|
||||
var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
|
||||
var/light_range = FLOOR(nanite_amount/50, 1) - 1
|
||||
explosion(host_mob, dev_range, heavy_range, light_range)
|
||||
qdel(nanites)
|
||||
|
||||
//TODO make it defuse if triggered again
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop
|
||||
name = "Heart-Stopper"
|
||||
desc = "Stops the host's heart when triggered; restarts it if triggered again."
|
||||
trigger_cost = 12
|
||||
trigger_cooldown = 10
|
||||
rogue_types = list(/datum/nanite_program/nerve_decay)
|
||||
|
||||
/datum/nanite_program/triggered/heart_stop/trigger()
|
||||
if(!..())
|
||||
return
|
||||
if(iscarbon(host_mob))
|
||||
var/mob/living/carbon/C = host_mob
|
||||
var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART)
|
||||
if(heart)
|
||||
if(heart.beating)
|
||||
heart.Stop()
|
||||
else
|
||||
heart.Restart()
|
||||
|
||||
/datum/nanite_program/triggered/emp
|
||||
name = "Electromagnetic Resonance"
|
||||
desc = "The nanites cause an elctromagnetic pulse around the host when triggered. Will corrupt other nanite programs!"
|
||||
trigger_cost = 10
|
||||
program_flags = NANITE_EMP_IMMUNE
|
||||
rogue_types = list(/datum/nanite_program/toxic)
|
||||
|
||||
/datum/nanite_program/triggered/emp/trigger()
|
||||
if(!..())
|
||||
return
|
||||
empulse(host_mob, 1, 2)
|
||||
|
||||
/datum/nanite_program/pyro/active_effect()
|
||||
host_mob.fire_stacks += 1
|
||||
host_mob.IgniteMob()
|
||||
|
||||
/datum/nanite_program/pyro
|
||||
name = "Sub-Dermal Combustion"
|
||||
desc = "The nanites cause buildup of flammable fluids under the host's skin, then ignites them."
|
||||
use_rate = 4
|
||||
rogue_types = list(/datum/nanite_program/skin_decay, /datum/nanite_program/cryo)
|
||||
|
||||
/datum/nanite_program/pyro/check_conditions()
|
||||
if(host_mob.fire_stacks >= 10 && host_mob.on_fire)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/pyro/active_effect()
|
||||
host_mob.fire_stacks += 1
|
||||
host_mob.IgniteMob()
|
||||
|
||||
/datum/nanite_program/cryo
|
||||
name = "Cryogenic Treatment"
|
||||
desc = "The nanites rapidly skin heat through the host's skin, lowering their temperature."
|
||||
use_rate = 1
|
||||
rogue_types = list(/datum/nanite_program/skin_decay, /datum/nanite_program/pyro)
|
||||
|
||||
/datum/nanite_program/cryo/check_conditions()
|
||||
if(host_mob.bodytemperature <= 70)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/nanite_program/cryo/active_effect()
|
||||
host_mob.adjust_bodytemperature(-rand(15,25), 50)
|
||||
|
||||
/datum/nanite_program/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
|
||||
use_rate = 3
|
||||
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
|
||||
|
||||
extra_settings = list("Directive")
|
||||
var/cooldown = 0 //avoids spam when nanites are running low
|
||||
var/directive = "..."
|
||||
|
||||
/datum/nanite_program/mind_control/set_extra_setting(user, setting)
|
||||
if(setting == "Directive")
|
||||
var/new_directive = stripped_input(user, "Choose the directive to imprint with mind control.", "Directive", directive, MAX_MESSAGE_LEN)
|
||||
if(!new_directive)
|
||||
return
|
||||
directive = new_directive
|
||||
|
||||
/datum/nanite_program/mind_control/get_extra_setting(setting)
|
||||
if(setting == "Directive")
|
||||
return directive
|
||||
|
||||
/datum/nanite_program/mind_control/copy_extra_settings_to(datum/nanite_program/mind_control/target)
|
||||
target.directive = directive
|
||||
|
||||
/datum/nanite_program/mind_control/enable_passive_effect()
|
||||
if(world.time < cooldown)
|
||||
return
|
||||
. = ..()
|
||||
brainwash(host_mob, directive)
|
||||
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
|
||||
|
||||
/datum/nanite_program/mind_control/disable_passive_effect()
|
||||
. = ..()
|
||||
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
|
||||
@@ -0,0 +1,172 @@
|
||||
#define REMOTE_MODE_OFF "Off"
|
||||
#define REMOTE_MODE_SELF "Local"
|
||||
#define REMOTE_MODE_TARGET "Targeted"
|
||||
#define REMOTE_MODE_AOE "Area"
|
||||
#define REMOTE_MODE_RELAY "Relay"
|
||||
|
||||
/obj/item/nanite_remote
|
||||
name = "nanite remote control"
|
||||
desc = "A device that can remotely control active nanites through wireless signals."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
req_access = list(ACCESS_ROBOTICS)
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "nanite_remote"
|
||||
item_flags = NOBLUDGEON
|
||||
var/locked = FALSE //Can be locked, so it can be given to users with a set code and mode
|
||||
var/mode = REMOTE_MODE_OFF
|
||||
var/list/saved_settings = list()
|
||||
var/last_id = 0
|
||||
var/code = 0
|
||||
var/relay_code = 0
|
||||
|
||||
/obj/item/nanite_remote/examine(mob/user)
|
||||
. = ..()
|
||||
if(locked)
|
||||
to_chat(user, "<span class='notice'>Alt-click to unlock.</span>")
|
||||
|
||||
/obj/item/nanite_remote/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(locked)
|
||||
if(allowed(user))
|
||||
to_chat(user, "<span class='notice'>You unlock [src].</span>")
|
||||
locked = FALSE
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
|
||||
/obj/item/nanite_remote/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
to_chat(user, "<span class='warning'>You override [src]'s ID lock.</span>")
|
||||
obj_flags |= EMAGGED
|
||||
if(locked)
|
||||
locked = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/nanite_remote/update_icon()
|
||||
. = ..()
|
||||
cut_overlays()
|
||||
if(obj_flags & EMAGGED)
|
||||
add_overlay("nanite_remote_emagged")
|
||||
if(locked)
|
||||
add_overlay("nanite_remote_locked")
|
||||
|
||||
/obj/item/nanite_remote/afterattack(atom/target, mob/user, etc)
|
||||
switch(mode)
|
||||
if(REMOTE_MODE_OFF)
|
||||
return
|
||||
if(REMOTE_MODE_SELF)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.<span>")
|
||||
signal_mob(user, code, key_name(user))
|
||||
if(REMOTE_MODE_TARGET)
|
||||
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].<span>")
|
||||
signal_mob(target, code, key_name(user))
|
||||
if(REMOTE_MODE_AOE)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.<span>")
|
||||
for(var/mob/living/L in view(user, 7))
|
||||
signal_mob(L, code, key_name(user))
|
||||
if(REMOTE_MODE_RELAY)
|
||||
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
|
||||
signal_relay(code, relay_code, key_name(user))
|
||||
|
||||
/obj/item/nanite_remote/proc/signal_mob(mob/living/M, code, source)
|
||||
SEND_SIGNAL(M, COMSIG_NANITE_SIGNAL, code, source)
|
||||
|
||||
/obj/item/nanite_remote/proc/signal_relay(code, relay_code, source)
|
||||
for(var/X in SSnanites.nanite_relays)
|
||||
var/datum/nanite_program/relay/N = X
|
||||
N.relay_signal(code, relay_code, source)
|
||||
|
||||
/obj/item/nanite_remote/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "nanite_remote", name, 420, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/nanite_remote/ui_data()
|
||||
var/list/data = list()
|
||||
data["code"] = code
|
||||
data["relay_code"] = relay_code
|
||||
data["mode"] = mode
|
||||
data["locked"] = locked
|
||||
data["saved_settings"] = saved_settings
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/nanite_remote/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("set_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set code (0000-9999):", name, code) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
code = new_code
|
||||
. = TRUE
|
||||
if("set_relay_code")
|
||||
if(locked)
|
||||
return
|
||||
var/new_code = input("Set relay code (0000-9999):", name, code) as null|num
|
||||
if(!isnull(new_code))
|
||||
new_code = CLAMP(round(new_code, 1),0,9999)
|
||||
relay_code = new_code
|
||||
. = TRUE
|
||||
if("save")
|
||||
if(locked)
|
||||
return
|
||||
var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
|
||||
if(!code_name)
|
||||
return
|
||||
var/new_save = list()
|
||||
new_save["id"] = last_id + 1
|
||||
last_id++
|
||||
new_save["name"] = code_name
|
||||
new_save["code"] = code
|
||||
new_save["mode"] = mode
|
||||
new_save["relay_code"] = relay_code
|
||||
|
||||
saved_settings += list(new_save)
|
||||
. = TRUE
|
||||
if("load")
|
||||
var/code_id = params["save_id"]
|
||||
var/list/setting
|
||||
for(var/list/X in saved_settings)
|
||||
if(X["id"] == text2num(code_id))
|
||||
setting = X
|
||||
break
|
||||
if(setting)
|
||||
code = setting["code"]
|
||||
mode = setting["mode"]
|
||||
relay_code = setting["relay_code"]
|
||||
. = TRUE
|
||||
if("remove_save")
|
||||
if(locked)
|
||||
return
|
||||
var/code_id = params["save_id"]
|
||||
for(var/list/setting in saved_settings)
|
||||
if(setting["id"] == text2num(code_id))
|
||||
saved_settings -= list(setting)
|
||||
break
|
||||
. = TRUE
|
||||
if("select_mode")
|
||||
if(locked)
|
||||
return
|
||||
mode = params["mode"]
|
||||
. = TRUE
|
||||
if("lock")
|
||||
if(!(obj_flags & EMAGGED))
|
||||
locked = TRUE
|
||||
update_icon()
|
||||
. = TRUE
|
||||
|
||||
|
||||
#undef REMOTE_MODE_OFF
|
||||
#undef REMOTE_MODE_SELF
|
||||
#undef REMOTE_MODE_TARGET
|
||||
#undef REMOTE_MODE_AOE
|
||||
#undef REMOTE_MODE_RELAY
|
||||
@@ -0,0 +1,133 @@
|
||||
//Names are intentionally all the same - track your nanites, or use a hand labeler
|
||||
//This also means that you can give flesh melting nanites to your victims if you feel like it
|
||||
|
||||
/obj/item/disk/nanite_program
|
||||
name = "nanite program disk"
|
||||
desc = "A disk capable of storing nanite programs. Can be customized using a Nanite Programming Console."
|
||||
var/program_type
|
||||
var/datum/nanite_program/program
|
||||
|
||||
/obj/item/disk/nanite_program/Initialize()
|
||||
. = ..()
|
||||
if(program_type)
|
||||
program = new program_type
|
||||
|
||||
/obj/item/disk/nanite_program/aggressive_replication
|
||||
program_type = /datum/nanite_program/aggressive_replication
|
||||
|
||||
/obj/item/disk/nanite_program/metabolic_synthesis
|
||||
program_type = /datum/nanite_program/metabolic_synthesis
|
||||
|
||||
/obj/item/disk/nanite_program/viral
|
||||
program_type = /datum/nanite_program/viral
|
||||
|
||||
/obj/item/disk/nanite_program/meltdown
|
||||
program_type = /datum/nanite_program/meltdown
|
||||
|
||||
/obj/item/disk/nanite_program/monitoring
|
||||
program_type = /datum/nanite_program/monitoring
|
||||
|
||||
/obj/item/disk/nanite_program/relay
|
||||
program_type = /datum/nanite_program/relay
|
||||
|
||||
/obj/item/disk/nanite_program/emp
|
||||
program_type = /datum/nanite_program/triggered/emp
|
||||
|
||||
/obj/item/disk/nanite_program/spreading
|
||||
program_type = /datum/nanite_program/spreading
|
||||
|
||||
/obj/item/disk/nanite_program/regenerative
|
||||
program_type = /datum/nanite_program/regenerative
|
||||
|
||||
/obj/item/disk/nanite_program/regenerative_advanced
|
||||
program_type = /datum/nanite_program/regenerative_advanced
|
||||
|
||||
/obj/item/disk/nanite_program/temperature
|
||||
program_type = /datum/nanite_program/temperature
|
||||
|
||||
/obj/item/disk/nanite_program/purging
|
||||
program_type = /datum/nanite_program/purging
|
||||
|
||||
/obj/item/disk/nanite_program/purging_advanced
|
||||
program_type = /datum/nanite_program/purging_advanced
|
||||
|
||||
/obj/item/disk/nanite_program/brain_heal
|
||||
program_type = /datum/nanite_program/brain_heal
|
||||
|
||||
/obj/item/disk/nanite_program/brain_heal_advanced
|
||||
program_type = /datum/nanite_program/brain_heal_advanced
|
||||
|
||||
/obj/item/disk/nanite_program/blood_restoring
|
||||
program_type = /datum/nanite_program/blood_restoring
|
||||
|
||||
/obj/item/disk/nanite_program/repairing
|
||||
program_type = /datum/nanite_program/repairing
|
||||
|
||||
/obj/item/disk/nanite_program/nervous
|
||||
program_type = /datum/nanite_program/nervous
|
||||
|
||||
/obj/item/disk/nanite_program/hardening
|
||||
program_type = /datum/nanite_program/hardening
|
||||
|
||||
/obj/item/disk/nanite_program/coagulating
|
||||
program_type = /datum/nanite_program/coagulating
|
||||
|
||||
/obj/item/disk/nanite_program/necrotic
|
||||
program_type = /datum/nanite_program/necrotic
|
||||
|
||||
/obj/item/disk/nanite_program/brain_decay
|
||||
program_type = /datum/nanite_program/brain_decay
|
||||
|
||||
/obj/item/disk/nanite_program/pyro
|
||||
program_type = /datum/nanite_program/pyro
|
||||
|
||||
/obj/item/disk/nanite_program/cryo
|
||||
program_type = /datum/nanite_program/cryo
|
||||
|
||||
/obj/item/disk/nanite_program/toxic
|
||||
program_type = /datum/nanite_program/toxic
|
||||
|
||||
/obj/item/disk/nanite_program/suffocating
|
||||
program_type = /datum/nanite_program/suffocating
|
||||
|
||||
/obj/item/disk/nanite_program/heart_stop
|
||||
program_type = /datum/nanite_program/triggered/heart_stop
|
||||
|
||||
/obj/item/disk/nanite_program/explosive
|
||||
program_type = /datum/nanite_program/triggered/explosive
|
||||
|
||||
/obj/item/disk/nanite_program/shock
|
||||
program_type = /datum/nanite_program/triggered/shocking
|
||||
|
||||
/obj/item/disk/nanite_program/sleepy
|
||||
program_type = /datum/nanite_program/triggered/sleepy
|
||||
|
||||
/obj/item/disk/nanite_program/paralyzing
|
||||
program_type = /datum/nanite_program/paralyzing
|
||||
|
||||
/obj/item/disk/nanite_program/fake_death
|
||||
program_type = /datum/nanite_program/fake_death
|
||||
|
||||
/obj/item/disk/nanite_program/pacifying
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/glitch
|
||||
program_type = /datum/nanite_program/glitch
|
||||
|
||||
/obj/item/disk/nanite_program/brain_misfire
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/skin_decay
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/nerve_decay
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/refractive
|
||||
program_type = /datum/nanite_program/refractive
|
||||
|
||||
/obj/item/disk/nanite_program/conductive
|
||||
program_type = /datum/nanite_program/pacifying
|
||||
|
||||
/obj/item/disk/nanite_program/stun
|
||||
program_type = /datum/nanite_program/triggered/stun
|
||||
@@ -0,0 +1,174 @@
|
||||
/obj/machinery/public_nanite_chamber
|
||||
name = "public nanite chamber"
|
||||
desc = "A device that can rapidly implant cloud-synced nanites without an external operator."
|
||||
circuit = /obj/item/circuitboard/machine/public_nanite_chamber
|
||||
icon = 'icons/obj/machines/nanite_chamber.dmi'
|
||||
icon_state = "nanite_chamber"
|
||||
use_power = IDLE_POWER_USE
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
idle_power_usage = 50
|
||||
active_power_usage = 300
|
||||
occupant_typecache = list(/mob/living)
|
||||
|
||||
var/cloud_id = 1
|
||||
var/locked = FALSE
|
||||
var/breakout_time = 1200
|
||||
var/busy = FALSE
|
||||
var/busy_icon_state
|
||||
var/message_cooldown = 0
|
||||
|
||||
/obj/machinery/public_nanite_chamber/RefreshParts()
|
||||
var/obj/item/circuitboard/machine/public_nanite_chamber/board = circuit
|
||||
if(board)
|
||||
cloud_id = board.cloud_id
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/set_busy(status, working_icon)
|
||||
busy = status
|
||||
busy_icon_state = working_icon
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/inject_nanites()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if((stat & MAINT) || panel_open)
|
||||
return
|
||||
if(!occupant || busy)
|
||||
return
|
||||
|
||||
var/locked_state = locked
|
||||
locked = TRUE
|
||||
|
||||
//TODO OMINOUS MACHINE SOUNDS
|
||||
set_busy(TRUE, "[initial(icon_state)]_raising")
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"),20)
|
||||
addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"),60)
|
||||
addtimer(CALLBACK(src, .proc/complete_injection, locked_state),80)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state)
|
||||
//TODO MACHINE DING
|
||||
locked = locked_state
|
||||
set_busy(FALSE)
|
||||
if(!occupant)
|
||||
return
|
||||
occupant.AddComponent(/datum/component/nanites, 75, cloud_id)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
if((stat & MAINT) || panel_open)
|
||||
add_overlay("maint")
|
||||
|
||||
else if(!(stat & (NOPOWER|BROKEN)))
|
||||
if(busy || locked)
|
||||
add_overlay("red")
|
||||
if(locked)
|
||||
add_overlay("bolted")
|
||||
else
|
||||
add_overlay("green")
|
||||
|
||||
|
||||
|
||||
//running and someone in there
|
||||
if(occupant)
|
||||
if(busy)
|
||||
icon_state = busy_icon_state
|
||||
else
|
||||
icon_state = initial(icon_state)+ "_occupied"
|
||||
return
|
||||
|
||||
//running
|
||||
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
|
||||
|
||||
/obj/machinery/public_nanite_chamber/power_change()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/toggle_open(mob/user)
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
if(state_open)
|
||||
close_machine()
|
||||
return
|
||||
|
||||
else if(locked)
|
||||
to_chat(user, "<span class='notice'>The bolts are locked down, securing the door shut.</span>")
|
||||
return
|
||||
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/container_resist(mob/living/user)
|
||||
if(!locked)
|
||||
open_machine()
|
||||
return
|
||||
if(busy)
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked || busy)
|
||||
return
|
||||
locked = FALSE
|
||||
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
|
||||
"<span class='notice'>You successfully break out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user)
|
||||
if(!state_open)
|
||||
return FALSE
|
||||
|
||||
..()
|
||||
|
||||
. = TRUE
|
||||
|
||||
addtimer(CALLBACK(src, .proc/try_inject_nanites), 30) //If someone is shoved in give them a chance to get out before the injection starts
|
||||
|
||||
/obj/machinery/public_nanite_chamber/proc/try_inject_nanites()
|
||||
if(occupant)
|
||||
var/mob/living/L = occupant
|
||||
if(SEND_SIGNAL(L, COMSIG_HAS_NANITES))
|
||||
return
|
||||
if((MOB_ORGANIC in L.mob_biotypes) || (MOB_UNDEAD in L.mob_biotypes))
|
||||
inject_nanites()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/open_machine()
|
||||
if(state_open)
|
||||
return FALSE
|
||||
|
||||
..()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/public_nanite_chamber/relaymove(mob/user as mob)
|
||||
if(user.stat || locked)
|
||||
if(message_cooldown <= world.time)
|
||||
message_cooldown = world.time + 50
|
||||
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
|
||||
return
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/attackby(obj/item/I, mob/user, params)
|
||||
if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant...
|
||||
update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed
|
||||
return
|
||||
|
||||
if(default_pry_open(I))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(I))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/public_nanite_chamber/interact(mob/user)
|
||||
toggle_open(user)
|
||||
|
||||
/obj/machinery/public_nanite_chamber/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
|
||||
return
|
||||
close_machine(target)
|
||||
@@ -832,6 +832,91 @@
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/////////////////////////Nanites/////////////////////////
|
||||
/datum/techweb_node/nanite_base
|
||||
id = "nanite_base"
|
||||
display_name = "Basic Nanite Programming"
|
||||
description = "The basics of nanite construction and programming."
|
||||
prereq_ids = list("datatheory","robotics")
|
||||
design_ids = list("nanite_disk","nanite_remote","nanite_scanner",\
|
||||
"nanite_chamber","public_nanite_chamber","nanite_chamber_control","nanite_programmer","nanite_program_hub","nanite_cloud_control",\
|
||||
"relay_nanites", "monitoring_nanites", "access_nanites", "repairing_nanites","sensor_nanite_volume", "repeater_nanites", "relay_repeater_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/nanite_smart
|
||||
id = "nanite_smart"
|
||||
display_name = "Smart Nanite Programming"
|
||||
description = "Nanite programs that require nanites to perform complex actions, act independently, roam or seek targets."
|
||||
prereq_ids = list("nanite_base","adv_robotics")
|
||||
design_ids = list("purging_nanites", "metabolic_nanites", "stealth_nanites", "memleak_nanites","sensor_voice_nanites", "voice_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000)
|
||||
export_price = 4000
|
||||
|
||||
/datum/techweb_node/nanite_mesh
|
||||
id = "nanite_mesh"
|
||||
display_name = "Mesh Nanite Programming"
|
||||
description = "Nanite programs that require static structures and membranes."
|
||||
prereq_ids = list("nanite_base","engineering")
|
||||
design_ids = list("hardening_nanites", "refractive_nanites", "cryo_nanites", "conductive_nanites", "shock_nanites", "emp_nanites", "temperature_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/nanite_bio
|
||||
id = "nanite_bio"
|
||||
display_name = "Biological Nanite Programming"
|
||||
description = "Nanite programs that require complex biological interaction."
|
||||
prereq_ids = list("nanite_base","biotech")
|
||||
design_ids = list("regenerative_nanites", "bloodheal_nanites", "coagulating_nanites","poison_nanites","flesheating_nanites",\
|
||||
"sensor_crit_nanites","sensor_death_nanites", "sensor_health_nanites", "sensor_damage_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/nanite_neural
|
||||
id = "nanite_neural"
|
||||
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")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/nanite_synaptic
|
||||
id = "nanite_synaptic"
|
||||
display_name = "Synaptic Nanite Programming"
|
||||
description = "Nanite programs affecting mind and thoughts."
|
||||
prereq_ids = list("nanite_neural","neural_programming")
|
||||
design_ids = list("mindshield_nanites", "pacifying_nanites", "blinding_nanites", "sleep_nanites", "mute_nanites", "speech_nanites","hallucination_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/nanite_harmonic
|
||||
id = "nanite_harmonic"
|
||||
display_name = "Harmonic Nanite Programming"
|
||||
description = "Nanite programs that require seamless integration between nanites and biology."
|
||||
prereq_ids = list("nanite_bio","nanite_smart","nanite_mesh")
|
||||
design_ids = list("fakedeath_nanites","aggressive_nanites","defib_nanites","regenerative_plus_nanites","brainheal_plus_nanites","purging_plus_nanites","adrenaline_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
|
||||
export_price = 8000
|
||||
|
||||
/datum/techweb_node/nanite_combat
|
||||
id = "nanite_military"
|
||||
display_name = "Military Nanite Programming"
|
||||
description = "Nanite programs that perform military-grade functions."
|
||||
prereq_ids = list("nanite_harmonic", "syndicate_basic")
|
||||
design_ids = list("explosive_nanites","pyro_nanites","meltdown_nanites","viral_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500)
|
||||
export_price = 12500
|
||||
|
||||
/datum/techweb_node/nanite_hazard
|
||||
id = "nanite_hazard"
|
||||
display_name = "Hazard Nanite Programs"
|
||||
description = "Extremely advanced Nanite programs with the potential of being extremely dangerous."
|
||||
prereq_ids = list("nanite_harmonic", "alientech")
|
||||
design_ids = list("spreading_nanites","mindcontrol_nanites","mitosis_nanites")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
|
||||
export_price = 15000
|
||||
|
||||
////////////////////////Alien technology////////////////////////
|
||||
/datum/techweb_node/alientech //AYYYYYYYYLMAOO tech
|
||||
id = "alientech"
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
if(!target.mind)
|
||||
user.visible_message("[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...")
|
||||
return FALSE
|
||||
if(target.isloyal())
|
||||
if(target.has_trait(TRAIT_MINDSHIELD))
|
||||
user.visible_message("You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased.")
|
||||
return FALSE
|
||||
user.visible_message("[user] successfully brainwashes [target]!", "<span class='notice'>You succeed in brainwashing [target].</span>")
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 28 KiB |