From 9950e761c45f1e336b73df49b1ea1a366475ffac Mon Sep 17 00:00:00 2001 From: Arturlang <24881678+Arturlang@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:33:42 +0300 Subject: [PATCH] Re-adds nanites (#2995) ## About The Pull Request Re-adds nanites, balance changes pending. No plans to do mapping/role changes Based on https://github.com/tgstation/tgstation/pull/60473 with a lot of work on modularizing ## Why It's Good For The Game Nanites are a rather interesting system, my hope is to port it in a more balanced format. ## Proof Of Testing Works, thoroughly tested ## Changelog :cl: add: Re-adds nanites /:cl: TODO: - [x] Add techweb linking for nanites - [x] Prevent stacking of armor mods (fortitude + dna vault + nanite armor) - [x] Rebalance damage regeneration programs - [x] Remove force speak program by @StrangeWeirdKitten request - [x] Convert UI's to TSX - [x] Fix Nanite program uhb and programmer overlays not working --------- Co-authored-by: Waterpig <49160555+Majkl-J@users.noreply.github.com> --- bubber_archive/blueshift/Blueshift.dmm | 4 +- code/__DEFINES/atom_hud.dm | 4 + code/__DEFINES/logging.dm | 2 + code/__DEFINES/machines.dm | 1 + code/__DEFINES/research.dm | 1 + code/__DEFINES/~~bubber_defines/nanites.dm | 71 +++ code/__DEFINES/~~bubber_defines/signals.dm | 2 + .../~~bubber_defines/traits/nanites.dm | 40 ++ .../~~bubber_defines/traits/sources.dm | 2 + code/__DEFINES/~~bubber_defines/vomit.dm | 2 + code/_globalvars/lists/mobs.dm | 1 + code/controllers/subsystem/research.dm | 2 +- code/game/data_huds.dm | 6 +- code/game/machinery/computer/crew.dm | 31 +- .../items/devices/scanners/health_analyzer.dm | 1 + code/game/objects/items/pinpointer.dm | 2 + code/modules/admin/admin_investigate.dm | 1 + code/modules/mob/living/carbon/alien/alien.dm | 7 + .../mob/living/carbon/carbon_defines.dm | 2 +- .../mob/living/carbon/human/human_defines.dm | 2 +- .../carbon/human/species_types/jellypeople.dm | 8 + code/modules/mob/living/damage_procs.dm | 3 + code/modules/mob/living/living_defines.dm | 2 +- .../file_system/programs/radar.dm | 2 + icons/obj/machines/computer.dmi | Bin 138564 -> 137966 bytes modular_zubbers/code/__DEFINES/traits.dm | 3 + .../subsystem/processing/nanites.dm | 22 + .../code/datums/components/nanites.dm | 531 ++++++++++++++++ .../code/datums/mood_events/nanite_events.dm | 13 + modular_zubbers/code/game/area/nanite.dm | 3 + .../mob/living/carbon/human/physiology.dm | 28 + .../code/modules/nanites/designs.dm | 91 +++ .../nanites/extra_settings/_extra_setting.dm | 20 + .../modules/nanites/extra_settings/boolean.dm | 27 + .../modules/nanites/extra_settings/number.dm | 32 + .../modules/nanites/extra_settings/text.dm | 21 + .../modules/nanites/extra_settings/type.dm | 18 + .../code/modules/nanites/items/boards.dm | 58 ++ .../code/modules/nanites/items/items.dm | 47 ++ .../modules/nanites/items/program_disks.dm | 147 +++++ .../code/modules/nanites/items/remote.dm | 247 ++++++++ .../code/modules/nanites/living.dm | 7 + .../nanites/machines/nanite_chamber.dm | 213 +++++++ .../machines/nanite_chamber_computer.dm | 109 ++++ .../machines/nanite_cloud_controller.dm | 306 ++++++++++ .../nanites/machines/nanite_program_hub.dm | 181 ++++++ .../nanites/machines/nanite_programmer.dm | 178 ++++++ .../nanites/machines/public_chamber.dm | 207 +++++++ .../code/modules/nanites/nanite_programs.dm | 335 ++++++++++ .../nanites/nanite_programs/buffing.dm | 231 +++++++ .../nanites/nanite_programs/healing.dm | 190 ++++++ .../nanites/nanite_programs/protocols.dm | 277 +++++++++ .../modules/nanites/nanite_programs/rogue.dm | 119 ++++ .../modules/nanites/nanite_programs/sensor.dm | 312 ++++++++++ .../nanites/nanite_programs/suppression.dm | 292 +++++++++ .../nanites/nanite_programs/utility.dm | 331 ++++++++++ .../modules/nanites/nanite_programs/weapon.dm | 186 ++++++ .../code/modules/nanites/nanite_sign.dm | 9 + .../code/modules/nanites/nanite_symptom.dm | 71 +++ .../code/modules/nanites/program_designs.dm | 573 ++++++++++++++++++ modular_zubbers/code/modules/nanites/rules.dm | 148 +++++ .../code/modules/nanites/spawners.dm | 11 + .../code/modules/nanites/techweb_nodes.dm | 180 ++++++ .../code/modules/nanites/unit_test.dm | 9 + modular_zubbers/icons/areas/nanite_area.dmi | Bin 0 -> 329 bytes .../icons/effects/decals/nanite_decal.dmi | Bin 0 -> 364 bytes modular_zubbers/icons/mob/huds/hud.dmi | Bin 14910 -> 15116 bytes .../icons/obj/devices/nanite_devices.dmi | Bin 0 -> 1040 bytes .../icons/obj/machines/nanite_machines.dmi | Bin 0 -> 10383 bytes .../icons/obj/signs/nanite_sign.dmi | Bin 0 -> 364 bytes strings/cas_white.txt | 1 + strings/locations.json | 3 +- tgstation.dme | 40 ++ .../tgui/interfaces/NaniteChamberControl.tsx | 286 +++++++++ .../tgui/interfaces/NaniteCloudControl.tsx | 366 +++++++++++ .../tgui/interfaces/NaniteProgramHub.tsx | 177 ++++++ .../tgui/interfaces/NaniteProgrammer.tsx | 402 ++++++++++++ .../packages/tgui/interfaces/NaniteRemote.tsx | 198 ++++++ .../interfaces/Nanites/NoTechwebWarning.tsx | 17 + .../tgui/interfaces/Nanites/types.d.ts | 34 ++ tgui/packages/tgui/interfaces/ScannerGate.jsx | 63 +- .../tgui/interfaces/Techweb/Content.tsx | 5 +- 82 files changed, 7550 insertions(+), 24 deletions(-) create mode 100644 code/__DEFINES/~~bubber_defines/nanites.dm create mode 100644 code/__DEFINES/~~bubber_defines/traits/nanites.dm create mode 100644 code/__DEFINES/~~bubber_defines/vomit.dm create mode 100644 modular_zubbers/code/controllers/subsystem/processing/nanites.dm create mode 100644 modular_zubbers/code/datums/components/nanites.dm create mode 100644 modular_zubbers/code/datums/mood_events/nanite_events.dm create mode 100644 modular_zubbers/code/game/area/nanite.dm create mode 100644 modular_zubbers/code/modules/mob/living/carbon/human/physiology.dm create mode 100644 modular_zubbers/code/modules/nanites/designs.dm create mode 100644 modular_zubbers/code/modules/nanites/extra_settings/_extra_setting.dm create mode 100644 modular_zubbers/code/modules/nanites/extra_settings/boolean.dm create mode 100644 modular_zubbers/code/modules/nanites/extra_settings/number.dm create mode 100644 modular_zubbers/code/modules/nanites/extra_settings/text.dm create mode 100644 modular_zubbers/code/modules/nanites/extra_settings/type.dm create mode 100644 modular_zubbers/code/modules/nanites/items/boards.dm create mode 100644 modular_zubbers/code/modules/nanites/items/items.dm create mode 100644 modular_zubbers/code/modules/nanites/items/program_disks.dm create mode 100644 modular_zubbers/code/modules/nanites/items/remote.dm create mode 100644 modular_zubbers/code/modules/nanites/living.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/nanite_chamber.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/nanite_chamber_computer.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/nanite_cloud_controller.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/nanite_program_hub.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/nanite_programmer.dm create mode 100644 modular_zubbers/code/modules/nanites/machines/public_chamber.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/buffing.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/healing.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/protocols.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/rogue.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/sensor.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/utility.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_programs/weapon.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_sign.dm create mode 100644 modular_zubbers/code/modules/nanites/nanite_symptom.dm create mode 100644 modular_zubbers/code/modules/nanites/program_designs.dm create mode 100644 modular_zubbers/code/modules/nanites/rules.dm create mode 100644 modular_zubbers/code/modules/nanites/spawners.dm create mode 100644 modular_zubbers/code/modules/nanites/techweb_nodes.dm create mode 100644 modular_zubbers/code/modules/nanites/unit_test.dm create mode 100644 modular_zubbers/icons/areas/nanite_area.dmi create mode 100644 modular_zubbers/icons/effects/decals/nanite_decal.dmi create mode 100644 modular_zubbers/icons/obj/devices/nanite_devices.dmi create mode 100644 modular_zubbers/icons/obj/machines/nanite_machines.dmi create mode 100644 modular_zubbers/icons/obj/signs/nanite_sign.dmi create mode 100644 tgui/packages/tgui/interfaces/NaniteChamberControl.tsx create mode 100644 tgui/packages/tgui/interfaces/NaniteCloudControl.tsx create mode 100644 tgui/packages/tgui/interfaces/NaniteProgramHub.tsx create mode 100644 tgui/packages/tgui/interfaces/NaniteProgrammer.tsx create mode 100644 tgui/packages/tgui/interfaces/NaniteRemote.tsx create mode 100644 tgui/packages/tgui/interfaces/Nanites/NoTechwebWarning.tsx create mode 100644 tgui/packages/tgui/interfaces/Nanites/types.d.ts diff --git a/bubber_archive/blueshift/Blueshift.dmm b/bubber_archive/blueshift/Blueshift.dmm index 3dd6caee06c..44c78a2faaa 100644 --- a/bubber_archive/blueshift/Blueshift.dmm +++ b/bubber_archive/blueshift/Blueshift.dmm @@ -41179,7 +41179,7 @@ pixel_y = 2 }, /obj/item/organ/external/tail/lizard, -/obj/item/organ/internal/ears/cat, +/obj/item/organ/ears/cat, /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-flat-1" }, @@ -85176,7 +85176,7 @@ name = "organ storage" }, /obj/item/organ/external/tail/cat, -/obj/item/organ/internal/ears/cat, +/obj/item/organ/ears/cat, /obj/item/organ/internal/heart, /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-flat-1" diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 1682fa4f953..91862241d69 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -56,6 +56,10 @@ /// If they have the DNR trait #define DNR_HUD "27" // SKYRAT EDIT ADDITION END +// BUBBER EDIT ADDITION START +#define NANITE_HUD "28" +#define DIAG_NANITE_FULL_HUD "29" +// BUBBER EDIT ADDITION END //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 diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 93245670782..e3d71a2d9e1 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -26,6 +26,8 @@ #define INVESTIGATE_RECORDS "records" #define INVESTIGATE_RESEARCH "research" #define INVESTIGATE_WIRES "wires" +#define INVESTIGATE_NANITES "nanites" // BUBBER EDIT ADDITION + // Logging types for log_message() #define LOG_ATTACK (1 << 0) diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index e5d7ce45ac5..dc7dfac3fd0 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -64,6 +64,7 @@ #define BIOGENERATOR (1<<4) //Uses biomass #define LIMBGROWER (1<<5) //Uses synthetic flesh #define SMELTER (1<<6) //uses various minerals +#define NANITE_COMPILER (1<<7) //Prints nanite disks BUBBER EDIT ADDITION - NANITES /// Protolathes for offstation roles. More limited tech tree. #define AWAY_LATHE (1<<8) /// Imprinters for offstation roles. More limited tech tree. diff --git a/code/__DEFINES/research.dm b/code/__DEFINES/research.dm index cf35d553ec4..feedbd61a88 100644 --- a/code/__DEFINES/research.dm +++ b/code/__DEFINES/research.dm @@ -3,6 +3,7 @@ //! Techweb names for new point types. Can be used to define specific point values for specific types of research (science, security, engineering, etc.) #define TECHWEB_POINT_TYPE_GENERIC "General Research" +#define TECHWEB_POINT_TYPE_NANITE "Nanite Research" // BUBBER EDIT ADDITION - NANITES //! Amount of points required to unlock nodes of corresponding tiers #define TECHWEB_TIER_1_POINTS 40 diff --git a/code/__DEFINES/~~bubber_defines/nanites.dm b/code/__DEFINES/~~bubber_defines/nanites.dm new file mode 100644 index 00000000000..f99ea731b4c --- /dev/null +++ b/code/__DEFINES/~~bubber_defines/nanites.dm @@ -0,0 +1,71 @@ +#define CAN_HAVE_NANITES(host_mob) (host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD|MOB_ROBOTIC) && !issilicon(host_mob)) + +#define NANITE_SYNC_DELAY 300 + +#define NANITE_SHOCK_IMMUNE 1 +#define NANITE_EMP_IMMUNE 2 + +#define NANITE_PROGRAM_LIMIT 20 + +#define NANITE_BASE_RESEARCH_PROGRESS 25 + +#define NANITE_CLOUD_TOGGLE 1 +#define NANITE_CLOUD_DISABLE 2 +#define NANITE_CLOUD_ENABLE 3 + +//Nanite excess thresholds +#define NANITE_EXCESS_MINOR 25 +#define NANITE_EXCESS_VOMIT 100 +#define NANITE_EXCESS_BURST 350 + +#define NANITE_BIO_REGENERATION 0.5 +#define NANITE_ADV_BIO_REGENERATION NANITE_BIO_REGENERATION * 4 +#define NANITE_ROBO_REGENERATION NANITE_BIO_REGENERATION * 2 + +#define NANITE_TOX_REGENERATION 0.5 +#define NANITE_ADV_TOX_REGENERATION NANITE_TOX_REGENERATION + +#define NANITE_BRAIN_REGENERATION 0.2 +#define NANITE_ADV_BRAIN_REGENERATION NANITE_BRAIN_REGENERATION * 2 + +#define HARMFUL_PROGRAM_DAMAGE_SCALE 1.25 +#define NANITE_OXYLOSS 5 + +#define NANITE_PROTOCOL_KICKSTART_REPLICATION 3.5 +#define NANITE_PROTOCOL_FACTORY_MAX_REPLICATION 2 + +///Nanite Protocol types +#define NANITE_PROTOCOL_REPLICATION "nanite_replication" +#define NANITE_PROTOCOL_STORAGE "nanite_storage" + +///Nanite extra settings types: used to help uis know what type an extra setting is +#define NESTYPE_TEXT "text" +#define NESTYPE_NUMBER "number" +#define NESTYPE_TYPE "type" +#define NESTYPE_BOOLEAN "boolean" + +///Nanite Extra Settings - Note that these will also be the names displayed in the UI +#define NES_SENT_CODE "Sent Code" +#define NES_DELAY "Delay" +#define NES_MODE "Mode" +#define NES_COMM_CODE "Comm Code" +#define NES_RELAY_CHANNEL "Relay Channel" +#define NES_HEALTH_PERCENT "Health Percent" +#define NES_DIRECTION "Direction" +#define NES_NANITE_PERCENT "Nanite Percent" +#define NES_DAMAGE_TYPE "Damage Type" +#define NES_DAMAGE "Damage" +#define NES_SENTENCE "Sentence" +#define NES_MESSAGE "Message" +#define NES_DIRECTIVE "Directive" +#define NES_INCLUSIVE_MODE "Inclusive Mode" +#define NES_RACE "Race" +#define NES_HALLUCINATION_TYPE "Hallucination Type" +#define NES_HALLUCINATION_DETAIL "Hallucination Detail" +#define NES_MOOD_MESSAGE "Mood Message" +#define NES_PROGRAM_OVERWRITE "Program Overwrite" +#define NES_CLOUD_OVERWRITE "Cloud Overwrite" +#define NES_SCAN_TYPE "Scan Type" +#define NES_BUTTON_NAME "Button Name" +#define NES_ICON "Icon" +#define NANITE_HARMONIC_ID "Nano Harmonic ID" diff --git a/code/__DEFINES/~~bubber_defines/signals.dm b/code/__DEFINES/~~bubber_defines/signals.dm index 49876f8d3fc..cc1c21adf6e 100644 --- a/code/__DEFINES/~~bubber_defines/signals.dm +++ b/code/__DEFINES/~~bubber_defines/signals.dm @@ -8,5 +8,7 @@ #define COMSIG_ORGAN_BODYPART_REMOVED "organ_bodypart_removed" /// From /datum/controller/subsystem/economy/proc/issue_paydays() #define COMSIG_ON_BANK_ACCOUNT_PAYOUT "bank_account_payout" +/// identical to COMSIG_MOB_APPLY_DAMAGE, but always runs, even if there is no damage +#define COMSIG_MOB_ALWAYS_APPLY_DAMAGE "mob_always_apply_damage" /// From modular_zubbers/code/modules/disease/disease_transmission.dm #define COMSIG_DISEASE_COUNT_UPDATE "disease_count_update" diff --git a/code/__DEFINES/~~bubber_defines/traits/nanites.dm b/code/__DEFINES/~~bubber_defines/traits/nanites.dm new file mode 100644 index 00000000000..ea1b3b7ff12 --- /dev/null +++ b/code/__DEFINES/~~bubber_defines/traits/nanites.dm @@ -0,0 +1,40 @@ +///() returns TRUE if nanites are found +#define COMSIG_HAS_NANITES "has_nanites" +///() returns TRUE if nanites have stealth +#define COMSIG_NANITE_IS_STEALTHY "nanite_is_stealthy" +///() deletes the nanite component +#define COMSIG_NANITE_DELETE "nanite_delete" +///(list/nanite_programs) - makes the input list a copy the nanites' program list +#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" +///(amount) Returns nanite amount +#define COMSIG_NANITE_GET_VOLUME "nanite_get_volume" +///(amount) Sets current nanite volume to the given amount +#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" +///(amount) Adjusts nanite volume by the given amount +#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust" +///(amount) Sets maximum nanite volume to the given amount +#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume" +///(amount(0-100)) Sets cloud ID to the given amount +#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud" +///(method) Modify cloud sync status. Method can be toggle, enable or disable +#define COMSIG_NANITE_SET_CLOUD_SYNC "nanite_set_cloud_sync" +///(amount) Sets safety threshold to the given amount +#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" +///(amount) Sets regeneration rate to the given amount +#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" +///(code(1-9999)) Called when sending a nanite signal to a mob. +#define COMSIG_NANITE_SIGNAL "nanite_signal" +///(comm_code(1-9999), comm_message) Called when sending a nanite comm signal to a mob. +#define COMSIG_NANITE_COMM_SIGNAL "nanite_comm_signal" +///(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected +#define COMSIG_NANITE_SCAN "nanite_scan" +///(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs +#define COMSIG_NANITE_UI_DATA "nanite_ui_data" +///(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component +#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" + ///Installation successful + #define COMPONENT_PROGRAM_INSTALLED (1<<0) + ///Installation failed, but there are still nanites + #define COMPONENT_PROGRAM_NOT_INSTALLED (1<<1) +///(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component +#define COMSIG_NANITE_SYNC "nanite_sync" diff --git a/code/__DEFINES/~~bubber_defines/traits/sources.dm b/code/__DEFINES/~~bubber_defines/traits/sources.dm index fb073441fc2..6cc1f854a18 100644 --- a/code/__DEFINES/~~bubber_defines/traits/sources.dm +++ b/code/__DEFINES/~~bubber_defines/traits/sources.dm @@ -1,2 +1,4 @@ // Loadout trait #define TRAIT_SOURCE_LOADOUT "loadout" + +#define NANITES_TRAIT "nanites" diff --git a/code/__DEFINES/~~bubber_defines/vomit.dm b/code/__DEFINES/~~bubber_defines/vomit.dm new file mode 100644 index 00000000000..025baa04897 --- /dev/null +++ b/code/__DEFINES/~~bubber_defines/vomit.dm @@ -0,0 +1,2 @@ + +#define VOMIT_CATEGORY_NANITE MOB_VOMIT_MESSAGE diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 73c75fec3ba..d88d08302ee 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -60,6 +60,7 @@ GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs GLOBAL_LIST_EMPTY(bots_list) GLOBAL_LIST_EMPTY(camera_eyes) GLOBAL_LIST_EMPTY(suit_sensors_list) //all people with suit sensors on +GLOBAL_LIST_EMPTY(nanite_sensors_list) //app people with nanite monitoring program // BUBBER EDIT ADDITION /// All alive mobs with clients. GLOBAL_LIST_EMPTY(alive_player_list) diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm index 937c2e3b1d4..2beec1f1641 100644 --- a/code/controllers/subsystem/research.dm +++ b/code/controllers/subsystem/research.dm @@ -40,7 +40,7 @@ SUBSYSTEM_DEF(research) ) var/list/errored_datums = list() ///Associated list of all point types that techwebs will have and their respective 'abbreviated' name. - var/list/point_types = list(TECHWEB_POINT_TYPE_GENERIC = "Gen. Res.") + var/list/point_types = list(TECHWEB_POINT_TYPE_GENERIC = "Gen. Res.", TECHWEB_POINT_TYPE_NANITE = "Nanite Res.") // BUBBER EDIT - NANITES //---------------------------------------------- var/list/single_server_income = list( TECHWEB_POINT_TYPE_GENERIC = TECHWEB_SINGLE_SERVER_INCOME, diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 55bafe9d152..34e47b5d654 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -18,7 +18,7 @@ /datum/atom_hud/data /datum/atom_hud/data/human/medical - hud_icons = list(STATUS_HUD, HEALTH_HUD, DNR_HUD) // SKYRAT EDIT ADDITION - DNR_HUD + hud_icons = list(STATUS_HUD, HEALTH_HUD, DNR_HUD, NANITE_HUD) // BUBBER EDIT ADDITION - DNR-HUD / NANITE_HUD /datum/atom_hud/data/human/medical/basic @@ -51,13 +51,13 @@ hud_icons = list(ID_HUD) /datum/atom_hud/data/human/security/advanced - hud_icons = list(ID_HUD, IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD, WANTED_HUD, PERMIT_HUD, DNR_HUD) //SKYRAT EDIT ADDITION - PERMIT_HUD, DNR_HUD + hud_icons = list(ID_HUD, IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD, WANTED_HUD, PERMIT_HUD, DNR_HUD, NANITE_HUD) // BUBBER EDIT ADDITION - DNR-HUD / NANITE_HUD /datum/atom_hud/data/human/fan_hud hud_icons = list(FAN_HUD) /datum/atom_hud/data/diagnostic - hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_CAMERA_HUD, DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD) + hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_CAMERA_HUD, DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, DIAG_NANITE_FULL_HUD) // BUBBER EDIT ADDITION - NANITE_HUD /datum/atom_hud/data/bot_path hud_icons = list(DIAG_PATH_HUD) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index c568c5a052a..46f6b407967 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -208,9 +208,9 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) return data_by_z["[z]"] var/list/results = list() - for(var/tracked_mob in GLOB.suit_sensors_list) + for(var/tracked_mob in GLOB.suit_sensors_list | GLOB.nanite_sensors_list) // BUBBER CHANGE - NANITES if(!tracked_mob) - stack_trace("Null entry in suit sensors list.") + stack_trace("Null entry in suit sensors or nanite sensors list.") // BUBBER CHANGE - NANITES continue var/mob/living/tracked_living_mob = tracked_mob @@ -227,25 +227,33 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) if(pos.z != z && (!is_station_level(pos.z) || !is_station_level(z)) && !HAS_TRAIT(tracked_living_mob, TRAIT_MULTIZ_SUIT_SENSORS)) continue + var/sensor_mode // BUBBER ADDITION - NANITES var/mob/living/carbon/human/tracked_human = tracked_living_mob - // Check their humanity. + // Set sensor level based on whether we're in the nanites list or the suit sensor list. + if(tracked_living_mob in GLOB.nanite_sensors_list) // BUBBER CHANGE - NANITES + sensor_mode = SENSOR_COORDS + if(!ishuman(tracked_human)) stack_trace("Non-human mob is in suit_sensors_list: [tracked_living_mob] ([tracked_living_mob.type])") continue + // BUBBER CHANGE START - NANITES // Check they have a uniform var/obj/item/clothing/under/uniform = tracked_human.w_uniform - if (!istype(uniform)) + if (!sensor_mode && istype(uniform)) + // Check if their uniform is in a compatible mode. + if((uniform.has_sensor == NO_SENSORS) || !uniform.sensor_mode) + stack_trace("Human without active suit sensors is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])") + continue + + sensor_mode = uniform.sensor_mode + // BUBBER CHANGE END - NANITES + else stack_trace("Human without a suit sensors compatible uniform is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform?.type])") continue - // Check if their uniform is in a compatible mode. - if((uniform.has_sensor == NO_SENSORS) || !uniform.sensor_mode) - stack_trace("Human without active suit sensors is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])") - continue - var/sensor_mode = uniform.sensor_mode // The entry for this human var/list/entry = list( @@ -262,7 +270,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) var/trim_assignment = id_card.get_trim_assignment() if (jobs[trim_assignment] != null) entry["ijob"] = jobs[trim_assignment] - + // SKYRAT EDIT BEGIN: Checking for robotic race if (issynthetic(tracked_human)) entry["is_robot"] = TRUE @@ -285,10 +293,9 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) // If sensors are above living tracking, set DNR state if (sensor_mode >= SENSOR_LIVING) entry["is_dnr"] = tracked_human.get_dnr() - // BUBBERSTATION EDIT END // Broken sensors show garbage data - if (uniform.has_sensor == BROKEN_SENSORS) + if (uniform?.has_sensor == BROKEN_SENSORS) entry["life_status"] = rand(0,1) entry["area"] = pick_list (ION_FILE, "ionarea") entry["oxydam"] = rand(0,175) diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 69a58223899..a3eea0e3523 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -436,6 +436,7 @@ . = jointext(render_list, "") if(tochat) to_chat(user, custom_boxed_message("blue_box", .), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) + SEND_SIGNAL(target, COMSIG_NANITE_SCAN, user, FALSE) // BUBBER EDIT ADDITION - NANITES return . /obj/item/healthanalyzer/click_ctrl_shift(mob/user) diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm index 878fd0ad3bb..3b877393031 100644 --- a/code/game/objects/items/pinpointer.dm +++ b/code/game/objects/items/pinpointer.dm @@ -105,6 +105,8 @@ var/turf/here = get_turf(src) var/turf/there = get_turf(H) if(here && there && (there.z == here.z || (is_station_level(here.z) && is_station_level(there.z)))) // Device and target should be on the same level or different levels of the same station + if (H in GLOB.nanite_sensors_list) // BUBBER ADDITION START - NANITES + return TRUE if (istype(H.w_uniform, /obj/item/clothing/under)) var/obj/item/clothing/under/U = H.w_uniform if(U.has_sensor && (U.sensor_mode >= SENSOR_COORDS || ignore_suit_sensor_level)) // Suit sensors must be on maximum or a contractor pinpointer diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index e3840198665..75c5176c844 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -31,6 +31,7 @@ ADMIN_VERB(investigate_show, R_NONE, "Investigate", "Browse various detailed log INVESTIGATE_RECORDS, INVESTIGATE_RESEARCH, INVESTIGATE_WIRES, + INVESTIGATE_NANITES, // BUBBER ADDITION - NANITES ) var/list/logs_present = list("notes, memos, watchlist") diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 821c8167368..c0234006bb1 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -177,6 +177,13 @@ Des: Removes all infected images from the alien. if(istype(melting_pot) && istype(frying_pan)) for (var/atom/movable/poor_sod as anything in melting_pot.stomach_contents) frying_pan.consume_thing(poor_sod) + // BUBBER ADDITION START - NANITES + var/datum/component/nanites/nanites = GetComponent(/datum/component/nanites) + if(nanites) + new_xeno.AddComponent(/datum/component/nanites, nanites.nanite_volume) + SEND_SIGNAL(new_xeno, COMSIG_NANITE_SYNC, nanites) + // BUBBER ADDITION END - NANITES + qdel(src) /// Changes the name of the xeno we are evolving into in order to keep the same numerical identifier the old xeno had. diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index ca6fea58393..30b37dea0ab 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -2,7 +2,7 @@ blood_volume = BLOOD_VOLUME_NORMAL gender = MALE pressure_resistance = 15 - hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD, DNR_HUD) // SKYRAT EDIT ADDITION - DNR ICON + hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,DNR_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) // BUBBER EDIT ADDITION - DNR_HUD / NANITE_HUD has_limbs = TRUE held_items = list(null, null) num_legs = 0 //Populated on init through list/bodyparts diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 3346a07513c..023ecb8801f 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -5,7 +5,7 @@ icon = 'icons/mob/human/human.dmi' icon_state = "human_basic" appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE - hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPSEC_FIRST_HUD,IMPSEC_SECOND_HUD,ANTAG_HUD,GLAND_HUD,FAN_HUD,PERMIT_HUD, DNR_HUD) //SKYRAT EDIT ADDITION - PERMIT_HUD, DNR_HUD + hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPSEC_FIRST_HUD,IMPSEC_SECOND_HUD,ANTAG_HUD,GLAND_HUD,FAN_HUD,PERMIT_HUD,DNR_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) //BUBBER EDIT ADDITION - PERMIT_HUD, DNR_HUD hud_type = /datum/hud/human pressure_resistance = 25 buckle_lying = 0 diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 23514ef63ff..6ce75f45737 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -320,6 +320,14 @@ spare.domutcheck() spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST))) + // BUBBER ADDITION START - NANITES + var/datum/component/nanites/owner_nanites = H.GetComponent(/datum/component/nanites) + if(owner_nanites) + //copying over nanite programs/cloud sync with 50% saturation in host and spare + owner_nanites.nanite_volume *= 0.5 + spare.AddComponent(/datum/component/nanites, owner_nanites.nanite_volume) + SEND_SIGNAL(spare, COMSIG_NANITE_SYNC, owner_nanites, TRUE, TRUE) //The trues are to copy activation as well + // BUBBER ADDITION END - NANITES H.blood_volume *= 0.45 REMOVE_TRAIT(H, TRAIT_NO_TRANSFORM, REF(src)) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 7f87af20d32..302dacb8bb0 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -39,6 +39,9 @@ if(!forced) damage_amount *= ((100 - blocked) / 100) damage_amount *= get_incoming_damage_modifier(damage_amount, damagetype, def_zone, sharpness, attack_direction, attacking_item) + + SEND_SIGNAL(src, COMSIG_MOB_ALWAYS_APPLY_DAMAGE, damage_amount, damagetype, def_zone, blocked, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item, wound_clothing) // BUBBER ADDITION: FLAT DAMAGE MODIFIERS + if(damage_amount <= 0) return 0 diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 811c86c082a..25cf6e26dbe 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -1,6 +1,6 @@ /mob/living see_invisible = SEE_INVISIBLE_LIVING - hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD, DNR_HUD) // SKYRAT EDIT ADDITION - DNR_HUD + hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,DNR_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) // BUBBER EDIT ADDITION - DNR_HUD / NANITE_HUD pressure_resistance = 10 hud_type = /datum/hud/living interaction_flags_click = ALLOW_RESTING diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm index 33dcd95e86b..77b376ba900 100644 --- a/code/modules/modular_computers/file_system/programs/radar.dm +++ b/code/modules/modular_computers/file_system/programs/radar.dm @@ -269,6 +269,8 @@ return . if(!istype(humanoid)) return RADAR_NOT_TRACKABLE + if (humanoid in GLOB.nanite_sensors_list) // BUBBER ADDITION - NANITES + return TRUE if(!istype(humanoid.w_uniform, /obj/item/clothing/under)) return RADAR_NOT_TRACKABLE var/obj/item/clothing/under/uniform = humanoid.w_uniform diff --git a/icons/obj/machines/computer.dmi b/icons/obj/machines/computer.dmi index 34f632044c162196f053257f9a0f68bd02a7aeb2..7dad1157cbb4143f53b75fc7af20188b68adb439 100644 GIT binary patch literal 137966 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
    7#ln&nkCZ_S{{&LAns-vrr{3h$pU9u=Q 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 IxbyhG072=PF8}}l literal 138564 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 next_sync) + cloud_sync() + next_sync = world.time + NANITE_SYNC_DELAY + set_nanite_bar() + +///Deletes nanites! +/datum/component/nanites/proc/delete_nanites() + SIGNAL_HANDLER + qdel(src) + +///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/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE) + SIGNAL_HANDLER + + 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(null, SNP.copy()) + +///Syncs the nanites to their assigned cloud copy, if it is available. If it is not, there is a small chance of a software error instead. +/datum/component/nanites/proc/cloud_sync() + if(cloud_id) + var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id) + if(backup) + connect_techweb(backup.techweb) + var/datum/component/nanites/cloud_copy = backup.nanites + if(cloud_copy) + sync(null, cloud_copy) + return + //Without cloud syncing nanites can accumulate errors and/or defects + if(prob(8) && programs.len) + var/datum/nanite_program/NP = pick(programs) + NP.software_error() +// todo test this +/datum/component/nanites/proc/add_design(datum/techweb/web, datum/design/design, custom = FALSE) + SIGNAL_HANDLER + if(design.id == "nanite_harmonic") + harmonic_regenerating = TRUE + +/datum/component/nanites/proc/remove_design(datum/techweb/web, datum/design/design, custom = FALSE) + SIGNAL_HANDLER + if(design.id == "nanite_harmonic") + harmonic_regenerating = FALSE + +/datum/component/nanites/proc/connect_techweb(datum/techweb/new_web) + if(!new_web || new_web == techweb) + return + if(techweb) + disconnect_techweb() + techweb = new_web + var/list/all_nodes = techweb.get_researched_nodes() + harmonic_regenerating = !!all_nodes["nanite_harmonic"] + RegisterSignal(techweb, COMSIG_TECHWEB_ADD_DESIGN, .proc/add_design) + RegisterSignal(techweb, COMSIG_TECHWEB_REMOVE_DESIGN, .proc/remove_design) + +/datum/component/nanites/proc/disconnect_techweb() + if(!techweb) + return + UnregisterSignal(techweb, COMSIG_TECHWEB_ADD_DESIGN) + UnregisterSignal(techweb, COMSIG_TECHWEB_REMOVE_DESIGN) + techweb = null + +///Adds a nanite program, replacing existing unique programs of the same type. A source program can be specified to copy its programming onto the new one. +/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program) + SIGNAL_HANDLER + + 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(null, -amount) + return (nanite_volume > 0) + +///Modifies the current nanite volume, then checks if the nanites are depleted or exceeding the maximum amount +/datum/component/nanites/proc/adjust_nanites(datum/source, amount) + SIGNAL_HANDLER + + nanite_volume += amount + if(nanite_volume > max_nanites) + reject_excess_nanites() + if(nanite_volume <= 0) //oops we ran out + qdel(src) + +/** + * Handles how nanites leave the host's body if they find out that they're currently exceeding the maximum supported amount + * + * IC explanation: + * Normally nanites simply discard excess volume by slowing replication or 'sweating' it out in imperceptible amounts, + * but if there is a large excess volume, likely due to a programming change that leaves them unable to support their current volume, + * the nanites attempt to leave the host as fast as necessary to prevent nanite poisoning. This can range from minor oozing to nanites + * rapidly bursting out from every possible pathway, causing temporary inconvenience to the host. + */ +/datum/component/nanites/proc/reject_excess_nanites() + var/excess = nanite_volume - max_nanites + nanite_volume = max_nanites + + switch(excess) + if(0 to NANITE_EXCESS_MINOR) //Minor excess amount, the extra nanites are quietly expelled without visible effects + return + if((NANITE_EXCESS_MINOR + 0.1) to NANITE_EXCESS_VOMIT) //Enough nanites getting rejected at once to be visible to the naked eye + host_mob.visible_message(span_warning("A grainy grey slurry starts oozing out of [host_mob]."), span_warning("A grainy grey slurry starts oozing out of your skin."), null, 4); + if((NANITE_EXCESS_VOMIT + 0.1) to NANITE_EXCESS_BURST) //Nanites getting rejected in massive amounts, but still enough to make a semi-orderly exit through vomit + if(iscarbon(host_mob)) + var/mob/living/carbon/C = host_mob + host_mob.visible_message(span_warning("[host_mob] vomits a grainy grey slurry!"), span_warning("You suddenly vomit a metallic-tasting grainy grey slurry!"), null); + C.vomit(VOMIT_CATEGORY_NANITE, /obj/effect/decal/cleanable/vomit/nanites, FLOOR(excess / 100, 1)) + else + host_mob.visible_message(span_warning("A metallic grey slurry bursts out of [host_mob]'s skin!"), span_userdanger("A metallic grey slurry violently bursts out of your skin!"), null); + if(isturf(host_mob.drop_location())) + var/turf/T = host_mob.drop_location() + T.add_vomit_floor(host_mob, /obj/effect/decal/cleanable/vomit/nanites, VOMIT_CATEGORY_NANITE, 0) + if((NANITE_EXCESS_BURST + 0.1) to INFINITY) //Way too many nanites, they just leave through the closest exit before they harm/poison the host + host_mob.visible_message(span_warning("A torrent of metallic grey slurry violently bursts out of [host_mob]'s face and floods out of [host_mob.p_their()] skin!"), + span_userdanger("A torrent of metallic grey slurry violently bursts out of your eyes, ears, and mouth, and floods out of your skin!")); + host_mob.adjust_eye_blur_up_to(15, 1 MINUTES) + host_mob.Paralyze(120) + if(iscarbon(host_mob)) + var/mob/living/carbon/carbon = host_mob + var/obj/item/organ/ears/ears = carbon.get_organ_slot(ORGAN_SLOT_EARS) + if(ears) + ears.adjustEarDamage(0, 30) //nanites coming out of your ears + carbon.vomit(VOMIT_CATEGORY_NANITE, /obj/effect/decal/cleanable/vomit/nanites) //nanites coming out of your mouth + + //nanites everywhere + if(isturf(host_mob.drop_location())) + var/turf/T = host_mob.drop_location() + T.add_vomit_floor(host_mob, VOMIT_CATEGORY_NANITE, 0) + for(var/turf/adjacent_turf in oview(host_mob, 1)) + if(adjacent_turf.density || !adjacent_turf.Adjacent(T)) + continue + adjacent_turf.add_vomit_floor(host_mob, /obj/effect/decal/cleanable/vomit/nanites, VOMIT_CATEGORY_NANITE, 0) + +///Updates the nanite volume bar visible in diagnostic HUDs +/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(datum/source, severity) + SIGNAL_HANDLER + + nanite_volume *= (rand(60, 90) * 0.01) //Lose 10-40% of nanites + adjust_nanites(null, -(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(datum/source, shock_damage, siemens_coeff = 1, flags = NONE) + SIGNAL_HANDLER + + if(flags & SHOCK_ILLUSION || shock_damage < 1) + return + + if(!HAS_TRAIT_NOT_FROM(host_mob, TRAIT_SHOCKIMMUNE, "nanites"))//Another shock protection must protect nanites too, but nanites protect only host + nanite_volume *= (rand(45, 80) * 0.01) //Lose 20-55% of nanites + adjust_nanites(null, -(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(datum/source) + SIGNAL_HANDLER + + adjust_nanites(null, -(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/check_stealth(datum/source) + SIGNAL_HANDLER + + return stealth + +/datum/component/nanites/proc/on_death(datum/source, gibbed) + SIGNAL_HANDLER + + for(var/X in programs) + var/datum/nanite_program/NP = X + NP.on_death(gibbed) + +/datum/component/nanites/proc/receive_signal(datum/source, code, source = "an unidentified source") + SIGNAL_HANDLER + + for(var/X in programs) + var/datum/nanite_program/NP = X + NP.receive_signal(code, source) + +/datum/component/nanites/proc/receive_comm_signal(datum/source, comm_code, comm_message, comm_source = "an unidentified source") + SIGNAL_HANDLER + + for(var/X in programs) + if(istype(X, /datum/nanite_program/comm)) + var/datum/nanite_program/comm/NP = X + NP.receive_comm_signal(comm_code, comm_message, comm_source) + +/datum/component/nanites/proc/check_viable_biotype() + SIGNAL_HANDLER + + if(!CAN_HAVE_NANITES(host_mob)) + qdel(src) //bodytype no longer sustains nanites + +/datum/component/nanites/proc/check_access(datum/source, atom/locked_thing) + SIGNAL_HANDLER + var/obj/locked_object = locked_thing + if(!istype(locked_thing)) + return FALSE + for(var/datum/nanite_program/access/access_program in programs) + if(access_program.activated) + return locked_object.check_access_list(access_program.access) + else + return FALSE + return FALSE + +/datum/component/nanites/proc/set_volume(datum/source, amount) + SIGNAL_HANDLER + + nanite_volume = clamp(amount, 0, max_nanites) + +/datum/component/nanites/proc/set_max_volume(datum/source, amount) + SIGNAL_HANDLER + + max_nanites = max(1, amount) + +/datum/component/nanites/proc/set_cloud(datum/source, amount) + SIGNAL_HANDLER + + cloud_id = clamp(amount, 0, 100) + +/datum/component/nanites/proc/set_cloud_sync(datum/source, method) + SIGNAL_HANDLER + + switch(method) + if(NANITE_CLOUD_TOGGLE) + cloud_active = !cloud_active + if(NANITE_CLOUD_DISABLE) + cloud_active = FALSE + if(NANITE_CLOUD_ENABLE) + cloud_active = TRUE + +/datum/component/nanites/proc/set_safety(datum/source, amount) + SIGNAL_HANDLER + + safety_threshold = clamp(amount, 0, max_nanites) + +/datum/component/nanites/proc/set_regen(datum/source, amount) + SIGNAL_HANDLER + + regen_rate = amount + +/datum/component/nanites/proc/confirm_nanites() + SIGNAL_HANDLER + + return TRUE //yup i exist + +/datum/component/nanites/proc/get_programs(datum/source, list/nanite_programs) + SIGNAL_HANDLER + + nanite_programs |= programs + +/datum/component/nanites/proc/add_research() + var/progress_addition = NANITE_BASE_RESEARCH_PROGRESS + if(!techweb) + return + if(!ishuman(host_mob)) + if(!iscarbon(host_mob)) + progress_addition *= 0.4 + else + progress_addition *= 0.8 + if(!host_mob.client) + progress_addition *= 0.5 + if(host_mob.stat == DEAD) + progress_addition *= 0.75 + research_progress += progress_addition + if(research_progress >= 100) + research_progress -= 100 + techweb.add_point_list( + list( + TECHWEB_POINT_TYPE_GENERIC = TECHWEB_SINGLE_SERVER_INCOME, + TECHWEB_POINT_TYPE_NANITE = TECHWEB_SINGLE_SERVER_INCOME + ) + ) + +/datum/component/nanites/proc/nanite_scan(datum/source, mob/user, full_scan) + SIGNAL_HANDLER + + if(!full_scan) + if(!stealth) + to_chat(user, span_notice("Nanites Detected")) + to_chat(user, span_notice("Saturation: [nanite_volume]/[max_nanites]")) + return TRUE + else + to_chat(user, span_info("NANITES DETECTED")) + to_chat(user, span_info("================")) + to_chat(user, span_info("Saturation: [nanite_volume]/[max_nanites]")) + to_chat(user, span_info("Safety Threshold: [safety_threshold]")) + to_chat(user, span_info("Cloud ID: [cloud_id ? cloud_id : "None"]")) + to_chat(user, span_info("Cloud Sync: [cloud_active ? "Active" : "Disabled"]")) + to_chat(user, span_info("================")) + to_chat(user, span_info("Program List:")) + if(!diagnostics) + to_chat(user, span_alert("Nanite debugging disabled.")) + else + for(var/X in programs) + var/datum/nanite_program/NP = X + to_chat(user, span_info("[NP.name] | [NP.activated ? "Active" : "Inactive"]")) + return TRUE + +/datum/component/nanites/proc/get_regen_rate() + return regen_rate + (harmonic_regenerating ? HARMONIC_REGEN_BOOST : 0) + +/datum/component/nanites/proc/nanite_ui_data(datum/source, list/data, scan_level) + SIGNAL_HANDLER + + data["has_nanites"] = TRUE + data["nanite_volume"] = nanite_volume + data["regen_rate"] = get_regen_rate() + data["safety_threshold"] = safety_threshold + data["cloud_id"] = cloud_id + data["cloud_active"] = cloud_active + 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["timer_restart"] = P.timer_restart / 10 + mob_program["timer_shutdown"] = P.timer_shutdown / 10 + mob_program["timer_trigger"] = P.timer_trigger / 10 + mob_program["timer_trigger_delay"] = P.timer_trigger_delay / 10 + var/list/extra_settings = P.get_extra_settings_frontend() + mob_program["extra_settings"] = extra_settings + if(LAZYLEN(extra_settings)) + mob_program["has_extra_settings"] = TRUE + else + mob_program["has_extra_settings"] = FALSE + + 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 + var/list/rules = list() + var/rule_id = 1 + for(var/Z in P.rules) + var/datum/nanite_rule/nanite_rule = Z + var/list/rule = list() + rule["display"] = nanite_rule.display() + rule["program_id"] = id + rule["id"] = rule_id + rules += list(rule) + rule_id++ + mob_program["rules"] = rules + if(LAZYLEN(rules)) + mob_program["has_rules"] = TRUE + id++ + mob_programs += list(mob_program) + data["mob_programs"] = mob_programs + +#undef HARMONIC_REGEN_BOOST diff --git a/modular_zubbers/code/datums/mood_events/nanite_events.dm b/modular_zubbers/code/datums/mood_events/nanite_events.dm new file mode 100644 index 00000000000..ae21bd84f4c --- /dev/null +++ b/modular_zubbers/code/datums/mood_events/nanite_events.dm @@ -0,0 +1,13 @@ +/datum/mood_event/nanite_happiness + description = "+++++++HAPPINESS ENHANCEMENT+++++++\n" + mood_change = 7 + +/datum/mood_event/nanite_happiness/add_effects(message) + description = "+++++++[message]+++++++\n" + +/datum/mood_event/nanite_sadness + description = "+++++++HAPPINESS SUPPRESSION+++++++\n" + mood_change = -7 + +/datum/mood_event/nanite_sadness/add_effects(message) + description = "+++++++[message]+++++++\n" diff --git a/modular_zubbers/code/game/area/nanite.dm b/modular_zubbers/code/game/area/nanite.dm new file mode 100644 index 00000000000..a5ad3943be2 --- /dev/null +++ b/modular_zubbers/code/game/area/nanite.dm @@ -0,0 +1,3 @@ +/area/science/nanite + name = "Nanite Lab" + icon_state = "nanite" diff --git a/modular_zubbers/code/modules/mob/living/carbon/human/physiology.dm b/modular_zubbers/code/modules/mob/living/carbon/human/physiology.dm new file mode 100644 index 00000000000..49497003629 --- /dev/null +++ b/modular_zubbers/code/modules/mob/living/carbon/human/physiology.dm @@ -0,0 +1,28 @@ +/datum/physiology + var/flat_brute_mod = 0 + var/flat_burn_mod = 0 + +/mob/living/carbon/human/apply_damage( + damage, + damagetype, + def_zone, + blocked, + forced, + spread_damage, + wound_bonus, + bare_wound_bonus, + sharpness, + attack_direction, + attacking_item, + wound_clothing + ) + if(!physiology) + return ..() + + switch(damagetype) + if(BRUTE) + damage += physiology.flat_brute_mod + if(BURN) + damage += physiology.flat_burn_mod + + . = ..() diff --git a/modular_zubbers/code/modules/nanites/designs.dm b/modular_zubbers/code/modules/nanites/designs.dm new file mode 100644 index 00000000000..72d46247ef9 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/designs.dm @@ -0,0 +1,91 @@ +/datum/design/nanite_disk + name = "Nanite Program Disk" + desc = "Stores nanite programs." + id = "nanite_disk" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = 300, /datum/material/glass = 100) + build_path = /obj/item/disk/nanite_program + category = list("Electronics") + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/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 = DEPARTMENT_BITFLAG_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 = DEPARTMENT_BITFLAG_SCIENCE + +/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 = DEPARTMENT_BITFLAG_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 = DEPARTMENT_BITFLAG_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 = DEPARTMENT_BITFLAG_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 = DEPARTMENT_BITFLAG_SCIENCE + +/////////////////////////////////// +//////////Nanite Devices/////////// +/////////////////////////////////// +/datum/design/nanite_remote + name = "Nanite Remote" + desc = "Allows for the construction of a nanite remote." + id = "nanite_remote" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/glass = 500, /datum/material/iron = 500) + build_path = /obj/item/nanite_remote + category = list("Electronics") + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/nanite_comm_remote + name = "Nanite Communication Remote" + desc = "Allows for the construction of a nanite communication remote." + id = "nanite_comm_remote" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/glass = 500, /datum/material/iron = 500) + build_path = /obj/item/nanite_remote/comm + category = list("Electronics") + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/nanite_scanner + name = "Nanite Scanner" + desc = "Allows for the construction of a nanite scanner." + id = "nanite_scanner" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/glass = 500, /datum/material/iron = 500) + build_path = /obj/item/nanite_scanner + category = list("Electronics") + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + diff --git a/modular_zubbers/code/modules/nanites/extra_settings/_extra_setting.dm b/modular_zubbers/code/modules/nanites/extra_settings/_extra_setting.dm new file mode 100644 index 00000000000..b3bef77eb40 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/extra_settings/_extra_setting.dm @@ -0,0 +1,20 @@ +/datum/nanite_extra_setting + var/setting_type + var/value + +/datum/nanite_extra_setting/proc/get_value() + return value + +/datum/nanite_extra_setting/proc/set_value(value) + src.value = value + +/datum/nanite_extra_setting/proc/get_copy() + return + +//I made the choice to send the name as part of the parameter instead of storing it directly on +//this datum as a way of avoiding duplication of data between the containing assoc list +//and this datum. +//Also make sure to double wrap the list when implementing this as +//+= is interpreted as a combine on lists, so the outer list gets unwrapped +/datum/nanite_extra_setting/proc/get_frontend_list(name) + return diff --git a/modular_zubbers/code/modules/nanites/extra_settings/boolean.dm b/modular_zubbers/code/modules/nanites/extra_settings/boolean.dm new file mode 100644 index 00000000000..7d66eb988ea --- /dev/null +++ b/modular_zubbers/code/modules/nanites/extra_settings/boolean.dm @@ -0,0 +1,27 @@ +/datum/nanite_extra_setting/boolean + setting_type = NESTYPE_BOOLEAN + var/true_text + var/false_text + +/datum/nanite_extra_setting/boolean/New(initial, true_text, false_text) + value = initial + src.true_text = true_text + src.false_text = false_text + +/datum/nanite_extra_setting/boolean/set_value(value) + if(isnull(value)) + src.value = !src.value + return + . = ..() + +/datum/nanite_extra_setting/boolean/get_copy() + return new /datum/nanite_extra_setting/boolean(value, true_text, false_text) + +/datum/nanite_extra_setting/boolean/get_frontend_list(name) + return list(list( + "name" = name, + "type" = setting_type, + "value" = value, + "true_text" = true_text, + "false_text" = false_text + )) diff --git a/modular_zubbers/code/modules/nanites/extra_settings/number.dm b/modular_zubbers/code/modules/nanites/extra_settings/number.dm new file mode 100644 index 00000000000..75489635f55 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/extra_settings/number.dm @@ -0,0 +1,32 @@ +/datum/nanite_extra_setting/number + setting_type = NESTYPE_NUMBER + var/min + var/max + var/unit = "" + +/datum/nanite_extra_setting/number/New(initial, min, max, unit) + value = initial + src.min = min + src.max = max + if(unit) + src.unit = unit + +/datum/nanite_extra_setting/number/set_value(value) + if(istext(value)) + value = text2num(value) + if(!value || !isnum(value)) + return + src.value = clamp(value, min, max) + +/datum/nanite_extra_setting/number/get_copy() + return new /datum/nanite_extra_setting/number(value, min, max, unit) + +/datum/nanite_extra_setting/number/get_frontend_list(name) + return list(list( + "name" = name, + "type" = setting_type, + "value" = value, + "min" = min, + "max" = max, + "unit" = unit + )) diff --git a/modular_zubbers/code/modules/nanites/extra_settings/text.dm b/modular_zubbers/code/modules/nanites/extra_settings/text.dm new file mode 100644 index 00000000000..d3cad27bcf5 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/extra_settings/text.dm @@ -0,0 +1,21 @@ +/datum/nanite_extra_setting/text + setting_type = NESTYPE_TEXT + +/datum/nanite_extra_setting/text/New(initial) + value = initial + +/datum/nanite_extra_setting/text/set_value(value) + src.value = trim(value) + +/datum/nanite_extra_setting/text/get_copy() + return new /datum/nanite_extra_setting/text(value) + +/datum/nanite_extra_setting/text/get_value() + return html_encode(value) + +/datum/nanite_extra_setting/text/get_frontend_list(name) + return list(list( + "name" = name, + "type" = setting_type, + "value" = value + )) diff --git a/modular_zubbers/code/modules/nanites/extra_settings/type.dm b/modular_zubbers/code/modules/nanites/extra_settings/type.dm new file mode 100644 index 00000000000..2085ba510c4 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/extra_settings/type.dm @@ -0,0 +1,18 @@ +/datum/nanite_extra_setting/type + setting_type = NESTYPE_TYPE + var/list/types + +/datum/nanite_extra_setting/type/New(initial, types) + value = initial + src.types = types + +/datum/nanite_extra_setting/type/get_copy() + return new /datum/nanite_extra_setting/type(value, types) + +/datum/nanite_extra_setting/type/get_frontend_list(name) + return list(list( + "name" = name, + "type" = setting_type, + "value" = value, + "types" = types + )) diff --git a/modular_zubbers/code/modules/nanites/items/boards.dm b/modular_zubbers/code/modules/nanites/items/boards.dm new file mode 100644 index 00000000000..154dec071c3 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/items/boards.dm @@ -0,0 +1,58 @@ +/obj/item/circuitboard/machine/nanite_chamber + name = "Nanite Chamber (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + 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/servo = 1 + ) + +/obj/item/circuitboard/machine/nanite_program_hub + name = "Nanite Program Hub (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/nanite_program_hub + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/servo = 1) + +/obj/item/circuitboard/machine/nanite_programmer + name = "Nanite Programmer (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/nanite_programmer + req_components = list( + /obj/item/stock_parts/servo = 2, + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/scanning_module = 1 + ) + +/obj/item/circuitboard/machine/public_nanite_chamber + name = "Public Nanite Chamber (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/public_nanite_chamber + req_components = list( + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/servo = 1 + ) + var/cloud_id = 1 + +/obj/item/circuitboard/machine/public_nanite_chamber/multitool_act(mob/living/user) + . = ..() + var/new_cloud = tgui_input_number(user, "Set the public nanite chamber's Cloud ID (1-100).", "Cloud ID", cloud_id, 100, 1, 0,) + if(!isnum(new_cloud)) + return + cloud_id = clamp(round(new_cloud, 1), 1, 100) + +/obj/item/circuitboard/machine/public_nanite_chamber/examine(mob/user) + . = ..() + . += "Cloud ID is currently set to [cloud_id]." + +/obj/item/circuitboard/computer/nanite_chamber_control + name = "Nanite Chamber Control (Computer Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/computer/nanite_chamber_control + +/obj/item/circuitboard/computer/nanite_cloud_controller + name = "Nanite Cloud Control (Computer Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/computer/nanite_cloud_controller diff --git a/modular_zubbers/code/modules/nanites/items/items.dm b/modular_zubbers/code/modules/nanites/items/items.dm new file mode 100644 index 00000000000..d70fa243725 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/items/items.dm @@ -0,0 +1,47 @@ +/obj/item/nanite_scanner + name = "nanite scanner" + icon = 'modular_zubbers/icons/obj/devices/nanite_devices.dmi' + icon_state = "nanite_scanner" + inhand_icon_state = "electronic" + worn_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + desc = "A hand-held body scanner able to detect nanites and their programming." + obj_flags = CONDUCTS_ELECTRICITY + item_flags = NOBLUDGEON + slot_flags = ITEM_SLOT_BELT + throwforce = 3 + w_class = WEIGHT_CLASS_TINY + throw_speed = 3 + throw_range = 7 + custom_materials = list(/datum/material/iron=200) + +/obj/item/nanite_scanner/attack(mob/living/M, mob/living/carbon/human/user) + user.visible_message( + span_notice("[user] analyzes [M]'s nanites."), + span_notice("You analyze [M]'s nanites.") + ) + + add_fingerprint(user) + + var/response = SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, TRUE) + if(!response) + to_chat(user, span_info("No nanites detected in the subject.")) + +/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) + +/obj/item/nanite_injector + name = "nanite injector" + desc = "Injects nanites into the user." + w_class = WEIGHT_CLASS_SMALL + icon = 'modular_zubbers/icons/obj/devices/nanite_devices.dmi' + icon_state = "nanite_remote" + +/obj/item/nanite_injector/attack_self(mob/user) + user.AddComponent(/datum/component/nanites, 150) diff --git a/modular_zubbers/code/modules/nanites/items/program_disks.dm b/modular_zubbers/code/modules/nanites/items/program_disks.dm new file mode 100644 index 00000000000..efa6e6ad15f --- /dev/null +++ b/modular_zubbers/code/modules/nanites/items/program_disks.dm @@ -0,0 +1,147 @@ + +/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(mapload) + . = ..() + if(program_type) + program = new program_type + update_name() + +/obj/item/disk/nanite_program/update_name() + . = ..() + if(!program) + return + name = "[initial(name)] \[[program.name]\]" + +/obj/item/disk/nanite_program/debugging + program_type = /datum/nanite_program/nanite_debugging + +/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/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/repairing + program_type = /datum/nanite_program/regenerative/robotic + +/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/defib + program_type = /datum/nanite_program/defib + +/obj/item/disk/nanite_program/nervous + program_type = /datum/nanite_program/nervous + +/obj/item/disk/nanite_program/hardening + program_type = /datum/nanite_program/dermal_armor + +/obj/item/disk/nanite_program/refractive + program_type = /datum/nanite_program/dermal_armor/refractive + +/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/heart_stop + +/obj/item/disk/nanite_program/explosive + program_type = /datum/nanite_program/explosive + +/obj/item/disk/nanite_program/shock + program_type = /datum/nanite_program/shocking + +/obj/item/disk/nanite_program/sleepy + program_type = /datum/nanite_program/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/conductive + program_type = /datum/nanite_program/pacifying + +/obj/item/disk/nanite_program/stun + program_type = /datum/nanite_program/stun + +/obj/item/disk/nanite_program/sting + program_type = /datum/nanite_program/nanite_sting diff --git a/modular_zubbers/code/modules/nanites/items/remote.dm b/modular_zubbers/code/modules/nanites/items/remote.dm new file mode 100644 index 00000000000..8ed634cb7cf --- /dev/null +++ b/modular_zubbers/code/modules/nanites/items/remote.dm @@ -0,0 +1,247 @@ +#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 = 'modular_zubbers/icons/obj/devices/nanite_devices.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 + var/current_program_name = "Program" + +/obj/item/nanite_remote/examine(mob/user) + . = ..() + if(locked) + . += span_notice("Alt-click to unlock.") + +/obj/item/nanite_remote/click_alt(mob/user) + . = ..() + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return + if(locked) + if(allowed(user)) + to_chat(user, span_notice("You unlock [src].")) + locked = FALSE + update_appearance() + else + to_chat(user, span_warning("Access denied.")) + +/obj/item/nanite_remote/emag_act(mob/user) + if(obj_flags & EMAGGED) + return + to_chat(user, span_warning("You override [src]'s ID lock.")) + obj_flags |= EMAGGED + if(locked) + locked = FALSE + update_appearance() + +/obj/item/nanite_remote/update_overlays() + . = ..() + if(obj_flags & EMAGGED) + . += "nanite_remote_emagged" + if(locked) + . += "nanite_remote_locked" + +/obj/item/nanite_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + return trigger_nanites(interacting_with, user, modifiers) + +/obj/item/nanite_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + return trigger_nanites(interacting_with, user, modifiers) + +/obj/item/nanite_remote/proc/trigger_nanites(atom/interacting_with, mob/living/user, list/modifiers) + switch(mode) + if(REMOTE_MODE_SELF) + to_chat(user, span_notice("You activate [src], signaling the nanites in your bloodstream.")) + signal_mob(user, code, key_name(user)) + return ITEM_INTERACT_SUCCESS + if(REMOTE_MODE_TARGET) + if(!istype(interacting_with, /mob/living)) + return NONE + if(isliving(interacting_with) && (get_dist(interacting_with, get_turf(src)) <= 7)) + to_chat(user, span_notice("You activate [src], signaling the nanites inside [interacting_with].")) + signal_mob(interacting_with, code, key_name(user)) + return ITEM_INTERACT_SUCCESS + if(REMOTE_MODE_AOE) + to_chat(user, span_notice("You activate [src], signaling the nanites inside every host around you.")) + for(var/mob/living/L in view(user, 7)) + signal_mob(L, code, key_name(user)) + return ITEM_INTERACT_SUCCESS + if(REMOTE_MODE_RELAY) + to_chat(user, span_notice("You activate [src], signaling all connected relay nanites.")) + signal_relay(code, relay_code, key_name(user)) + return ITEM_INTERACT_SUCCESS + return NONE + +/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_state(mob/user) + return GLOB.hands_state + +/obj/item/nanite_remote/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NaniteRemote", name) + 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 + data["program_name"] = current_program_name + return data + +/obj/item/nanite_remote/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("set_code") + if(locked) + return + var/new_code = text2num(params["code"]) + 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 = text2num(params["code"]) + if(!isnull(new_code)) + new_code = clamp(round(new_code, 1),0,9999) + relay_code = new_code + . = TRUE + if("update_name") + current_program_name = params["name"] + . = TRUE + if("save") + if(locked) + return + var/new_save = list() + new_save["id"] = last_id + 1 + last_id++ + new_save["name"] = current_program_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_appearance() + . = TRUE + + +/obj/item/nanite_remote/comm + name = "nanite communication remote" + desc = "A device that can send text messages to specific programs." + icon_state = "nanite_comm_remote" + var/comm_message = "" + +/obj/item/nanite_remote/comm/afterattack(atom/target, mob/user, etc) + switch(mode) + if(REMOTE_MODE_OFF) + return + if(REMOTE_MODE_SELF) + to_chat(user, span_notice("You activate [src], signaling the nanites in your bloodstream.")) + 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_notice("You activate [src], signaling the nanites inside [target].")) + signal_mob(target, code, key_name(user)) + if(REMOTE_MODE_AOE) + to_chat(user, span_notice("You activate [src], signaling the nanites inside every host around you.")) + for(var/mob/living/L in view(user, 7)) + signal_mob(L, code, key_name(user)) + if(REMOTE_MODE_RELAY) + to_chat(user, span_notice("You activate [src], signaling all connected relay nanites.")) + signal_relay(code, relay_code, key_name(user)) + +/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source) + SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, code, comm_message, source) + +/obj/item/nanite_remote/comm/signal_relay(code, relay_code, source) + for(var/X in SSnanites.nanite_relays) + var/datum/nanite_program/relay/N = X + N.relay_comm_signal(code, relay_code, comm_message) + +/obj/item/nanite_remote/comm/ui_data() + var/list/data = list() + data["comms"] = TRUE + data["code"] = code + data["relay_code"] = relay_code + data["message"] = comm_message + data["mode"] = mode + data["locked"] = locked + data["saved_settings"] = saved_settings + data["program_name"] = current_program_name + + return data + +/obj/item/nanite_remote/comm/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("set_message") + if(locked) + return + var/new_message = html_encode(params["value"]) + if(!new_message) + return + comm_message = new_message + . = TRUE + +#undef REMOTE_MODE_OFF +#undef REMOTE_MODE_SELF +#undef REMOTE_MODE_TARGET +#undef REMOTE_MODE_AOE +#undef REMOTE_MODE_RELAY diff --git a/modular_zubbers/code/modules/nanites/living.dm b/modular_zubbers/code/modules/nanites/living.dm new file mode 100644 index 00000000000..3e16ae76ed6 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/living.dm @@ -0,0 +1,7 @@ +/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(HAS_TRAIT(src, TRAIT_NANITE_MONITORING)) + holder.icon_state = "nanite_ping" diff --git a/modular_zubbers/code/modules/nanites/machines/nanite_chamber.dm b/modular_zubbers/code/modules/nanites/machines/nanite_chamber.dm new file mode 100644 index 00000000000..63e425dbcc1 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/nanite_chamber.dm @@ -0,0 +1,213 @@ +/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/bci_implanter.dmi' + icon_state = "bci_implanter" + base_icon_state = "bci_implanter" + layer = ABOVE_WINDOW_LAYER + use_power = IDLE_POWER_USE + anchored = TRUE + density = TRUE + idle_power_usage = 50 + active_power_usage = 300 + + 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/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + occupant_typecache = GLOB.typecache_living + +/obj/machinery/nanite_chamber/RefreshParts() + . = ..() + scan_level = 0 + for(var/datum/stock_part/P in component_parts) + scan_level += P.tier + +/obj/machinery/nanite_chamber/examine(mob/user) + . = ..() + if(in_range(user, src) || isobserver(user)) + . += span_notice("The status display reads: Scanning module has been upgraded to level [scan_level].") + +/obj/machinery/nanite_chamber/proc/set_busy(status, message, working_icon) + busy = status + busy_message = message + busy_icon_state = working_icon + update_appearance() + +/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(machine_stat & (NOPOWER|BROKEN)) + return + if((machine_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/remove_nanites(datum/nanite_program/NP) + if(machine_stat & (NOPOWER|BROKEN)) + return + if((machine_stat & MAINT) || panel_open) + return + if(!occupant || busy) + return + + var/locked_state = locked + locked = TRUE + + //TODO OMINOUS MACHINE SOUNDS + set_busy(TRUE, "Initializing cleanup 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, "Pinging nanites...", "[initial(icon_state)]_active"),40) + addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Initiating graceful self-destruct sequence...", "[initial(icon_state)]_active"),70) + addtimer(CALLBACK(src, .proc/set_busy, TRUE, "Removing debris...", "[initial(icon_state)]_falling"),110) + addtimer(CALLBACK(src, .proc/complete_removal, locked_state),130) + +/obj/machinery/nanite_chamber/proc/complete_removal(locked_state) + //TODO MACHINE DING + locked = locked_state + set_busy(FALSE) + if(!occupant) + return + SEND_SIGNAL(occupant, COMSIG_NANITE_DELETE) + +/obj/machinery/nanite_chamber/update_icon_state() + //running and someone in there + if(occupant) + icon_state = busy ? busy_icon_state : "[base_icon_state]_occupied" + return ..() + //running + icon_state = "[base_icon_state][state_open ? "_open" : null]" + return ..() + +/obj/machinery/nanite_chamber/update_overlays() + . = ..() + + if((machine_stat & MAINT) || panel_open) + . += "maint" + return + + if(machine_stat & (NOPOWER|BROKEN)) + return + + if(busy || locked) + . += "red" + if(locked) + . += "bolted" + return + + . += "green" + +/obj/machinery/nanite_chamber/proc/toggle_open(mob/user) + if(panel_open) + to_chat(user, span_notice("Close the maintenance panel first.")) + return + + if(state_open) + close_machine() + return + + else if(locked) + to_chat(user, span_notice("The bolts are locked down, securing the door shut.")) + return + + open_machine() + +/obj/machinery/nanite_chamber/container_resist_act(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_notice("You see [user] kicking against the door of [src]!"), \ + span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \ + span_hear("You hear a metallic creaking from [src].")) + 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_warning("[user] successfully broke out of [src]!"), \ + span_notice("You successfully break out of [src]!")) + open_machine() + +/obj/machinery/nanite_chamber/close_machine(mob/living/carbon/user, density_to_set = TRUE) + if(!state_open) + return FALSE + + ..(user) + return TRUE + +/obj/machinery/nanite_chamber/open_machine(drop = TRUE, density_to_set = FALSE) + if(state_open) + return FALSE + + ..() + + return TRUE + +/obj/machinery/nanite_chamber/relaymove(mob/living/user, direction) + if(user.stat || locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, span_warning("[src]'s door won't budge!")) + 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_appearance()//..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/mouse_drop_receive(atom/target, mob/user, params) + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH|SILENT_ADJACENCY) || !iscarbon(target)) + return + if(close_machine(target)) + log_combat(user, target, "inserted", null, "into [src].") + add_fingerprint(user) diff --git a/modular_zubbers/code/modules/nanites/machines/nanite_chamber_computer.dm b/modular_zubbers/code/modules/nanites/machines/nanite_chamber_computer.dm new file mode 100644 index 00000000000..edec4df1511 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/nanite_chamber_computer.dm @@ -0,0 +1,109 @@ +/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." + icon_screen = "nanite_chamber_control" + circuit = /obj/item/circuitboard/computer/nanite_chamber_control + var/obj/machinery/nanite_chamber/chamber + +/obj/machinery/computer/nanite_chamber_control/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + find_chamber() + +/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 + set_connected_chamber(NC) + +/obj/machinery/computer/nanite_chamber_control/interact() + if(!chamber) + find_chamber() + ..() + +/obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NaniteChamberControl", name) + ui.open() + +/obj/machinery/computer/nanite_chamber_control/ui_data() + var/list/data = list() + + 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(!CAN_HAVE_NANITES(L)) + data["status_msg"] = "Occupant not compatible with nanites." + return data + + if(chamber.busy) + data["status_msg"] = chamber.busy_message + return data + + data["status_msg"] = null + 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_appearance() + . = TRUE + if("set_safety") + var/threshold = text2num(params["value"]) + if(!isnull(threshold)) + chamber.set_safety(clamp(round(threshold, 1),0,500)) + playsound(src, "terminal_type", 25, FALSE) + chamber.occupant.investigate_log("'s nanites' safety threshold was set to [threshold] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + . = TRUE + if("set_cloud") + var/cloud_id = text2num(params["value"]) + if(!isnull(cloud_id)) + chamber.set_cloud(clamp(round(cloud_id, 1),0,100)) + playsound(src, "terminal_type", 25, FALSE) + chamber.occupant.investigate_log("'s nanites' cloud id was set to [cloud_id] by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + . = TRUE + if("connect_chamber") + find_chamber() + . = TRUE + if("remove_nanites") + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 25, FALSE) + chamber.remove_nanites() + log_combat(usr, chamber.occupant, "cleared nanites from", null, "via [src]") + chamber.occupant.investigate_log("'s nanites were cleared by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + . = TRUE + if("nanite_injection") + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 25, FALSE) + chamber.inject_nanites() + log_combat(usr, chamber.occupant, "injected", null, "with nanites via [src]") + chamber.occupant.investigate_log("was injected with nanites by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + . = TRUE + +/obj/machinery/computer/nanite_chamber_control/proc/set_connected_chamber(new_chamber) + if(chamber) + UnregisterSignal(chamber, COMSIG_PREQDELETED) + chamber = new_chamber + if(chamber) + RegisterSignal(chamber, COMSIG_PREQDELETED, .proc/react_to_chamber_del) + +/obj/machinery/computer/nanite_chamber_control/proc/react_to_chamber_del(datum/source) + SIGNAL_HANDLER + set_connected_chamber(null) diff --git a/modular_zubbers/code/modules/nanites/machines/nanite_cloud_controller.dm b/modular_zubbers/code/modules/nanites/machines/nanite_cloud_controller.dm new file mode 100644 index 00000000000..a4ea1e07de4 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/nanite_cloud_controller.dm @@ -0,0 +1,306 @@ +/obj/machinery/computer/nanite_cloud_controller + name = "nanite cloud controller" + desc = "Stores and controls nanite cloud backups." + icon = 'modular_zubbers/icons/obj/machines/nanite_machines.dmi' + icon_state = "nanite_cloud_controller" + circuit = /obj/item/circuitboard/computer/nanite_cloud_controller + icon_screen = "nanite_cloud_controller_screen" + icon_keyboard = null + + var/obj/item/disk/nanite_program/disk + var/list/datum/nanite_cloud_backup/cloud_backups = list() + var/datum/techweb/linked_techweb + var/current_view = 0 //0 is the main menu, any other number is the page of the backup with that ID + var/new_backup_id = 1 + +/obj/machinery/computer/nanite_cloud_controller/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb) + CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src) + register_context() + +/obj/machinery/computer/nanite_cloud_controller/Destroy() + QDEL_LIST(cloud_backups) //rip backups + eject() + return ..() + +/obj/machinery/computer/nanite_cloud_controller/examine(mob/user) + . = ..() + . += span_notice("Use with a linked multitool to link to a techweb server.") + +/obj/machinery/computer/nanite_cloud_controller/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + return + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Open Panel" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_MULTITOOL) + context[SCREENTIP_CONTEXT_LMB] = "Upload Techweb" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/computer/nanite_cloud_controller/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(!istype(tool, /obj/item/disk/nanite_program)) + return NONE + var/obj/item/disk/nanite_program/new_disk = tool + if(!user.transferItemToLoc(new_disk, src)) + return NONE + to_chat(user, span_notice("You insert [new_disk] into [src]")) + playsound(src, 'sound/machines/terminal/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) + disk = new_disk + return ITEM_INTERACT_SUCCESS + +/obj/machinery/computer/nanite_cloud_controller/multitool_act(mob/living/user, obj/item/multitool/tool) + if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb)) + linked_techweb = tool.buffer + balloon_alert(user, "linked!") + update_static_data_for_all_viewers() + return TRUE + +/obj/machinery/computer/nanite_cloud_controller/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(disk && user.can_perform_action(src, !issilicon(user))) + to_chat(user, span_notice("You take out [disk] from [src].")) + eject(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/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_warning("Cloud ID already registered.")) + return + + var/datum/nanite_cloud_backup/backup = new(src) + var/datum/component/nanites/cloud_copy = backup.AddComponent(/datum/component/nanites) + backup.cloud_id = cloud_id + backup.nanites = cloud_copy + if(linked_techweb) + backup.techweb = linked_techweb + 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, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NaniteCloudControl", name) + ui.open() + +/obj/machinery/computer/nanite_cloud_controller/ui_static_data(mob/user) + . = ..() + var/list/data = . + if(linked_techweb) + data["techweb"] = list( + "name" = linked_techweb.id, + "organization" = linked_techweb.organization, + ) + +// a lot of this should be in static data +/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 + data["has_program"] = P ? TRUE : FALSE + if(P) + 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_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_restart"] = P.timer_restart / 10 + disk_data["timer_shutdown"] = P.timer_shutdown / 10 + disk_data["timer_trigger"] = P.timer_trigger / 10 + disk_data["timer_trigger_delay"] = P.timer_trigger_delay / 10 + + var/list/extra_settings = P.get_extra_settings_frontend() + disk_data["extra_settings"] = extra_settings + if(LAZYLEN(extra_settings)) + disk_data["has_extra_settings"] = TRUE + if(istype(P, /datum/nanite_program/sensor)) + var/datum/nanite_program/sensor/sensor = P + if(sensor.can_rule) + disk_data["can_rule"] = TRUE + data["disk"] = disk_data + else + data["has_disk"] = FALSE + + data["new_backup_id"] = new_backup_id + + 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["timer_restart"] = P.timer_restart / 10 + cloud_program["timer_shutdown"] = P.timer_shutdown / 10 + cloud_program["timer_trigger"] = P.timer_trigger / 10 + cloud_program["timer_trigger_delay"] = P.timer_trigger_delay / 10 + + 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/rules = list() + var/rule_id = 1 + for(var/X in P.rules) + var/datum/nanite_rule/nanite_rule = X + var/list/rule = list() + rule["display"] = nanite_rule.display() + rule["program_id"] = id + rule["id"] = rule_id + rules += list(rule) + rule_id++ + cloud_program["rules"] = rules + if(LAZYLEN(rules)) + cloud_program["has_rules"] = TRUE + cloud_program["all_rules_required"] = P.all_rules_required + + var/list/extra_settings = P.get_extra_settings_frontend() + cloud_program["extra_settings"] = extra_settings + 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("update_new_backup_value") + var/backup_value = text2num(params["value"]) + new_backup_id = backup_value + if("create_backup") + var/cloud_id = new_backup_id + if(!isnull(cloud_id)) + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 50, FALSE) + 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/terminal_prompt.ogg', 50, FALSE) + qdel(backup) + investigate_log("[key_name(usr)] deleted the nanite cloud backup #[current_view]", INVESTIGATE_NANITES) + . = TRUE + if("upload_program") + if(disk?.program) + var/datum/nanite_cloud_backup/backup = get_backup(current_view) + if(backup) + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 50, FALSE) + var/datum/component/nanites/nanites = backup.nanites + nanites.add_program(null, 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/terminal_prompt.ogg', 50, FALSE) + 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 + if("add_rule") + if(disk && disk.program && istype(disk.program, /datum/nanite_program/sensor)) + var/datum/nanite_program/sensor/rule_template = disk.program + if(!rule_template.can_rule) + return + var/datum/nanite_cloud_backup/backup = get_backup(current_view) + if(backup) + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 50, 0) + var/datum/component/nanites/nanites = backup.nanites + var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])] + var/datum/nanite_rule/rule = rule_template.make_rule(P) + + investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES) + . = TRUE + if("remove_rule") + var/datum/nanite_cloud_backup/backup = get_backup(current_view) + if(backup) + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 50, 0) + var/datum/component/nanites/nanites = backup.nanites + var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])] + var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])] + rule.remove() + + investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES) + . = TRUE + if("toggle_rule_logic") + var/datum/nanite_cloud_backup/backup = get_backup(current_view) + if(backup) + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 50, FALSE) + var/datum/component/nanites/nanites = backup.nanites + var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])] + P.all_rules_required = !P.all_rules_required + investigate_log("[key_name(usr)] edited rule logic for program [P.name] into [P.all_rules_required ? "All" : "Any"] in cloud #[current_view]", INVESTIGATE_NANITES) + . = TRUE + +/datum/nanite_cloud_backup + var/cloud_id = 0 + var/datum/component/nanites/nanites + var/obj/machinery/computer/nanite_cloud_controller/storage + var/datum/techweb/techweb + +/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 ..() diff --git a/modular_zubbers/code/modules/nanites/machines/nanite_program_hub.dm b/modular_zubbers/code/modules/nanites/machines/nanite_program_hub.dm new file mode 100644 index 00000000000..4b3ec8d3a72 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/nanite_program_hub.dm @@ -0,0 +1,181 @@ +/obj/machinery/nanite_program_hub + name = "nanite program hub" + desc = "Compiles nanite programs from the techweb servers and downloads them into disks." + icon = 'modular_zubbers/icons/obj/machines/nanite_machines.dmi' + icon_state = "nanite_program_hub" + use_power = IDLE_POWER_USE + anchored = TRUE + density = TRUE + circuit = /obj/item/circuitboard/machine/nanite_program_hub + + var/obj/item/disk/nanite_program/disk + var/datum/techweb/linked_techweb + var/current_category = "Main" + var/detail_view = TRUE + 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"), + list(name = "Protocols"), + ) + +/obj/machinery/nanite_program_hub/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb) + CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src) + register_context() + +/obj/machinery/nanite_program_hub/examine(mob/user) + . = ..() + . += span_notice("Use with a linked multitool to link to a techweb server.") + +/obj/machinery/nanite_program_hub/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + return + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Open Panel" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_MULTITOOL) + context[SCREENTIP_CONTEXT_LMB] = "Upload Techweb" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/nanite_program_hub/update_overlays() + . = ..() + if((machine_stat & (NOPOWER|MAINT|BROKEN)) || panel_open) + return + . += "nanite_program_hub_on" + . += emissive_appearance(icon, "nanite_program_hub_on", src, alpha = src.alpha) + +/obj/machinery/nanite_program_hub/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(!istype(tool, /obj/item/disk/nanite_program)) + return NONE + var/obj/item/disk/nanite_program/new_disk = tool + if(!user.transferItemToLoc(new_disk, src)) + return NONE + to_chat(user, span_notice("You insert [new_disk] into [src]")) + playsound(src, 'sound/machines/terminal/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) + disk = new_disk + return ITEM_INTERACT_SUCCESS + +/obj/machinery/nanite_program_hub/multitool_act(mob/living/user, obj/item/multitool/tool) + if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb)) + linked_techweb = tool.buffer + balloon_alert(user, "linked!") + update_static_data_for_all_viewers() + return TRUE + +/obj/machinery/nanite_program_hub/screwdriver_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_screwdriver(user, "nanite_program_hub_t", "nanite_program_hub", I) + +/obj/machinery/nanite_program_hub/crowbar_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_crowbar(I) + +/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/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(disk && user.can_perform_action(src, !issilicon(user))) + to_chat(user, span_notice("You take out [disk] from [src].")) + eject(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/nanite_program_hub/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NaniteProgramHub", name) + 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 + else + data["has_disk"] = FALSE + + data["detail_view"] = detail_view + + return data + +/obj/machinery/nanite_program_hub/ui_static_data(mob/user) + var/list/data = list() + if(linked_techweb) + data["techweb"] = list( + "name" = linked_techweb.id, + "organization" = linked_techweb.organization, + ) + data["programs"] = list() + for(var/i in linked_techweb.researched_designs) + var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i) + if(!istype(D)) + continue + var/cat_name = D.category[1] //just put them in the first category fuck it + if(isnull(data["programs"][cat_name])) + data["programs"][cat_name] = list() + var/list/program_design = list() + program_design["id"] = D.id + program_design["name"] = D.name + program_design["desc"] = D.desc + data["programs"][cat_name] += list(program_design) + + if(!length(data["programs"])) + data["programs"] = null + + 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.update_name() + playsound(src, 'sound/machines/terminal/terminal_prompt.ogg', 25, FALSE) + . = TRUE + if("refresh") + update_static_data(usr) + . = TRUE + if("toggle_details") + detail_view = !detail_view + . = TRUE + if("clear") + if(disk?.program) + qdel(disk.program) + disk.program = null + disk.name = initial(disk.name) + . = TRUE diff --git a/modular_zubbers/code/modules/nanites/machines/nanite_programmer.dm b/modular_zubbers/code/modules/nanites/machines/nanite_programmer.dm new file mode 100644 index 00000000000..979a89f7988 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/nanite_programmer.dm @@ -0,0 +1,178 @@ +/obj/machinery/nanite_programmer + name = "nanite programmer" + desc = "A device that can edit nanite program disks to adjust their functionality." + icon = 'modular_zubbers/icons/obj/machines/nanite_machines.dmi' + icon_state = "nanite_programmer" + use_power = IDLE_POWER_USE + anchored = TRUE + density = TRUE + circuit = /obj/item/circuitboard/machine/nanite_programmer + var/obj/item/disk/nanite_program/disk + var/datum/nanite_program/program + +/obj/machinery/nanite_programmer/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT) + +/obj/machinery/nanite_programmer/update_overlays() + . = ..() + if((machine_stat & (NOPOWER|MAINT|BROKEN)) || panel_open) + return + . += "nanite_programmer_on" + . += emissive_appearance(icon, "nanite_programmer_on", src, alpha = src.alpha) + +/obj/machinery/nanite_programmer/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(!istype(tool, /obj/item/disk/nanite_program)) + return NONE + var/obj/item/disk/nanite_program/new_disk = tool + if(!user.transferItemToLoc(new_disk, src)) + return NONE + to_chat(user, span_notice("You insert [new_disk] into [src]")) + playsound(src, 'sound/machines/terminal/terminal_insert_disc.ogg', 50, FALSE) + if(disk) + eject(user) + disk = new_disk + program = new_disk.program + return ITEM_INTERACT_SUCCESS + +/obj/machinery/nanite_programmer/screwdriver_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_screwdriver(user, "nanite_programmer_t", "nanite_programmer", I) + +/obj/machinery/nanite_programmer/crowbar_act(mob/living/user, obj/item/I) + if(..()) + return TRUE + + return default_deconstruction_crowbar(I) + +/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/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(disk && user.can_perform_action(src, !issilicon(user))) + to_chat(user, span_notice("You take out [disk] from [src].")) + eject(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/nanite_programmer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NaniteProgrammer", name) + 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_code"] = program.activation_code + data["deactivation_code"] = program.deactivation_code + data["kill_code"] = program.kill_code + data["trigger_code"] = program.trigger_code + data["timer_restart"] = program.timer_restart / 10 + data["timer_shutdown"] = program.timer_shutdown / 10 + data["timer_trigger"] = program.timer_trigger / 10 + data["timer_trigger_delay"] = program.timer_trigger_delay / 10 + + var/list/extra_settings = program.get_extra_settings_frontend() + 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, FALSE) + program.activated = !program.activated //we don't use the activation procs since we aren't in a mob + investigate_log("[key_name(usr)] edited [program.name]'s initial activation status into [program.activated ? "Activated" : "Deactivated"]", INVESTIGATE_NANITES) + . = TRUE + if("set_code") + var/new_code = text2num(params["code"]) + playsound(src, "terminal_type", 25, FALSE) + var/target_code = params["target_code"] + switch(target_code) + if("activation") + program.activation_code = clamp(round(new_code, 1),0,9999) + investigate_log("[key_name(usr)] edited [program.name]'s activation code into [program.activation_code]", INVESTIGATE_NANITES) + if("deactivation") + program.deactivation_code = clamp(round(new_code, 1),0,9999) + investigate_log("[key_name(usr)] edited [program.name]'s deactivation code into [program.deactivation_code]", INVESTIGATE_NANITES) + if("kill") + program.kill_code = clamp(round(new_code, 1),0,9999) + investigate_log("[key_name(usr)] edited [program.name]'s kill code into [program.kill_code]", INVESTIGATE_NANITES) + if("trigger") + program.trigger_code = clamp(round(new_code, 1),0,9999) + investigate_log("[key_name(usr)] edited [program.name]'s trigger code into [program.trigger_code]", INVESTIGATE_NANITES) + . = TRUE + if("set_extra_setting") + program.set_extra_setting(params["target_setting"], params["value"]) + investigate_log("[key_name(usr)] edited [program.name]'s extra setting '[params["target_setting"]]' into [params["value"]]", INVESTIGATE_NANITES) + playsound(src, "terminal_type", 25, FALSE) + . = TRUE + if("set_restart_timer") + var/timer = text2num(params["delay"]) + if(!isnull(timer)) + playsound(src, "terminal_type", 25, FALSE) + timer = clamp(round(timer, 1), 0, 3600) + timer *= 10 //convert to deciseconds + program.timer_restart = timer + investigate_log("[key_name(usr)] edited [program.name]'s restart timer into [timer/10] s", INVESTIGATE_NANITES) + . = TRUE + if("set_shutdown_timer") + var/timer = text2num(params["delay"]) + if(!isnull(timer)) + playsound(src, "terminal_type", 25, FALSE) + timer = clamp(round(timer, 1), 0, 3600) + timer *= 10 //convert to deciseconds + program.timer_shutdown = timer + investigate_log("[key_name(usr)] edited [program.name]'s shutdown timer into [timer/10] s", INVESTIGATE_NANITES) + . = TRUE + if("set_trigger_timer") + var/timer = text2num(params["delay"]) + if(!isnull(timer)) + playsound(src, "terminal_type", 25, FALSE) + timer = clamp(round(timer, 1), 0, 3600) + timer *= 10 //convert to deciseconds + program.timer_trigger = timer + investigate_log("[key_name(usr)] edited [program.name]'s trigger timer into [timer/10] s", INVESTIGATE_NANITES) + . = TRUE + if("set_timer_trigger_delay") + var/timer = text2num(params["delay"]) + if(!isnull(timer)) + playsound(src, "terminal_type", 25, FALSE) + timer = clamp(round(timer, 1), 0, 3600) + timer *= 10 //convert to deciseconds + program.timer_trigger_delay = timer + investigate_log("[key_name(usr)] edited [program.name]'s trigger delay timer into [timer/10] s", INVESTIGATE_NANITES) + . = TRUE + +/obj/machinery/nanite_programmer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range=0) + . = ..() + var/static/regex/when = regex("(?:^\\W*when|when\\W*$)", "i") //starts or ends with when + if(findtext(raw_message, when) && !istype(speaker, /obj/machinery/nanite_programmer)) + say("When you code it!!") diff --git a/modular_zubbers/code/modules/nanites/machines/public_chamber.dm b/modular_zubbers/code/modules/nanites/machines/public_chamber.dm new file mode 100644 index 00000000000..09904de4246 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/machines/public_chamber.dm @@ -0,0 +1,207 @@ +/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/bci_implanter.dmi' + icon_state = "bci_implanter" + base_icon_state = "bci_implanter" + layer = ABOVE_WINDOW_LAYER + use_power = IDLE_POWER_USE + anchored = TRUE + density = TRUE + idle_power_usage = 50 + active_power_usage = 300 + + 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/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + occupant_typecache = GLOB.typecache_living + +/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_appearance() + +/obj/machinery/public_nanite_chamber/proc/inject_nanites(mob/living/attacker) + if(machine_stat & (NOPOWER|BROKEN)) + return + if((machine_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, attacker),80) + +/obj/machinery/public_nanite_chamber/proc/complete_injection(locked_state, mob/living/attacker) + //TODO MACHINE DING + locked = locked_state + set_busy(FALSE) + if(!occupant) + return + if(attacker) + occupant.investigate_log("was injected with nanites with cloud ID [cloud_id] by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + log_combat(attacker, occupant, "injected", null, "with nanites via [src]") + occupant.AddComponent(/datum/component/nanites, 75, cloud_id) + +/obj/machinery/public_nanite_chamber/proc/change_cloud(mob/living/attacker) + if(machine_stat & (NOPOWER|BROKEN)) + return + if((machine_stat & MAINT) || panel_open) + return + if(!occupant || busy) + return + + var/locked_state = locked + locked = TRUE + + 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"),40) + addtimer(CALLBACK(src, .proc/complete_cloud_change, locked_state, attacker),60) + +/obj/machinery/public_nanite_chamber/proc/complete_cloud_change(locked_state, mob/living/attacker) + locked = locked_state + set_busy(FALSE) + if(!occupant) + return + if(attacker) + occupant.investigate_log("had their nanite cloud ID changed into [cloud_id] by [key_name(attacker)] using [src] at [AREACOORD(src)].", INVESTIGATE_NANITES) + SEND_SIGNAL(occupant, COMSIG_NANITE_SET_CLOUD, cloud_id) + +/obj/machinery/public_nanite_chamber/update_icon_state() + //running and someone in there + if(occupant) + icon_state = busy ? busy_icon_state : "[base_icon_state]_occupied" + return ..() + //running + icon_state = "[base_icon_state][state_open ? "_open" : null]" + return ..() + +/obj/machinery/public_nanite_chamber/update_overlays() + . = ..() + if((machine_stat & MAINT) || panel_open) + . += "maint" + return + if(machine_stat & (NOPOWER|BROKEN)) + return + + if(busy || locked) + . += "red" + if(locked) + . += "bolted" + return + . += "green" + +/obj/machinery/public_nanite_chamber/proc/toggle_open(mob/user) + if(panel_open) + to_chat(user, span_notice("Close the maintenance panel first.")) + return + + if(state_open) + close_machine(null, user) + return + + else if(locked) + to_chat(user, span_notice("The bolts are locked down, securing the door shut.")) + return + + open_machine() + +/obj/machinery/public_nanite_chamber/container_resist_act(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_notice("You see [user] kicking against the door of [src]!"), \ + span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \ + span_hear("You hear a metallic creaking from [src].")) + 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_warning("[user] successfully broke out of [src]!"), \ + span_notice("You successfully break out of [src]!")) + open_machine() + +/obj/machinery/public_nanite_chamber/close_machine(mob/living/carbon/user, density_to_set = TRUE) + if(!state_open) + return FALSE + + ..() + + . = TRUE + + addtimer(CALLBACK(src, .proc/try_inject_nanites, user), 3 SECONDS) //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(mob/living/attacker) + if(occupant) + var/mob/living/L = occupant + if(SEND_SIGNAL(L, COMSIG_HAS_NANITES)) + var/datum/component/nanites/nanites = L.GetComponent(/datum/component/nanites) + if(nanites && nanites.cloud_id != cloud_id) + change_cloud(attacker) + return + if(CAN_HAVE_NANITES(L)) + inject_nanites(attacker) + +/obj/machinery/public_nanite_chamber/open_machine(drop = TRUE, density_to_set = FALSE) + . = ..() + if(state_open) + return FALSE + + ..() + + return TRUE + +/obj/machinery/public_nanite_chamber/relaymove(mob/living/user, direction) + if(user.stat || locked) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, span_warning("[src]'s door won't budge!")) + 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_appearance()//..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/mouse_drop_receive(mob/living/M, mob/user, params) + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH | SILENT_ADJACENCY) || !iscarbon(M)) + return + if(close_machine(M, user)) + log_combat(user, M, "inserted", null, "into [src].") + add_fingerprint(user) diff --git a/modular_zubbers/code/modules/nanites/nanite_programs.dm b/modular_zubbers/code/modules/nanites/nanite_programs.dm new file mode 100644 index 00000000000..0b26b4e79f0 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs.dm @@ -0,0 +1,335 @@ +/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/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/timer_restart = 0 //When deactivated, the program will wait X deciseconds before self-reactivating. Also works if the program begins deactivated. + var/timer_shutdown = 0 //When activated, the program will wait X deciseconds before self-deactivating. Also works if the program begins activated. + var/timer_trigger = 0 //[Trigger only] While active, the program will attempt to trigger once every x deciseconds. + var/timer_trigger_delay = 0 //[Trigger only] While active, the program will delay trigger signals by X deciseconds. + + //Indicates the next world.time tick where these timers will act + var/timer_restart_next = 0 + var/timer_shutdown_next = 0 + var/timer_trigger_next = 0 + var/timer_trigger_delay_next = 0 + + //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 + ///Don't ever override this or I will come to your house and stand menacingly behind a bush + VAR_FINAL/list/extra_settings = list() + + //Rules + //Rules that automatically manage if the program's active without requiring separate sensor programs + var/list/datum/nanite_rule/rules = list() + var/all_rules_required = TRUE //Whether all rules are required for positive condition or any of specified + +/datum/nanite_program/New() + . = ..() + register_extra_settings() + +/datum/nanite_program/Destroy() + extra_settings = null + if(host_mob) + if(activated) + deactivate() + if(passive_enabled) + disable_passive_effect() + on_mob_remove() + if(nanites) + nanites.programs -= src + for(var/datum/nanite_rule/rule as anything in rules) + rule.remove() + rules.Cut() + return ..() + +/datum/nanite_program/proc/copy() + var/datum/nanite_program/new_program = new type() + copy_programming(new_program, TRUE) + + return new_program + +/datum/nanite_program/proc/copy_programming(datum/nanite_program/target, copy_activated = TRUE) + if(copy_activated) + target.activated = activated + target.timer_restart = timer_restart + target.timer_shutdown = timer_shutdown + target.timer_trigger = timer_trigger + target.timer_trigger_delay = timer_trigger_delay + target.activation_code = activation_code + target.deactivation_code = deactivation_code + target.kill_code = kill_code + target.trigger_code = trigger_code + + target.rules = list() + for(var/R in rules) + var/datum/nanite_rule/rule = R + rule.copy_to(target) + target.all_rules_required = all_rules_required + + if(istype(target,src)) + copy_extra_settings_to(target) + +/// Register extra settings by overriding this. +/// +/// `extra_settings[name] = new typepath()` for each extra setting. +/datum/nanite_program/proc/register_extra_settings() + return + +///You can override this if you need to have special behavior after setting certain settings. +/datum/nanite_program/proc/set_extra_setting(setting, value) + var/datum/nanite_extra_setting/ES = extra_settings[setting] + return ES.set_value(value) + +///You probably shouldn't be overriding this one, but I'm not a cop. +/datum/nanite_program/proc/get_extra_setting_value(setting) + var/datum/nanite_extra_setting/ES = extra_settings[setting] + return ES.get_value() + +///Used for getting information about the extra settings to the frontend +/datum/nanite_program/proc/get_extra_settings_frontend() + var/list/out = list() + for(var/name in extra_settings) + var/datum/nanite_extra_setting/ES = extra_settings[name] + out += ES.get_frontend_list(name) + return out + +///Copy of the list instead of direct reference for obvious reasons +/datum/nanite_program/proc/copy_extra_settings_to(datum/nanite_program/target) + var/list/copy_list = list() + for(var/ns_name in extra_settings) + var/datum/nanite_extra_setting/extra_setting = extra_settings[ns_name] + copy_list[ns_name] = extra_setting.get_copy() + target.extra_settings = copy_list + +/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 depending on initial status; starts the restart and shutdown timers + activate() + else + deactivate() + +/datum/nanite_program/proc/on_mob_remove() + return + +/datum/nanite_program/proc/toggle() + if(!activated) + activate() + else + deactivate() + +/datum/nanite_program/proc/activate() + activated = TRUE + if(timer_shutdown) + timer_shutdown_next = world.time + timer_shutdown + +/datum/nanite_program/proc/deactivate() + if(passive_enabled) + disable_passive_effect() + activated = FALSE + if(timer_restart) + timer_restart_next = world.time + timer_restart + +/datum/nanite_program/proc/on_process() + if(!activated) + if(timer_restart_next && world.time > timer_restart_next) + activate() + timer_restart_next = 0 + return + + if(timer_shutdown_next && world.time > timer_shutdown_next) + deactivate() + timer_shutdown_next = 0 + return + + if(timer_trigger && world.time > timer_trigger_next) + trigger() + timer_trigger_next = world.time + timer_trigger + return + + if(timer_trigger_delay_next && world.time > timer_trigger_delay_next) + trigger(delayed = TRUE) + timer_trigger_delay_next = 0 + return + + if(check_conditions() && consume_nanites(use_rate)) + if(!passive_enabled) + enable_passive_effect() + active_effect() + else + if(passive_enabled) + disable_passive_effect() + +//If false, disables active, passive effects, and triggers without consuming nanites +//Can be used to avoid consuming nanites for nothing +/datum/nanite_program/proc/check_conditions() + if (!LAZYLEN(rules)) + return TRUE + for(var/R in rules) + var/datum/nanite_rule/rule = R + if(!all_rules_required && rule.check_rule()) + return TRUE + if(all_rules_required && !rule.check_rule()) + return FALSE + return all_rules_required ? TRUE : FALSE + +//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 + +//Checks conditions then fires the nanite trigger effect +/datum/nanite_program/proc/trigger(delayed = FALSE, comm_message) + if(!can_trigger) + return + if(!activated) + return + if(timer_trigger_delay && !delayed) + timer_trigger_delay_next = world.time + timer_trigger_delay + return + if(world.time < next_trigger) + return + if(!check_conditions()) + return + if(!consume_nanites(trigger_cost)) + return + next_trigger = world.time + trigger_cooldown + on_trigger(comm_message) + +//Nanite trigger effect, requires can_trigger to be used +/datum/nanite_program/proc/on_trigger(comm_message) + return + +/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)) + host_mob.investigate_log("[src] nanite program received a software error due to emp.", INVESTIGATE_NANITES) + software_error() + +/datum/nanite_program/proc/on_shock(shock_damage) + if(!(program_flags & NANITE_SHOCK_IMMUNE)) + if(prob(10)) + host_mob.investigate_log("[src] nanite program received a software error due to shock.", INVESTIGATE_NANITES) + software_error() + else if(prob(33)) + host_mob.investigate_log("[src] nanite program was deleted due to shock.", INVESTIGATE_NANITES) + qdel(src) + +/datum/nanite_program/proc/on_minor_shock() + if(!(program_flags & NANITE_SHOCK_IMMUNE)) + if(prob(10)) + host_mob.investigate_log("[src] nanite program received a software error due to minor shock.", INVESTIGATE_NANITES) + software_error() + +/datum/nanite_program/proc/on_death() + return + +/datum/nanite_program/proc/software_error(type) + if(!type) + type = rand(1,5) + switch(type) + if(1) + host_mob.investigate_log("[src] nanite program was deleted by software error.", INVESTIGATE_NANITES) + qdel(src) //kill switch + return + if(2) //deprogram codes + host_mob.investigate_log("[src] nanite program was de-programmed by software error.", INVESTIGATE_NANITES) + activation_code = 0 + deactivation_code = 0 + kill_code = 0 + trigger_code = 0 + if(3) + host_mob.investigate_log("[src] nanite program was toggled by software error.", INVESTIGATE_NANITES) + toggle() //enable/disable + if(4) + if(can_trigger) + host_mob.investigate_log("[src] nanite program was triggered by software error.", INVESTIGATE_NANITES) + trigger() + if(5) //Program is scrambled and does something different + var/rogue_type = pick(rogue_types) + var/datum/nanite_program/rogue = new rogue_type + host_mob.investigate_log("[src] nanite program was converted into [rogue.name] by software error.", INVESTIGATE_NANITES) + nanites.add_program(null, rogue, src) + qdel(src) + +/datum/nanite_program/proc/receive_signal(code, source) + if(activation_code && code == activation_code && !activated) + activate() + host_mob.investigate_log("'s [name] nanite program was activated by [source] with code [code].", INVESTIGATE_NANITES) + else if(deactivation_code && code == deactivation_code && activated) + deactivate() + host_mob.investigate_log("'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("'s [name] nanite program was triggered by [source] with code [code].", INVESTIGATE_NANITES) + if(kill_code && code == kill_code) + host_mob.investigate_log("'s [name] nanite program was deleted by [source] with code [code].", INVESTIGATE_NANITES) + qdel(src) + +///A nanite program containing a behaviour protocol. Only one protocol of each class can be active at once. +/datum/nanite_program/protocol + name = "Nanite Protocol" + var/protocol_class = NONE + +/datum/nanite_program/protocol/check_conditions() + . = ..() + for(var/protocol in nanites.protocols) + var/datum/nanite_program/protocol/P = protocol + if(P != src && P.activated && P.protocol_class == protocol_class) + return FALSE + +/datum/nanite_program/protocol/on_add(datum/component/nanites/_nanites) + ..() + nanites.protocols += src + +/datum/nanite_program/protocol/Destroy() + if(nanites) + nanites.protocols -= src + return ..() diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/buffing.dm b/modular_zubbers/code/modules/nanites/nanite_programs/buffing.dm new file mode 100644 index 00000000000..05e2ba311cf --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/buffing.dm @@ -0,0 +1,231 @@ +//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/disable_passive_effect() + . = ..() + if(ishuman(host_mob)) + var/mob/living/carbon/human/H = host_mob + H.physiology.stun_mod *= 2 + +/datum/nanite_program/dermal_armor + name = "Dermal Hardening" + desc = "The nanites form a mesh under the host's skin, protecting them from melee and bullet impacts. \ + Each hit costs nanites two times to damage, but the more nanites you have, the more protection you get. \ + 50 nanites = 1 flat armor, with each hit costing two times it's damage in nanites. \ + Will not turn on with other dermal armor programs." + use_rate = 2 + rogue_types = list(/datum/nanite_program/skin_decay) + var/damage_type = BRUTE + var/signal = COMSIG_MOB_ALWAYS_APPLY_DAMAGE + var/max_damage_resist = 30 + var/current_flat_mod = 0 + var/rgb_color = list(255, 0, 0) + var/filter_name = "nanite_armor_outline" + var/hide_timer + var/cleanup_timer + /// how much to multiply the nanite cost on the damage received + var/cost_modifier = 2 + +/datum/nanite_program/dermal_armor/activate() + if(check_duplicate_programs()) + return + if(!ishuman(host_mob)) + return + . = ..() + +/datum/nanite_program/dermal_armor/enable_passive_effect() + . = ..() + RegisterSignal(host_mob, signal, PROC_REF(pre_damage)) + +/datum/nanite_program/dermal_armor/proc/check_duplicate_programs() + for(var/program in nanites.programs) + if(istype(program, type) && program != src) + return TRUE + return FALSE + +/datum/nanite_program/dermal_armor/disable_passive_effect() + . = ..() + UnregisterSignal(host_mob, signal) + + delete_hide_timer() + delete_cleanup_timer() + + update_damage_modifier(0) + +/datum/nanite_program/dermal_armor/active_effect() + // 1 for every 50 nanites, up to 30 flat armor, max of 10 at 500 nanites + var/nanite_armor = ceil(nanites.nanite_volume * 0.02) + var/clamped_armor = clamp(nanite_armor, 1, max_damage_resist) + update_damage_modifier(clamped_armor) + +// update and handle the damage modifier before taking damage, thus only when needed +/datum/nanite_program/dermal_armor/proc/pre_damage( + mob/living/damaged_mob, + damage_amount, + damagetype, + def_zone, + blocked, + wound_bonus, + bare_wound_bonus, + sharpness, + attack_direction, + attacking_item, + wound_clothing + ) + SIGNAL_HANDLER + if(damagetype != damage_type) + return + var/mob/living/carbon/human/humie = host_mob + if(!istype(humie) || !humie.physiology || !nanites) + return + // since we are likely to already have a damage modifier, we need to calculate the actual damage received + // as the damage_amount received here is already modified by the flat_brute_mod + var/actual_damage = damage_amount + current_flat_mod + if(actual_damage >= nanites.nanite_volume) + playsound(host_mob, SFX_SHATTER) + host_mob.Knockdown(1 SECONDS) + to_chat(host_mob, span_warning("Something shatters under your skin, and you feel a sharp pain!")) + disable_passive_effect() + return + + // after this we don't need to prevent the rest of the code from running + INVOKE_ASYNC(src, PROC_REF(on_pre_damage), damagetype, actual_damage) + +/datum/nanite_program/dermal_armor/proc/on_pre_damage(damagetype, amount) + // 2 nanites for every 1 damage blocked, ensure that we don't spend extra nanites when armor is higher than damage + if(amount >= current_flat_mod) + consume_nanites(current_flat_mod * cost_modifier) + else + consume_nanites(amount * cost_modifier) + + var/damage_duration = (amount / current_flat_mod) * 2 SECONDS + var/timeleft = timeleft(hide_timer) + var/leftover_time = !isnull(timeleft) ? timeleft : 0 + // if we're already showing the outline, reset the timer + + if(hide_timer) + delete_hide_timer() + else + // how long to keep the color effect, while also changing color intensity based on damage + // only add the filter if we're not cleaning up, as that means we're already showing the outline which is animating to hide itself + if(cleanup_timer) + delete_cleanup_timer() + else + host_mob.add_filter(filter_name, 2, list("type" = "outline", size = 0)) + // control the intensity of the color based on how much damage we're taking vs the armor we have + var/rgb_color = damage_color(amount, current_flat_mod) + host_mob.transition_filter(filter_name, list("type" = "outline", color = rgb(rgb_color[1], rgb_color[2], rgb_color[3]), size = 0.5), 0.5 SECONDS) + + var/time_to_hide = clamp((damage_duration + leftover_time * 0.5) * 0.8, 0.5 SECONDS, 2 SECONDS) + var/difference = max(damage_duration - time_to_hide, 0.5 SECONDS) // spend 20% of the time to hide the outline + hide_timer = addtimer(CALLBACK(src, PROC_REF(hide_outline), difference), time_to_hide, TIMER_STOPPABLE) + +/datum/nanite_program/dermal_armor/proc/delete_hide_timer() + deltimer(hide_timer) + hide_timer = null + +/datum/nanite_program/dermal_armor/proc/delete_cleanup_timer() + deltimer(cleanup_timer) + cleanup_timer = null + +// modifies the RGB color based on the damage amount, making it more or less intense based on the damage +/datum/nanite_program/dermal_armor/proc/damage_color(amount, armor) + var/color_strength = clamp(amount / armor, 0.2, 1) + var/colors = list() + for(var/i in 1 to 3) + var/color = rgb_color[i] + colors += clamp(color * color_strength, 0, 255) + return colors + +// hiding the outline is a 2 step process as we have a delay before we start hiding it +// this is to prevent the outline from flickering when we're taking damage in quick succession +/datum/nanite_program/dermal_armor/proc/hide_outline(hide_time = 0.5 SECONDS) + hide_timer = null + host_mob.transition_filter(filter_name, list("type" = "outline", size = 0), hide_time) + cleanup_timer = addtimer(CALLBACK(src, PROC_REF(cleanup_outline)), hide_time, TIMER_STOPPABLE) + +/datum/nanite_program/dermal_armor/proc/cleanup_outline() + host_mob.remove_filter(filter_name) + cleanup_timer = null + +/datum/nanite_program/dermal_armor/proc/update_damage_modifier(amount) + var/mob/living/carbon/human/humie = host_mob + var/valid_change = clamp(amount, 1, 30) + humie.physiology.flat_brute_mod += current_flat_mod + current_flat_mod = valid_change + humie.physiology.flat_brute_mod -= valid_change + +/datum/nanite_program/dermal_armor/refractive + name = "Dermal Refractive Surface" + desc = "The nanites form a membrane above the host's skin, reducing the effect of laser and energy impacts. \ + Each hit costs nanites equilavent to damage, but the more nanites you have, the more protection you get. \ + 50 nanites = 1 flat armor, with each hit costing two times it's damage in nanites. \ + Will not turn on with other dermal armor programs." + damage_type = BURN + rgb_color = list(255, 255, 0) + +/datum/nanite_program/dermal_armor/refractive/update_damage_modifier(mob/living/carbon/human/humie, amount) + humie.physiology.flat_burn_mod -= current_flat_mod + current_flat_mod = amount + humie.physiology.flat_burn_mod += amount + +/datum/nanite_program/coagulating + name = "Vein Repressurization" + desc = "The nanites re-route circulating blood away from open wounds, dramatically reducing bleeding rate." + use_rate = 0.20 + 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.5 + +/datum/nanite_program/coagulating/disable_passive_effect() + . = ..() + if(ishuman(host_mob)) + var/mob/living/carbon/human/H = host_mob + H.physiology.bleed_mod *= 2 + +/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() + . = ..() + ADD_TRAIT(host_mob, TRAIT_SHOCKIMMUNE, NANITES_TRAIT) + +/datum/nanite_program/conductive/disable_passive_effect() + . = ..() + REMOVE_TRAIT(host_mob, TRAIT_SHOCKIMMUNE, NANITES_TRAIT) + +/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, TRUE)) //won't work if on a rev, to avoid having implanted revs. + ADD_TRAIT(host_mob, TRAIT_MINDSHIELD, NANITES_TRAIT) + host_mob.sec_hud_set_implants() + +/datum/nanite_program/mindshield/disable_passive_effect() + . = ..() + REMOVE_TRAIT(host_mob, TRAIT_MINDSHIELD, NANITES_TRAIT) + host_mob.sec_hud_set_implants() diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/healing.dm b/modular_zubbers/code/modules/nanites/nanite_programs/healing.dm new file mode 100644 index 00000000000..b5c972ca43d --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/healing.dm @@ -0,0 +1,190 @@ +//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. Will not consume nanites while the host is unharmed." + use_rate = 0.5 + rogue_types = list(/datum/nanite_program/necrotic) + var/valid_bodytype = BODYTYPE_ORGANIC + var/valid_biotype = MOB_ORGANIC + var/healing_rate = NANITE_BIO_REGENERATION + var/always_active = FALSE + +/datum/nanite_program/regenerative/check_conditions() + if(always_active) + return TRUE + if(!host_mob.getBruteLoss() && !host_mob.getFireLoss()) + return FALSE + if(iscarbon(host_mob)) + var/mob/living/carbon/carbon = host_mob + var/list/parts = carbon.get_damaged_bodyparts(TRUE, TRUE, valid_bodytype) + if(!parts.len) + return FALSE + else if(!(host_mob.mob_biotypes & valid_biotype)) + return FALSE + return ..() + +/datum/nanite_program/regenerative/active_effect() + host_mob.heal_overall_damage(healing_rate, healing_rate, required_bodytype = valid_bodytype) + +/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) + healing_rate = NANITE_ADV_BIO_REGENERATION + always_active = TRUE + +/datum/nanite_program/regenerative/robotic + name = "Mechanical Repair" + desc = "The nanites fix damage in the host's mechanical limbs. Will not consume nanites while the host's mechanical limbs are undamaged, or while the host has no mechanical limbs." + use_rate = 3 + rogue_types = list(/datum/nanite_program/necrotic) + valid_bodytype = BODYTYPE_ROBOTIC + valid_biotype = MOB_ROBOTIC + healing_rate = NANITE_ROBO_REGENERATION + +/datum/nanite_program/temperature + name = "Temperature Adjustment" + desc = "The nanites adjust the host's internal temperature to an ideal level. Will not consume nanites while the host is at a normal body temperature." + use_rate = 3.5 + rogue_types = list(/datum/nanite_program/skin_decay) + +/datum/nanite_program/temperature/check_conditions() + if(host_mob.bodytemperature > (host_mob.get_body_temp_normal(apply_change=FALSE) - 30) && host_mob.bodytemperature < (host_mob.get_body_temp_normal(apply_change=FALSE) + 30)) + return FALSE + return ..() + +/datum/nanite_program/temperature/active_effect() + var/target_temp = host_mob.get_body_temp_normal(apply_change=FALSE) + if(host_mob.bodytemperature > target_temp) + host_mob.adjust_bodytemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) + else if(host_mob.bodytemperature < (target_temp + 1)) + host_mob.adjust_bodytemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, target_temp) + +/datum/nanite_program/purging + name = "Blood Purification" + desc = "The nanites purge toxins and chemicals from the host's bloodstream. Consumes nanites even if it has no effect." + use_rate = 1 + rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic) + var/healing_rate = NANITE_TOX_REGENERATION + var/purge_path = /datum/reagent + var/force_heal = FALSE + +/datum/nanite_program/purging/check_conditions() + . = ..() + if(!. || !host_mob.reagents) + return FALSE // No trying to purge simple mobs + +/datum/nanite_program/purging/active_effect() + host_mob.adjustToxLoss(-healing_rate, forced = force_heal) + for(var/datum/reagent/R as anything in host_mob.reagents.reagent_list) + if(!istype(R, purge_path)) + continue + host_mob.reagents.remove_reagent(R.type, 1) + +/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. Consumes nanites even if it has no effect." + use_rate = 2 + rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic) + healing_rate = NANITE_ADV_TOX_REGENERATION + purge_path = /datum/reagent/toxin + force_heal = TRUE + +/datum/nanite_program/blood_restoring + name = "Blood Regeneration" + desc = "The nanites stimulate and boost blood cell production in the host. Will not consume nanites while the host has a safe blood level." + use_rate = 1 + rogue_types = list(/datum/nanite_program/suffocating) + +/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/brain_heal + name = "Neural Regeneration" + desc = "The nanites fix neural connections in the host's brain, reversing brain damage and minor traumas. Will not consume nanites while it would not have an effect." + use_rate = 1.5 + rogue_types = list(/datum/nanite_program/brain_decay) + +/datum/nanite_program/brain_heal/check_conditions() + if(host_mob.get_organ_loss(ORGAN_SLOT_BRAIN) > 0) + return ..() + if(iscarbon(host_mob)) + var/mob/living/carbon/carbon = host_mob + if (carbon.has_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)) + return ..() + return FALSE + +/datum/nanite_program/brain_heal/active_effect() + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -NANITE_BRAIN_REGENERATION) + if(iscarbon(host_mob) && prob(1)) + var/mob/living/carbon/C = host_mob + C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC) + +/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. Consumes nanites even if it has no effect." + use_rate = 3 + rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire) + +/datum/nanite_program/brain_heal_advanced/active_effect() + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -NANITE_ADV_BRAIN_REGENERATION) + if(iscarbon(host_mob) && prob(1)) + var/mob/living/carbon/C = host_mob + C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY) + +/datum/nanite_program/defib + name = "Defibrillation" + desc = "The nanites shock the host's heart when triggered, bringing them back to life if the body can sustain it." + can_trigger = TRUE + trigger_cost = 25 + trigger_cooldown = 120 + rogue_types = list(/datum/nanite_program/shocking) + +/datum/nanite_program/defib/on_trigger(comm_message) + host_mob.notify_revival("Your heart is being defibrillated by nanites. Re-enter your corpse if you want to be revived!") + host_mob.grab_ghost() + addtimer(CALLBACK(src, .proc/zap), 50) + +/datum/nanite_program/defib/proc/check_revivable() + if(!iscarbon(host_mob)) //nonstandard biology + return FALSE + var/mob/living/carbon/C = host_mob + if(C.get_ghost()) + return FALSE + return C.can_defib() == DEFIB_POSSIBLE + +/datum/nanite_program/defib/proc/zap() + var/mob/living/carbon/C = host_mob + playsound(C, 'sound/machines/defib/defib_charge.ogg', 50, FALSE) + sleep(30) + playsound(C, 'sound/machines/defib/defib_zap.ogg', 50, FALSE) + if(check_revivable()) + if(C.stat == DEAD) + var/original_oxyloss = C.getOxyLoss() + C.setOxyLoss(OXYLOSS_PASSOUT_THRESHOLD - 5) + if(C.revive()) + playsound(C, 'sound/machines/defib/defib_success.ogg', 50, FALSE) + C.emote("gasp") + C.adjust_jitter_up_to(10 SECONDS, 1 MINUTES) + SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) + log_game("[C] has been successfully defibrillated by nanites.") + return + else + C.setOxyLoss(original_oxyloss) + playsound(C, 'sound/machines/defib/defib_failed.ogg', 50, FALSE) + diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/protocols.dm b/modular_zubbers/code/modules/nanites/nanite_programs/protocols.dm new file mode 100644 index 00000000000..1b40e6d7f61 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/protocols.dm @@ -0,0 +1,277 @@ +//Replication Protocols +/datum/nanite_program/protocol/kickstart + name = "Kickstart Protocol" + desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation, \ + resulting in an additional 420 nanite volume being produced during the first two minutes." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_REPLICATION + var/boost_duration = 1200 + +/datum/nanite_program/protocol/kickstart/check_conditions() + if(!(world.time < nanites.start_time + boost_duration)) + return FALSE + return ..() + +/datum/nanite_program/protocol/kickstart/active_effect() + nanites.adjust_nanites(null, NANITE_PROTOCOL_KICKSTART_REPLICATION) + +/datum/nanite_program/protocol/factory + name = "Factory Protocol" + desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time, \ + granting a maximum of 2 additional nanite production after roughly 17 minutes. \ + The factory decays if the protocol is not active, or if the nanites are disrupted by shocks or EMPs." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_REPLICATION + var/factory_efficiency = 0 + var/max_efficiency = 1000 //Goes up to 2 bonus regen per tick after 16 minutes and 40 seconds + +/datum/nanite_program/protocol/factory/on_process() + if(!activated || !check_conditions()) + factory_efficiency = max(0, factory_efficiency - 5) + ..() + +/datum/nanite_program/protocol/factory/on_emp(severity) + ..() + factory_efficiency = max(0, factory_efficiency - 300) + +/datum/nanite_program/protocol/factory/on_shock(shock_damage) + ..() + factory_efficiency = max(0, factory_efficiency - 200) + +/datum/nanite_program/protocol/factory/on_minor_shock() + ..() + factory_efficiency = max(0, factory_efficiency - 100) + +/datum/nanite_program/protocol/factory/active_effect() + factory_efficiency = min(factory_efficiency + 1, max_efficiency) + nanites.adjust_nanites(null, round(0.002 * factory_efficiency, 0.1)) + +/datum/nanite_program/protocol/pyramid + name = "Pyramid Protocol" + desc = "Replication Protocol: the nanites implement an alternate cooperative replication protocol that is active as long as the nanite saturation level is above 80%, \ + resulting in an additional volume production of 1.2 per second." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_REPLICATION + var/boost = 1.2 + +/datum/nanite_program/protocol/pyramid/check_conditions() + if((nanites.nanite_volume / nanites.max_nanites) < 0.8) + return FALSE + + return ..() + +/datum/nanite_program/protocol/pyramid/active_effect() + nanites.adjust_nanites(null, boost) + +/datum/nanite_program/protocol/offline + name = "Eclipse Protocol" + desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_REPLICATION + var/boost = 3 + + +/datum/nanite_program/protocol/offline/check_conditions() + if(nanites.host_mob.stat == CONSCIOUS) + return FALSE + return ..() + + +/datum/nanite_program/protocol/offline/active_effect() + nanites.adjust_nanites(null, boost) + +/datum/nanite_program/protocol/hive + name = "Hive Protocol" + desc = "Storage Protocol: the nanites use a more efficient grid arrangment for volume storage, increasing maximum volume to 750." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_STORAGE + var/extra_volume = 250 + +/datum/nanite_program/protocol/hive/enable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites + extra_volume) + +/datum/nanite_program/protocol/hive/disable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites - extra_volume) + +/datum/nanite_program/protocol/zip + name = "Zip Protocol" + desc = "Storage Protocol: the nanites are disassembled and compacted when unused, increasing the maximum volume to 1000. However, the process slows down their replication rate slightly." + use_rate = 0.2 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_STORAGE + var/extra_volume = 500 + +/datum/nanite_program/protocol/zip/enable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites + extra_volume) + +/datum/nanite_program/protocol/zip/disable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites - extra_volume) + +/datum/nanite_program/protocol/free_range + name = "Free-range Protocol" + desc = "Storage Protocol: the nanites discard their default storage protocols in favour of a cheaper and more organic approach. Reduces maximum volume to 250, but increases the replication rate by 0.5." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_STORAGE + var/boost = 0.5 + var/extra_volume = -250 + +/datum/nanite_program/protocol/free_range/enable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites + extra_volume) + +/datum/nanite_program/protocol/free_range/disable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites - extra_volume) + +/datum/nanite_program/protocol/free_range/active_effect() + nanites.adjust_nanites(null, boost) + +/datum/nanite_program/protocol/unsafe_storage + name = "S.L.O. Protocol" + desc = "Storage Protocol: 'S.L.O.P.', or Storage Level Override Protocol, completely disables the safety measures normally present in nanites, \ + allowing them to reach a whopping maximum volume level of 2000, but at the risk of causing damage to the host at nanite concentrations above the standard limit of 500." + use_rate = 0 + rogue_types = list(/datum/nanite_program/necrotic) + protocol_class = NANITE_PROTOCOL_STORAGE + var/extra_volume = 1500 + var/next_warning = 0 + var/min_warning_cooldown = 120 + var/max_warning_cooldown = 350 + var/volume_warnings_stage_1 = list("You feel a dull pain in your abdomen.", + "You feel a tickling sensation in your abdomen.") + var/volume_warnings_stage_2 = list("You feel a dull pain in your stomach.", + "You feel a dull pain when breathing.", + "Your stomach grumbles.", + "You feel a tickling sensation in your throat.", + "You feel a tickling sensation in your lungs.", + "You feel a tickling sensation in your stomach.", + "Your lungs feel stiff.") + var/volume_warnings_stage_3 = list("You feel a dull pain in your chest.", + "You hear a faint buzzing coming from nowhere.", + "You hear a faint buzzing inside your head.", + "Your head aches.") + var/volume_warnings_stage_4 = list("You feel a dull pain in your ears.", + "You feel a dull pain behind your eyes.", + "You hear a loud, echoing buzz inside your ears.", + "You feel dizzy.", + "You feel an itch coming from behind your eyes.", + "Your eardrums itch.", + "You see tiny grey motes drifting in your field of view.") + var/volume_warnings_stage_5 = list("You feel sick.", + "You feel a dull pain from every part of your body.", + "You feel nauseous.") + var/volume_warnings_stage_6 = list("Your skin itches and burns.", + "Your muscles ache.", + "You feel tired.", + "You feel something skittering under your skin.",) + +/datum/nanite_program/protocol/unsafe_storage/enable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites + extra_volume) + +/datum/nanite_program/protocol/unsafe_storage/disable_passive_effect() + . = ..() + nanites.set_max_volume(null, nanites.max_nanites - extra_volume) + +/datum/nanite_program/protocol/unsafe_storage/active_effect() + if(!iscarbon(host_mob)) + if(prob(10)) + host_mob.adjustBruteLoss(((max(nanites.nanite_volume - 450, 0) / 450) ** 2 ) * 0.5) // 0.5 -> 2 -> 4.5 -> 8 damage per successful tick + return + + var/mob/living/carbon/carbon = host_mob + + if(nanites.nanite_volume < 500) + return + + var/current_stage = 0 + if(nanites.nanite_volume > 500) //Liver is the main hub of nanite replication and the first to be threatened by excess volume + if(prob(10)) + var/obj/item/organ/liver/liver = carbon.get_organ_slot(ORGAN_SLOT_LIVER) + if(liver) + liver.apply_organ_damage(0.6) + current_stage++ + if(nanites.nanite_volume > 750) //Extra volume spills out in other central organs + if(prob(10)) + var/obj/item/organ/stomach/stomach = carbon.get_organ_slot(ORGAN_SLOT_STOMACH) + if(stomach) + stomach.apply_organ_damage(0.75) + if(prob(10)) + var/obj/item/organ/lungs/lungs = carbon.get_organ_slot(ORGAN_SLOT_LUNGS) + if(lungs) + lungs.apply_organ_damage(0.75) + current_stage++ + if(nanites.nanite_volume > 1000) //Extra volume spills out in more critical organs + if(prob(10)) + var/obj/item/organ/heart/heart = carbon.get_organ_slot(ORGAN_SLOT_HEART) + if(heart) + heart.apply_organ_damage(0.75) + if(prob(10)) + var/obj/item/organ/brain/brain = carbon.get_organ_slot(ORGAN_SLOT_BRAIN) + if(brain) + brain.apply_organ_damage(0.75) + current_stage++ + if(nanites.nanite_volume > 1250) //Excess nanites start invading smaller organs for more space, including sensory organs + if(prob(13)) + var/obj/item/organ/eyes/eyes = carbon.get_organ_slot(ORGAN_SLOT_EYES) + if(eyes) + eyes.apply_organ_damage(0.75) + if(prob(13)) + var/obj/item/organ/ears/ears = carbon.get_organ_slot(ORGAN_SLOT_EARS) + if(ears) + ears.apply_organ_damage(0.75) + current_stage++ + if(nanites.nanite_volume > 1500) //Nanites start spilling into the bloodstream, causing toxicity + if(prob(15)) + carbon.adjustToxLoss(0.5, TRUE, forced = TRUE) //Not healthy for slimepeople either + current_stage++ + if(nanites.nanite_volume > 1750) //Nanites have almost reached their physical limit, and the pressure itself starts causing tissue damage + if(prob(15)) + carbon.adjustBruteLoss(0.75, TRUE) + current_stage++ + + volume_warning(current_stage) + +/datum/nanite_program/protocol/unsafe_storage/proc/volume_warning(tier) + if(world.time < next_warning) + return + + var/list/main_warnings + var/list/extra_warnings + + switch(tier) + if(1) + main_warnings = volume_warnings_stage_1 + extra_warnings = null + if(2) + main_warnings = volume_warnings_stage_2 + extra_warnings = volume_warnings_stage_1 + if(3) + main_warnings = volume_warnings_stage_3 + extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + if(4) + main_warnings = volume_warnings_stage_4 + extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3 + if(5) + main_warnings = volume_warnings_stage_5 + extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3 + volume_warnings_stage_4 + if(6) + main_warnings = volume_warnings_stage_6 + extra_warnings = volume_warnings_stage_1 + volume_warnings_stage_2 + volume_warnings_stage_3 + volume_warnings_stage_4 + volume_warnings_stage_5 + + if(prob(35)) + to_chat(host_mob, span_warning("[pick(main_warnings)]")) + next_warning = world.time + rand(min_warning_cooldown, max_warning_cooldown) + else if(islist(extra_warnings)) + to_chat(host_mob, span_warning("[pick(extra_warnings)]")) + next_warning = world.time + rand(min_warning_cooldown, max_warning_cooldown) diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/rogue.dm b/modular_zubbers/code/modules/nanites/nanite_programs/rogue.dm new file mode 100644 index 00000000000..affe66e1b51 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/rogue.dm @@ -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_warning("You feel a mild ache from somewhere inside you.")) + +//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_warning("You feel a bit sick.")) + +//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_warning("You feel short of breath.")) + +//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.set_hallucinations_if_lower(15) + host_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 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.adjust_hallucinations(15) + if(2) + host_mob.adjust_confusion(10) + if(3) + host_mob.adjust_drowsiness(10) + if(4) + host_mob.adjust_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_warning("[host_mob] scratches [host_mob.p_their()] [bodypart.name].") : ""]",\ + span_warning("Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]")) + +//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_warning("You feel unbalanced!")) + host_mob.adjust_confusion(10) + else if(prob(4)) + to_chat(host_mob, span_warning("You can't feel your hands!")) + host_mob.drop_all_held_items() + else if(prob(4)) + to_chat(host_mob, span_warning("You can't feel your legs!")) + host_mob.Paralyze(30) diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/sensor.dm b/modular_zubbers/code/modules/nanites/nanite_programs/sensor.dm new file mode 100644 index 00000000000..916c2aa989a --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/sensor.dm @@ -0,0 +1,312 @@ +/datum/nanite_program/sensor + name = "Sensor Nanites" + desc = "These nanites send a signal code when a certain condition is met." + unique = FALSE + var/can_rule = FALSE + +/datum/nanite_program/sensor/register_extra_settings() + extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(0, 1, 9999) + +/datum/nanite_program/sensor/proc/check_event() + return FALSE + +/datum/nanite_program/sensor/proc/send_code() + if(activated) + var/datum/nanite_extra_setting/ES = extra_settings[NES_SENT_CODE] + SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, ES.value, "a [name] program") + +/datum/nanite_program/sensor/active_effect() + if(check_event()) + send_code() + +/datum/nanite_program/sensor/proc/make_rule(datum/nanite_program/target) + return + +/datum/nanite_program/sensor/repeat + name = "Signal Repeater" + desc = "When triggered, sends another signal to the nanites, optionally with a delay." + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 10 + var/spent = FALSE + +/datum/nanite_program/sensor/repeat/register_extra_settings() + . = ..() + extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s") + +/datum/nanite_program/sensor/repeat/on_trigger(comm_message) + var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] + addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10) + +/datum/nanite_program/sensor/relay_repeat + name = "Relay Signal Repeater" + desc = "When triggered, sends another signal to a relay channel, optionally with a delay." + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 10 + var/spent = FALSE + +/datum/nanite_program/sensor/relay_repeat/register_extra_settings() + . = ..() + extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999) + extra_settings[NES_DELAY] = new /datum/nanite_extra_setting/number(0, 0, 3600, "s") + +/datum/nanite_program/sensor/relay_repeat/on_trigger(comm_message) + var/datum/nanite_extra_setting/ES = extra_settings[NES_DELAY] + addtimer(CALLBACK(src, .proc/send_code), ES.get_value() * 10) + +/datum/nanite_program/sensor/relay_repeat/send_code() + var/datum/nanite_extra_setting/relay = extra_settings[NES_RELAY_CHANNEL] + if(activated && relay.get_value()) + for(var/X in SSnanites.nanite_relays) + var/datum/nanite_program/relay/N = X + var/datum/nanite_extra_setting/code = extra_settings[NES_SENT_CODE] + N.relay_signal(code.get_value(), relay.get_value(), "a [name] program") + +/datum/nanite_program/sensor/health + name = "Health Sensor" + desc = "The nanites receive a signal when the host's health is above/below a target percentage." + can_rule = TRUE + var/spent = FALSE + +/datum/nanite_program/sensor/health/register_extra_settings() + . = ..() + extra_settings[NES_HEALTH_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%") + extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below") + +/datum/nanite_program/sensor/health/check_event() + var/health_percent = host_mob.health / host_mob.maxHealth * 100 + var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/detected = FALSE + if(direction.get_value()) + if(health_percent >= percent.get_value()) + detected = TRUE + else + if(health_percent < percent.get_value()) + detected = TRUE + + if(detected) + if(!spent) + spent = TRUE + return TRUE + return FALSE + else + spent = FALSE + return FALSE + +/datum/nanite_program/sensor/health/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/health/rule = new(target) + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/datum/nanite_extra_setting/percent = extra_settings[NES_HEALTH_PERCENT] + rule.above = direction.get_value() + rule.threshold = percent.get_value() + return rule + +/datum/nanite_program/sensor/crit + name = "Critical Health Sensor" + desc = "The nanites receive a signal when the host first reaches critical health." + can_rule = TRUE + var/spent = FALSE + +/datum/nanite_program/sensor/crit/check_event() + if(HAS_TRAIT(host_mob, TRAIT_CRITICAL_CONDITION)) + if(spent) + return FALSE + spent = TRUE + return TRUE + spent = FALSE + return FALSE + + +/datum/nanite_program/sensor/crit/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/crit/rule = new(target) + return rule + +/datum/nanite_program/sensor/death + name = "Death Sensor" + desc = "The nanites receive a signal when they detect the host is dead." + can_rule = TRUE + var/spent = FALSE + +/datum/nanite_program/sensor/death/on_death() + send_code() + +/datum/nanite_program/sensor/death/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/death/rule = new(target) + return rule + +/datum/nanite_program/sensor/nanite_volume + name = "Nanite Volume Sensor" + desc = "The nanites receive a signal when the nanite supply is above/below a certain percentage." + can_rule = TRUE + var/spent = FALSE + +/datum/nanite_program/sensor/nanite_volume/register_extra_settings() + . = ..() + extra_settings[NES_NANITE_PERCENT] = new /datum/nanite_extra_setting/number(50, -99, 100, "%") + extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below") + +/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/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/detected = FALSE + if(direction.get_value()) + if(nanite_percent >= percent.get_value()) + detected = TRUE + else + if(nanite_percent < percent.get_value()) + detected = TRUE + + if(detected) + if(!spent) + spent = TRUE + return TRUE + return FALSE + else + spent = FALSE + return FALSE + +/datum/nanite_program/sensor/nanite_volume/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/nanites/rule = new(target) + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/datum/nanite_extra_setting/percent = extra_settings[NES_NANITE_PERCENT] + rule.above = direction.get_value() + rule.threshold = percent.get_value() + return rule + +/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." + can_rule = TRUE + var/spent = FALSE + +/datum/nanite_program/sensor/damage/register_extra_settings() + . = ..() + extra_settings[NES_DAMAGE_TYPE] = new /datum/nanite_extra_setting/type(BRUTE, list(BRUTE, BURN, TOX, OXY)) + extra_settings[NES_DAMAGE] = new /datum/nanite_extra_setting/number(50, 0, 500) + extra_settings[NES_DIRECTION] = new /datum/nanite_extra_setting/boolean(TRUE, "Above", "Below") + +/datum/nanite_program/sensor/damage/check_event() + var/reached_threshold = FALSE + var/datum/nanite_extra_setting/type = extra_settings[NES_DAMAGE_TYPE] + var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE] + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/check_above = direction.get_value() + var/damage_amt = 0 + switch(type.get_value()) + if(BRUTE) + damage_amt = host_mob.getBruteLoss() + if(BURN) + damage_amt = host_mob.getFireLoss() + if(TOX) + damage_amt = host_mob.getToxLoss() + if(OXY) + damage_amt = host_mob.getOxyLoss() + + if(check_above) + if(damage_amt >= damage.get_value()) + reached_threshold = TRUE + else + if(damage_amt < damage.get_value()) + reached_threshold = TRUE + + if(reached_threshold) + if(!spent) + spent = TRUE + return TRUE + return FALSE + else + spent = FALSE + return FALSE + +/datum/nanite_program/sensor/damage/make_rule(datum/nanite_program/target) + var/datum/nanite_rule/damage/rule = new(target) + var/datum/nanite_extra_setting/direction = extra_settings[NES_DIRECTION] + var/datum/nanite_extra_setting/damage_type = extra_settings[NES_DAMAGE_TYPE] + var/datum/nanite_extra_setting/damage = extra_settings[NES_DAMAGE] + rule.above = direction.get_value() + rule.threshold = damage.get_value() + rule.damage_type = damage_type.get_value() + return rule + +/datum/nanite_program/sensor/voice + name = "Voice Sensor" + desc = "The nanites receive a signal when they detect a specific, preprogrammed word or phrase being said." + +/datum/nanite_program/sensor/voice/register_extra_settings() + . = ..() + extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("") + extra_settings[NES_INCLUSIVE_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Inclusive", "Exclusive") + +/datum/nanite_program/sensor/voice/on_mob_add() + . = ..() + RegisterSignal(host_mob, COMSIG_MOVABLE_HEAR, .proc/on_hear) + +/datum/nanite_program/sensor/voice/on_mob_remove() + UnregisterSignal(host_mob, COMSIG_MOVABLE_HEAR) + +/datum/nanite_program/sensor/voice/proc/on_hear(datum/source, list/hearing_args) + SIGNAL_HANDLER + var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE] + var/datum/nanite_extra_setting/inclusive = extra_settings[NES_INCLUSIVE_MODE] + if(!sentence.get_value()) + return + if(inclusive.get_value()) + if(findtext(hearing_args[HEARING_RAW_MESSAGE], sentence.get_value())) + send_code() + else + if(LOWER_TEXT(hearing_args[HEARING_RAW_MESSAGE]) == LOWER_TEXT(sentence.get_value())) + send_code() + +/datum/nanite_program/sensor/species + name = "Species Sensor" + desc = "When triggered, the nanites scan the host to determine their species and receive a signal depending on the conditions set in the settings." + can_trigger = TRUE + trigger_cost = 0 + trigger_cooldown = 5 + + var/static/list/allowed_species = list( + "Human" = /datum/species/human, + "Lizard" = /datum/species/lizard, + "Moth" = /datum/species/moth, + "Ethereal" = /datum/species/ethereal, + "Pod" = /datum/species/pod, + "Fly" = /datum/species/fly, + "Felinid" = /datum/species/human/felinid, + "Jelly" = /datum/species/jelly, + ) + +/datum/nanite_program/sensor/species/register_extra_settings() + . = ..() + var/list/species_types = list() + for(var/name in allowed_species) + species_types += name + species_types += "Other" + extra_settings[NES_RACE] = new /datum/nanite_extra_setting/type("Human", species_types) + extra_settings[NES_MODE] = new /datum/nanite_extra_setting/boolean(TRUE, "Is", "Is Not") + +/datum/nanite_program/sensor/species/on_trigger(comm_message) + var/datum/nanite_extra_setting/species_type = extra_settings[NES_RACE] + var/species = allowed_species[species_type.get_value()] + var/species_match = FALSE + + if(species) + if(is_species(host_mob, species)) + species_match = TRUE + else //this is the check for the "Other" option + species_match = TRUE + for(var/name in allowed_species) + var/species_other = allowed_species[name] + if(is_species(host_mob, species_other)) + species_match = FALSE + break + + var/datum/nanite_extra_setting/mode = extra_settings[NES_MODE] + if(mode.get_value()) + if(species_match) + send_code() + else + if(!species_match) + send_code() diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm b/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm new file mode 100644 index 00000000000..ddd38bc9790 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm @@ -0,0 +1,292 @@ +//Programs that are generally useful for population control and non-harmful suppression. + +/datum/nanite_program/sleepy + name = "Sleep Induction" + desc = "The nanites induce rapid narcolepsy when triggered." + can_trigger = TRUE + trigger_cost = 15 + trigger_cooldown = 1200 + rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay) + +/datum/nanite_program/sleepy/on_trigger(comm_message) + to_chat(host_mob, span_warning("You start to feel very sleepy...")) + host_mob.adjust_drowsiness(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_warning("Your muscles seize! You can't move!")) + +/datum/nanite_program/paralyzing/disable_passive_effect() + . = ..() + to_chat(host_mob, span_notice("Your muscles relax, and you can move again.")) + +/datum/nanite_program/shocking + name = "Electric Shock" + desc = "The nanites shock the host when triggered. Destroys a large amount of nanites!" + can_trigger = TRUE + trigger_cost = 10 + trigger_cooldown = 300 + program_flags = NANITE_SHOCK_IMMUNE + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/shocking/on_trigger(comm_message) + host_mob.electrocute_act(rand(5,10), "shock nanites", 1, SHOCK_NOGLOVES) + +/datum/nanite_program/stun + name = "Neural Shock" + desc = "The nanites pulse the host's nerves when triggered, inapacitating them for a short period." + can_trigger = TRUE + trigger_cost = 4 + trigger_cooldown = 300 + rogue_types = list(/datum/nanite_program/shocking, /datum/nanite_program/nerve_decay) + +/datum/nanite_program/stun/on_trigger(comm_message) + playsound(host_mob, "sparks", 75, TRUE, -1, SHORT_RANGE_SOUND_EXTRARANGE) + host_mob.Paralyze(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() + . = ..() + ADD_TRAIT(host_mob, TRAIT_PACIFISM, NANITES_TRAIT) + +/datum/nanite_program/pacifying/disable_passive_effect() + . = ..() + REMOVE_TRAIT(host_mob, TRAIT_PACIFISM, NANITES_TRAIT) + +/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_TRAIT) + +/datum/nanite_program/blinding/disable_passive_effect() + . = ..() + host_mob.cure_blind(NANITES_TRAIT) + +/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() + . = ..() + ADD_TRAIT(host_mob, TRAIT_MUTE, NANITES_TRAIT) + +/datum/nanite_program/mute/disable_passive_effect() + . = ..() + REMOVE_TRAIT(host_mob, TRAIT_MUTE, NANITES_TRAIT) + +/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") + +//Can receive transmissions from a nanite communication remote for customized messages +/datum/nanite_program/comm + can_trigger = TRUE + var/comm_message = "" + +/datum/nanite_program/comm/register_extra_settings() + extra_settings[NES_COMM_CODE] = new /datum/nanite_extra_setting/number(0, 0, 9999) + +/datum/nanite_program/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source) + var/datum/nanite_extra_setting/comm_code = extra_settings[NES_COMM_CODE] + if(!activated || !comm_code.get_value()) + return + if(signal_comm_code == comm_code.get_value()) + host_mob.investigate_log("'s [name] nanite program was messaged by [comm_source] with comm code [signal_comm_code] and message '[comm_message]'.", INVESTIGATE_NANITES) + trigger(FALSE, comm_message) + +/datum/nanite_program/comm/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) + var/static/list/blacklist = list( + "*surrender", + "*collapse", + "*faint", + ) + +/datum/nanite_program/comm/speech/register_extra_settings() + . = ..() + extra_settings[NES_SENTENCE] = new /datum/nanite_extra_setting/text("") + +/datum/nanite_program/comm/speech/on_trigger(comm_message) + var/sent_message = comm_message + if(!comm_message) + var/datum/nanite_extra_setting/sentence = extra_settings[NES_SENTENCE] + sent_message = sentence.get_value() + if(sent_message in blacklist) + return + if(host_mob.stat == DEAD) + return + to_chat(host_mob, span_warning("You feel compelled to speak...")) + host_mob.say(sent_message, forced = "nanite speech") + +/datum/nanite_program/comm/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) + +/datum/nanite_program/comm/voice/register_extra_settings() + . = ..() + extra_settings[NES_MESSAGE] = new /datum/nanite_extra_setting/text("") + +/datum/nanite_program/comm/voice/on_trigger(comm_message) + var/sent_message = comm_message + if(!comm_message) + var/datum/nanite_extra_setting/message_setting = extra_settings[NES_MESSAGE] + sent_message = message_setting.get_value() + if(host_mob.stat == DEAD) + return + to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[span_robot("[sent_message]")]\"") + +/datum/nanite_program/comm/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) + var/list/hallucination_options = list( + "Message" = /datum/hallucination/chat, + "Battle" = /datum/hallucination/battle, + "Sound" = /datum/hallucination/fake_sound, + "Weird Sound" = /datum/hallucination/fake_sound/weird, + "Station Message" = /datum/hallucination/station_message, + "Health" = null, + "Alert" = /datum/hallucination/fake_alert, + "Fire" = /datum/hallucination/fire, + "Shock" = /datum/hallucination/shock, + "Plasma Flood" = /datum/hallucination/fake_flood, + "Random" = null + ) + +/datum/nanite_program/comm/hallucination/register_extra_settings() + . = ..() + var/list/options = assoc_to_keys(hallucination_options) + extra_settings[NES_HALLUCINATION_TYPE] = new /datum/nanite_extra_setting/type("Message", options) + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("") + +/datum/nanite_program/comm/hallucination/on_trigger(comm_message) + var/datum/nanite_extra_setting/hal_setting = extra_settings[NES_HALLUCINATION_TYPE] + var/hal_type = hal_setting.get_value() + var/datum/nanite_extra_setting/hal_detail_setting = extra_settings[NES_HALLUCINATION_DETAIL] + var/hal_details = hal_detail_setting.get_value() + if(comm_message && (hal_type != "Message")) //Triggered via comm remote, but not set to a message hallucination + return + var/sent_message = comm_message //Comm remotes can send custom hallucination messages for the chat hallucination + if(!sent_message) + sent_message = hal_details + + if(!iscarbon(host_mob)) + return + var/mob/living/carbon/carbon = host_mob + if(hal_details == "random") + hal_details = null + switch(hal_type) + if("Random") + carbon.adjust_hallucinations(15) + if("Health") + switch(hal_details) + if("critical") + carbon.adjust_timed_status_effect(3 MINUTES, /datum/status_effect/grouped/screwy_hud/fake_crit) + if("dead") + carbon.adjust_timed_status_effect(3 MINUTES, /datum/status_effect/grouped/screwy_hud/fake_dead) + if("healthy") + carbon.adjust_timed_status_effect(3 MINUTES, /datum/status_effect/grouped/screwy_hud/fake_healthy) + else if(hallucination_options[hal_type]) + carbon.cause_hallucination(hallucination_options[hal_type], TRUE, hal_details) + +/datum/nanite_program/comm/hallucination/set_extra_setting(setting, value) + . = ..() + if(setting == NES_HALLUCINATION_TYPE) + switch(value) + if("Message") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/text("") + if("Battle") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","laser","disabler","esword","gun","stunprod","harmbaton","bomb")) + if("Sound") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")) + if("Weird Sound") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","phone","hallelujah","highlander","laughter","hyperspace","game over","creepy","tesla")) + if("Station Message") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","ratvar","shuttle dock","blob alert","malf ai","meteors","supermatter")) + if("Health") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", list("random","critical","dead","healthy")) + if("Alert") + extra_settings[NES_HALLUCINATION_DETAIL] = new /datum/nanite_extra_setting/type("random", 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")) + else + extra_settings.Remove(NES_HALLUCINATION_DETAIL) + +/datum/nanite_program/good_mood + name = "Happiness Enhancer" + desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness." + use_rate = 0.1 + rogue_types = list(/datum/nanite_program/brain_decay) + +/datum/nanite_program/good_mood/register_extra_settings() + . = ..() + extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS ENHANCEMENT") + +/datum/nanite_program/good_mood/enable_passive_effect() + . = ..() + host_mob.add_mood_event("nanite_happy", /datum/mood_event/nanite_happiness, get_extra_setting_value(NES_MOOD_MESSAGE)) + +/datum/nanite_program/good_mood/disable_passive_effect() + . = ..() + host_mob.clear_mood_event("nanite_happy") + +/datum/nanite_program/bad_mood + name = "Happiness Suppressor" + desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression." + use_rate = 0.1 + rogue_types = list(/datum/nanite_program/brain_decay) + +/datum/nanite_program/bad_mood/register_extra_settings() + . = ..() + extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS SUPPRESSION") + +/datum/nanite_program/bad_mood/enable_passive_effect() + . = ..() + host_mob.add_mood_event("nanite_unhappy", /datum/mood_event/nanite_sadness, get_extra_setting_value(NES_MOOD_MESSAGE)) + +/datum/nanite_program/bad_mood/disable_passive_effect() + . = ..() + host_mob.add_mood_event("nanite_unhappy") diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm b/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm new file mode 100644 index 00000000000..77567fd5e1e --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm @@ -0,0 +1,331 @@ +//Programs that interact with other programs or nanites directly, or have other special purposes. +/datum/nanite_program/viral + name = "Viral Replica" + desc = "The nanites constantly send encrypted signals attempting to forcefully copy their own programming into other nanite clusters, also overriding or disabling their cloud sync." + use_rate = 0.5 + rogue_types = list(/datum/nanite_program/toxic) + var/pulse_cooldown = 0 + +/datum/nanite_program/viral/register_extra_settings() + extra_settings[NES_PROGRAM_OVERWRITE] = new /datum/nanite_extra_setting/type("Add To", list("Overwrite", "Add To", "Ignore")) + extra_settings[NES_CLOUD_OVERWRITE] = new /datum/nanite_extra_setting/number(0, 0, 100) + +/datum/nanite_program/viral/active_effect() + if(world.time < pulse_cooldown) + return + var/datum/nanite_extra_setting/program = extra_settings[NES_PROGRAM_OVERWRITE] + var/datum/nanite_extra_setting/cloud = extra_settings[NES_CLOUD_OVERWRITE] + for(var/mob/M in orange(host_mob, 5)) + if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY)) + continue + switch(program.get_value()) + if("Overwrite") + SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, TRUE) + if("Add To") + SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, FALSE) + SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, cloud.get_value()) + pulse_cooldown = world.time + 75 + +/datum/nanite_program/monitoring + name = "Monitoring" + desc = "The nanites monitor the host's vitals and location, sending them to the suit sensor network." + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/monitoring/enable_passive_effect() + . = ..() + ADD_TRAIT(host_mob, TRAIT_NANITE_MONITORING, NANITES_TRAIT) //Shows up in diagnostic and medical HUDs as a small blinking icon + if(ishuman(host_mob)) + GLOB.nanite_sensors_list |= host_mob + host_mob.hud_set_nanite_indicator() + +/datum/nanite_program/monitoring/disable_passive_effect() + . = ..() + REMOVE_TRAIT(host_mob, TRAIT_NANITE_MONITORING, "nanites") + if(ishuman(host_mob)) + GLOB.nanite_sensors_list -= host_mob + + host_mob.hud_set_nanite_indicator() + +/datum/nanite_program/self_scan + name = "Host Scan" + desc = "The nanites display a detailed readout of a body scan to the host." + unique = FALSE + can_trigger = TRUE + trigger_cost = 3 + trigger_cooldown = 50 + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/self_scan/register_extra_settings() + extra_settings[NES_SCAN_TYPE] = new /datum/nanite_extra_setting/type("Medical", list("Medical", "Chemical", "Wound", "Nanite")) + +/datum/nanite_program/self_scan/on_trigger(comm_message) + if(host_mob.stat == DEAD) + return + var/datum/nanite_extra_setting/NS = extra_settings[NES_SCAN_TYPE] + switch(NS.get_value()) + if("Medical") + healthscan(host_mob, host_mob) + if("Chemical") + chemscan(host_mob, host_mob) + if("Wound") + woundscan(host_mob, host_mob) + if("Nanite") + SEND_SIGNAL(host_mob, COMSIG_NANITE_SCAN, host_mob, TRUE) + +/datum/nanite_program/stealth + name = "Stealth" + desc = "The nanites mask their activity from superficial scans, becoming undetectable by HUDs and non-specialized scanners." + rogue_types = list(/datum/nanite_program/toxic) + use_rate = 0.2 + +/datum/nanite_program/stealth/enable_passive_effect() + . = ..() + nanites.stealth = TRUE + +/datum/nanite_program/stealth/disable_passive_effect() + . = ..() + nanites.stealth = FALSE + +/datum/nanite_program/nanite_debugging + name = "Nanite Debugging" + desc = "Enables various high-cost diagnostics in the nanites, making them able to communicate their program list to portable scanners. \ + Doing so uses some power, slightly decreasing their replication speed." + rogue_types = list(/datum/nanite_program/toxic) + use_rate = 0.1 + +/datum/nanite_program/nanite_debugging/enable_passive_effect() + . = ..() + nanites.diagnostics = TRUE + +/datum/nanite_program/nanite_debugging/disable_passive_effect() + . = ..() + nanites.diagnostics = FALSE + +/datum/nanite_program/relay + name = "Relay" + desc = "The nanites receive and relay long-range nanite signals." + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/relay/register_extra_settings() + extra_settings[NES_RELAY_CHANNEL] = new /datum/nanite_extra_setting/number(1, 1, 9999) + +/datum/nanite_program/relay/enable_passive_effect() + . = ..() + SSnanites.nanite_relays |= src + +/datum/nanite_program/relay/disable_passive_effect() + . = ..() + SSnanites.nanite_relays -= src + +/datum/nanite_program/relay/proc/relay_signal(code, relay_code, source) + if(!activated) + return + if(!host_mob) + return + var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL] + if(relay_code != NS.get_value()) + return + SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source) + +/datum/nanite_program/relay/proc/relay_comm_signal(comm_code, relay_code, comm_message) + if(!activated) + return + if(!host_mob) + return + var/datum/nanite_extra_setting/NS = extra_settings[NES_RELAY_CHANNEL] + if(relay_code != NS.get_value()) + return + SEND_SIGNAL(host_mob, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message) + +/datum/nanite_program/metabolic_synthesis + name = "Metabolic Synthesis" + desc = "The nanites use the metabolic cycle of the host to speed up their replication rate, using their extra nutrition as fuel." + use_rate = -0.5 //generates nanites + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/metabolic_synthesis/check_conditions() + if(!iscarbon(host_mob)) + return FALSE + var/mob/living/carbon/C = host_mob + if(C.nutrition <= NUTRITION_LEVEL_WELL_FED) + return FALSE + return ..() + +/datum/nanite_program/metabolic_synthesis/active_effect() + host_mob.adjust_nutrition(-0.5) + +/datum/nanite_program/access + name = "Subdermal ID" + desc = "The nanites store the host's ID access rights in a subdermal magnetic strip. Updates when triggered, copying the host's current access." + can_trigger = TRUE + trigger_cost = 3 + trigger_cooldown = 30 + rogue_types = list(/datum/nanite_program/skin_decay) + var/access = list() + +//Syncs the nanites with the cumulative current mob's access level. Can potentially wipe existing access. +/datum/nanite_program/access/on_trigger(comm_message) + var/list/potential_items = list() + + potential_items += host_mob.get_active_held_item() + potential_items += host_mob.get_inactive_held_item() + potential_items += host_mob.pulling + + if(ishuman(host_mob)) + var/mob/living/carbon/human/H = host_mob + potential_items += H.wear_id + else if(isanimal(host_mob)) + var/mob/living/simple_animal/A = host_mob + potential_items += A.access_card + + var/list/new_access = list() + for(var/obj/item/I in potential_items) + new_access += I.GetAccess() + + access = new_access + +/datum/nanite_program/spreading + name = "Infective Exo-Locomotion" + desc = "The nanites gain the ability to survive for brief periods outside of the human body, as well as the ability to start new colonies without an integration process; \ + resulting in an extremely infective strain of nanites." + use_rate = 1.50 + rogue_types = list(/datum/nanite_program/aggressive_replication, /datum/nanite_program/necrotic) + var/spread_cooldown = 0 + +/datum/nanite_program/spreading/active_effect() + if(world.time < spread_cooldown) + return + spread_cooldown = world.time + 50 + var/list/mob/living/target_hosts = list() + for(var/mob/living/L in oview(5, host_mob)) + if(!prob(25)) + continue + if(!CAN_HAVE_NANITES(L)) + continue + target_hosts += L + if(!target_hosts.len) + return + var/mob/living/infectee = pick(target_hosts) + if(prob(100 - infectee.getarmor(null, BIO))) + //this will potentially take over existing nanites! + infectee.AddComponent(/datum/component/nanites, 10) + SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites) + SEND_SIGNAL(infectee, COMSIG_NANITE_SET_CLOUD, nanites.cloud_id) + infectee.investigate_log("was infected by spreading nanites with cloud ID [nanites.cloud_id] by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES) + +/datum/nanite_program/nanite_sting + name = "Nanite Sting" + desc = "When triggered, builds a invisible spikes of nanites on the host's skin that \ + can infect a nearby non-host with a copy of the host's nanites cluster \ + that is unlinked from the cloud. \ + Will not work on hosts or those already infected." + can_trigger = TRUE + trigger_cost = 5 + trigger_cooldown = 100 + rogue_types = list(/datum/nanite_program/glitch, /datum/nanite_program/toxic) + var/decay_timer + +/datum/nanite_program/nanite_sting/Destroy() + . = ..() + if(!decay_timer) + return + decay_sting() + +/datum/nanite_program/nanite_sting/on_trigger(comm_message) + consume_nanites(-15) + to_chat(host_mob, span_warning("Your hands becomes sharp and prickly.")) + RegisterSignal(host_mob, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) + decay_timer = addtimer(CALLBACK(src, PROC_REF(decay_sting)), 30 SECONDS, TIMER_STOPPABLE) + +/datum/nanite_program/nanite_sting/proc/on_attack_hand(atom/source, mob/user, modifiers) + SIGNAL_HANDLER + var/mob/living/living = source + if(!istype(living)) return + if(!CAN_HAVE_NANITES(living) || SEND_SIGNAL(living, COMSIG_HAS_NANITES) || !living.Adjacent(host_mob)) return + + if(prob(100 - living.getarmor(null, BIO))) + //unlike with Infective Exo-Locomotion, this can't take over existing nanites, because Nanite Sting only targets non-hosts. + living.AddComponent(/datum/component/nanites, 5) + SEND_SIGNAL(living, COMSIG_NANITE_SYNC, nanites) + // SEND_SIGNAL(living, COMSIG_NANITE_SET_CLOUD, nanites.cloud_id) won't set the cloud + // SEND_SIGNAL(living, COMSIG_NANITE_SET_CLOUD_SYNC, NANITE_CLOUD_DISABLE) + living.investigate_log("was infected by a nanite cluster with cloud ID [nanites.cloud_id] by [key_name(host_mob)] at [AREACOORD(living)].", INVESTIGATE_NANITES) + to_chat(living, span_warning("You feel a tiny prick.")) + decay_sting() + +/datum/nanite_program/nanite_sting/proc/decay_sting() + to_chat(host_mob, span_warning("Your hands no longer feel like they're covered in spines.")) + deltimer(decay_timer) + decay_timer = null + UnregisterSignal(host_mob, COMSIG_LIVING_EARLY_UNARMED_ATTACK) + +/datum/nanite_program/mitosis + name = "Mitosis" + desc = "The nanites gain the ability to self-replicate, using bluespace to power the process. Becomes more effective the more nanites are already in the host; \ + For every 50 nanite volume in the host, the production rate is increased by 0.5. The replication has also a chance to corrupt the nanite programming \ + due to copy faults - constant cloud sync is highly recommended." + use_rate = 0 + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/mitosis/active_effect() + var/rep_rate = round(nanites.nanite_volume / 50, 1) //0.5 per 50 nanite volume + rep_rate *= 0.5 + nanites.adjust_nanites(null, rep_rate) + if(prob(rep_rate)) + var/datum/nanite_program/fault = pick(nanites.programs) + if(fault == src) + return + fault.software_error() + host_mob.investigate_log("[fault] nanite program received a software error due to Mitosis program.", INVESTIGATE_NANITES) + +/datum/nanite_program/dermal_button + name = "Dermal Button" + desc = "Displays a button on the host's skin, which can be used to send a signal to the nanites." + unique = FALSE + var/datum/action/innate/nanite_button/button + +/datum/nanite_program/dermal_button/register_extra_settings() + extra_settings[NES_SENT_CODE] = new /datum/nanite_extra_setting/number(1, 1, 9999) + extra_settings[NES_BUTTON_NAME] = new /datum/nanite_extra_setting/text("Button") + extra_settings[NES_ICON] = new /datum/nanite_extra_setting/type("power", list("blank","one","two","three","four","five","plus","minus","exclamation","question","cross","info","heart","skull","brain","brain_damage","injection","blood","shield","reaction","network","power","radioactive","electricity","magnetism","scan","repair","id","wireless","say","sleep","bomb")) + +/datum/nanite_program/dermal_button/enable_passive_effect() + . = ..() + var/datum/nanite_extra_setting/bn_name = extra_settings[NES_BUTTON_NAME] + var/datum/nanite_extra_setting/bn_icon = extra_settings[NES_ICON] + if(!button) + button = new(src, bn_name.get_value(), bn_icon.get_value()) + button.target = host_mob + button.Grant(host_mob) + +/datum/nanite_program/dermal_button/disable_passive_effect() + . = ..() + if(button) + button.Remove(host_mob) + +/datum/nanite_program/dermal_button/on_mob_remove() + . = ..() + QDEL_NULL(button) + +/datum/nanite_program/dermal_button/proc/press() + if(activated) + host_mob.visible_message(span_notice("[host_mob] presses a button on [host_mob.p_their()] forearm."), + span_notice("You press the nanite button on your forearm."), null, 2) + var/datum/nanite_extra_setting/sent_code = extra_settings[NES_SENT_CODE] + SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, sent_code.get_value(), "a [name] program") + +/datum/action/innate/nanite_button + name = "Button" + button_icon = 'icons/mob/actions/actions_items.dmi' + check_flags = AB_CHECK_HANDS_BLOCKED|AB_CHECK_IMMOBILE|AB_CHECK_CONSCIOUS + button_icon_state = "bci_power" + var/datum/nanite_program/dermal_button/program + +/datum/action/innate/nanite_button/New(datum/nanite_program/dermal_button/_program, _name, _icon) + ..() + program = _program + name = _name + button_icon_state = "bci_[_icon]" + +/datum/action/innate/nanite_button/Activate() + program.press() diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/weapon.dm b/modular_zubbers/code/modules/nanites/nanite_programs/weapon.dm new file mode 100644 index 00000000000..f71a101ad97 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_programs/weapon.dm @@ -0,0 +1,186 @@ +//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, TRUE) + else + host_mob.adjustBruteLoss(1, TRUE) + if(prob(3)) + to_chat(host_mob, span_warning("You feel a stab of pain from somewhere inside you.")) + +/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_warning("You feel nauseous.")) + 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() + host_mob.investigate_log("[target] nanite program received a software error due to Memory Leak program.", INVESTIGATE_NANITES) + +/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, \ + and scaling linearly for a net positive of 0.1 production rate per 20 nanite volume beyond that." + 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(null, 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_userdanger("Your blood is burning!")) + nanites.safety_threshold = 0 + +/datum/nanite_program/meltdown/disable_passive_effect() + . = ..() + to_chat(host_mob, span_warning("Your blood cools down, and the pain gradually fades.")) + +/datum/nanite_program/explosive + name = "Chain Detonation" + desc = "Detonates all the nanites inside the host in a chain reaction when triggered." + can_trigger = TRUE + 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/explosive/on_trigger(comm_message) + host_mob.visible_message(span_warning("[host_mob] starts emitting a high-pitched buzzing, and [host_mob.p_their()] skin begins to glow..."),\ + span_userdanger("You start emitting a high-pitched buzzing, and your skin begins to glow...")) + addtimer(CALLBACK(src, .proc/boom), clamp((nanites.nanite_volume * 0.35), 25, 150)) + +/datum/nanite_program/explosive/proc/boom() + dyn_explosion(host_mob, nanites.nanite_volume / 50) + qdel(nanites) + +//TODO make it defuse if triggered again + +/datum/nanite_program/heart_stop + name = "Heart-Stopper" + desc = "Stops the host's heart when triggered; restarts it if triggered again." + can_trigger = TRUE + trigger_cost = 12 + trigger_cooldown = 10 + rogue_types = list(/datum/nanite_program/nerve_decay) + +/datum/nanite_program/heart_stop/on_trigger(comm_message) + if(iscarbon(host_mob)) + var/mob/living/carbon/carbon = host_mob + var/obj/item/organ/heart/heart = carbon.get_organ_slot(ORGAN_SLOT_HEART) + if(heart) + if(heart.is_beating()) + heart.Stop() + else + heart.Restart() + +/datum/nanite_program/emp + name = "Electromagnetic Resonance" + desc = "The nanites cause an electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!" + can_trigger = TRUE + trigger_cost = 10 + trigger_cooldown = 50 + program_flags = NANITE_EMP_IMMUNE + rogue_types = list(/datum/nanite_program/toxic) + +/datum/nanite_program/emp/on_trigger(comm_message) + empulse(host_mob, 1, 2) + +/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.adjust_fire_stacks(1) + host_mob.ignite_mob() + +/datum/nanite_program/cryo + name = "Cryogenic Treatment" + desc = "The nanites rapidly sink 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/comm/mind_control + name = "Mind Control" + desc = "The nanites imprint an absolute directive onto the host's brain for one minute when triggered." + trigger_cost = 30 + trigger_cooldown = 1800 + rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire) + +/datum/nanite_program/comm/mind_control/register_extra_settings() + . = ..() + extra_settings[NES_DIRECTIVE] = new /datum/nanite_extra_setting/text("...") + +/datum/nanite_program/comm/mind_control/on_trigger(comm_message) + if(host_mob.stat == DEAD) + return + var/sent_directive = comm_message + if(!comm_message) + var/datum/nanite_extra_setting/ES = extra_settings[NES_DIRECTIVE] + sent_directive = ES.get_value() + brainwash(host_mob, sent_directive) + log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[sent_directive]'.") + host_mob.log_message("has been brainwashed with the objective '[sent_directive]' triggered by a mind control nanite program.", LOG_ATTACK) + addtimer(CALLBACK(src, .proc/end_brainwashing), 600) + +/datum/nanite_program/comm/mind_control/proc/end_brainwashing() + if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed)) + host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed) + log_game("[key_name(host_mob)] is no longer brainwashed by nanites.") + +/datum/nanite_program/comm/mind_control/disable_passive_effect() + . = ..() + end_brainwashing() diff --git a/modular_zubbers/code/modules/nanites/nanite_sign.dm b/modular_zubbers/code/modules/nanites/nanite_sign.dm new file mode 100644 index 00000000000..f849aca4e1c --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_sign.dm @@ -0,0 +1,9 @@ +/obj/structure/sign/departments/nanites + name = "\improper Nanite Lab sign" + icon = 'modular_zubbers/icons/obj/signs/nanite_sign.dmi' + icon_state = "nanites" + sign_change_name = "Department - Science: Nanites" + desc = "A sign labelling an area where testing and development of nanites is performed." + is_editable = TRUE + +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/nanites, 32) diff --git a/modular_zubbers/code/modules/nanites/nanite_symptom.dm b/modular_zubbers/code/modules/nanites/nanite_symptom.dm new file mode 100644 index 00000000000..1ca11b28e27 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/nanite_symptom.dm @@ -0,0 +1,71 @@ +/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_descs = list( + "Transmission 5" = "Increases the virus' growth rate while nanites are present.", + "Stage Speed 7" = "Increases the replication boost." + ) + +/datum/symptom/nano_boost/Start(datum/disease/advance/A) + . = ..() + if(!.) + return + if(A.totalTransmittable() >= 5) //reverse boost + reverse_boost = TRUE + if(A.totalStageSpeed() >= 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_descs = list( + "Stage Speed 5" = "Increases the virus' growth rate while nanites are present.", + "Resistance 7" = "Severely increases the rate at which the nanites are destroyed." + ) + +/datum/symptom/nano_destroy/Start(datum/disease/advance/A) + . = ..() + if(!.) + return + if(A.totalStageSpeed() >= 5) //reverse boost + reverse_boost = TRUE + if(A.totalResistance() >= 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) diff --git a/modular_zubbers/code/modules/nanites/program_designs.dm b/modular_zubbers/code/modules/nanites/program_designs.dm new file mode 100644 index 00000000000..6dbfb469664 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/program_designs.dm @@ -0,0 +1,573 @@ +/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 = 'modular_zubbers/icons/obj/devices/nanite_devices.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/self_scan + category = list("Utility Nanites") + +/datum/design/nanites/dermal_button + name = "Dermal Button" + desc = "Displays a button on the host's skin, which can be used to send a signal to the nanites." + id = "dermal_button_nanites" + program_type = /datum/nanite_program/dermal_button + 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/nanite_debugging + name = "Nanite Debugging" + desc = "Enables various high-cost diagnostics in the nanites, making them able to communicate their program list to portable scanners. \ + Doing so uses some power, slightly decreasing their replication speed." + id = "debugging_nanites" + program_type = /datum/nanite_program/nanite_debugging + 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/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 electromagnetic pulse around the host when triggered. Will corrupt other nanite programs!" + id = "emp_nanites" + program_type = /datum/nanite_program/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/nanite_sting + name = "Nanite Sting" + desc = "When triggered, projects a nearly invisible spike of nanites that attempts to infect a nearby non-host with a copy of the host's nanites cluster." + id = "nanite_sting_nanites" + program_type = /datum/nanite_program/nanite_sting + 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." + 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/regenerative/robotic + 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/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/dermal_armor + 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/dermal_armor/refractive + category = list("Augmentation Nanites") + +/datum/design/nanites/coagulating + name = "Vein Repressurization" + desc = "The nanites re-route circulating blood away from open wounds, dramatically reducing bleeding rate." + id = "coagulating_nanites" + program_type = /datum/nanite_program/coagulating + category = list("Augmentation Nanites") + +/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/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/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/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/comm/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/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/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/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/comm/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/comm/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/comm/hallucination + category = list("Suppression Nanites") + +/datum/design/nanites/good_mood + name = "Happiness Enhancer" + desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness." + id = "good_mood_nanites" + program_type = /datum/nanite_program/good_mood + category = list("Suppression Nanites") + +/datum/design/nanites/bad_mood + name = "Happiness Suppressor" + desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression." + id = "bad_mood_nanites" + program_type = /datum/nanite_program/bad_mood + category = list("Suppression Nanites") + +////////////////////SENSOR NANITES////////////////////////////////////// + +/datum/design/nanites/sensor_health + 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") + +/datum/design/nanites/sensor_species + name = "Species Sensor" + desc = "When triggered, the nanites scan the host to determine their species and output a signal depending on the conditions set in the settings." + id = "sensor_species_nanites" + program_type = /datum/nanite_program/sensor/species + category = list("Sensor Nanites") + +////////////////////NANITE PROTOCOLS////////////////////////////////////// +//Note about the category name: The UI cuts the last 8 characters from the category name to remove the " Nanites" in the other categories +//Because of this, Protocols was getting cut down to "P", so i had to add some padding +/datum/design/nanites/kickstart + name = "Kickstart Protocol" + desc = "Replication Protocol: the nanites focus on early growth, heavily boosting replication rate for a few minutes after the initial implantation." + id = "kickstart_nanites" + program_type = /datum/nanite_program/protocol/kickstart + category = list("Protocols_Nanites") + +/datum/design/nanites/factory + name = "Factory Protocol" + desc = "Replication Protocol: the nanites build a factory matrix within the host, gradually increasing replication speed over time. The factory decays if the protocol is not active." + id = "factory_nanites" + program_type = /datum/nanite_program/protocol/factory + category = list("Protocols_Nanites") + +/datum/design/nanites/pyramid + name = "Pyramid Protocol" + desc = "Replication Protocol: the nanites implement an alternate cooperative replication protocol that is more efficient as long as the saturation level is above 80%." + id = "pyramid_nanites" + program_type = /datum/nanite_program/protocol/pyramid + category = list("Protocols_Nanites") + +/datum/design/nanites/offline + name = "Eclipse Protocol" + desc = "Replication Protocol: while the host is asleep or otherwise unconcious, the nanites exploit the reduced interference to replicate more quickly." + id = "offline_nanites" + program_type = /datum/nanite_program/protocol/offline + category = list("Protocols_Nanites") + +/datum/design/nanites/hive + name = "Hive Protocol" + desc = "Storage Protocol: the nanites use a more efficient grid arrangment for volume storage, increasing maximum volume in a host." + id = "hive_nanites" + program_type = /datum/nanite_program/protocol/hive + category = list("Protocols_Nanites") + +/datum/design/nanites/zip + name = "Zip Protocol" + desc = "Storage Protocol: the nanites are disassembled and compacted when unused, greatly increasing the maximum volume while in a host. However, the process slows down the replication rate slightly." + id = "zip_nanites" + program_type = /datum/nanite_program/protocol/zip + category = list("Protocols_Nanites") + +/datum/design/nanites/free_range + name = "Free-range Protocol" + desc = "Storage Protocol: the nanites discard their default storage protocols in favour of a cheaper and more organic approach. Reduces maximum volume, but increases the replication rate." + id = "free_range_nanites" + program_type = /datum/nanite_program/protocol/free_range + category = list("Protocols_Nanites") + +/datum/design/nanites/unsafe_storage + name = "S.L.O. Protocol" + desc = "Storage Protocol: 'S.L.O.P.', or Storage Level Override Protocol, completely disables the safety measures normally present in nanites,\ + allowing them to reach much higher saturation levels, but at the risk of causing internal damage to the host." + id = "unsafe_storage_nanites" + program_type = /datum/nanite_program/protocol/unsafe_storage + category = list("Protocols_Nanites") diff --git a/modular_zubbers/code/modules/nanites/rules.dm b/modular_zubbers/code/modules/nanites/rules.dm new file mode 100644 index 00000000000..79723ca5b03 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/rules.dm @@ -0,0 +1,148 @@ +/datum/nanite_rule + var/name = "Generic Condition" + var/desc = "When triggered, the program is active" + var/datum/nanite_program/program + +/datum/nanite_rule/New(datum/nanite_program/new_program) + program = new_program + if(LAZYLEN(new_program.rules) <= 5) //Avoid infinite stacking rules + new_program.rules += src + else + qdel(src) + +/datum/nanite_rule/proc/remove() + program.rules -= src + program = null + qdel(src) + +/datum/nanite_rule/proc/check_rule() + return TRUE + +/datum/nanite_rule/proc/display() + return name + +/datum/nanite_rule/proc/copy_to(datum/nanite_program/new_program) + new type(new_program) + +/datum/nanite_rule/health + name = "Health" + desc = "Checks the host's health status." + + var/threshold = 50 + var/above = TRUE + +/datum/nanite_rule/health/check_rule() + var/health_percent = program.host_mob.health / program.host_mob.maxHealth * 100 + if(above) + if(health_percent >= threshold) + return TRUE + else + if(health_percent < threshold) + return TRUE + return FALSE + +/datum/nanite_rule/health/display() + return "[name] [above ? ">" : "<"] [threshold]%" + +/datum/nanite_rule/health/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/health/rule = new(new_program) + rule.above = above + rule.threshold = threshold + +//TODO allow inversion +/datum/nanite_rule/crit + name = "Crit" + desc = "Checks if the host is in critical condition." + +/datum/nanite_rule/crit/check_rule() + return HAS_TRAIT(program.host_mob, TRAIT_CRITICAL_CONDITION) + + +/datum/nanite_rule/death + name = "Death" + desc = "Checks if the host is dead." + +/datum/nanite_rule/death/check_rule() + if(program.host_mob.stat == DEAD || HAS_TRAIT(program.host_mob, TRAIT_FAKEDEATH)) + return TRUE + return FALSE + +/datum/nanite_rule/cloud_sync + name = "Cloud Sync" + desc = "Checks if the nanites have cloud sync enabled or disabled." + var/check_type = "Enabled" + +/datum/nanite_rule/cloud_sync/check_rule() + if(check_type == "Enabled") + return program.nanites.cloud_active + else + return !program.nanites.cloud_active + +/datum/nanite_rule/cloud_sync/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/cloud_sync/rule = new(new_program) + rule.check_type = check_type + +/datum/nanite_rule/cloud_sync/display() + return "[name]:[check_type]" + +/datum/nanite_rule/nanites + name = "Nanite Volume" + desc = "Checks the host's nanite volume." + + var/threshold = 50 + var/above = TRUE + +/datum/nanite_rule/nanites/check_rule() + var/nanite_percent = (program.nanites.nanite_volume - program.nanites.safety_threshold)/(program.nanites.max_nanites - program.nanites.safety_threshold)*100 + if(above) + if(nanite_percent >= threshold) + return TRUE + else + if(nanite_percent < threshold) + return TRUE + return FALSE + +/datum/nanite_rule/nanites/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/nanites/rule = new(new_program) + rule.above = above + rule.threshold = threshold + +/datum/nanite_rule/nanites/display() + return "[name] [above ? ">" : "<"] [threshold]%" + +/datum/nanite_rule/damage + name = "Damage" + desc = "Checks the host's damage." + + var/threshold = 50 + var/above = TRUE + var/damage_type = BRUTE + +/datum/nanite_rule/damage/check_rule() + var/damage_amt = 0 + switch(damage_type) + if(BRUTE) + damage_amt = program.host_mob.getBruteLoss() + if(BURN) + damage_amt = program.host_mob.getFireLoss() + if(TOX) + damage_amt = program.host_mob.getToxLoss() + if(OXY) + damage_amt = program.host_mob.getOxyLoss() + + if(above) + if(damage_amt >= threshold) + return TRUE + else + if(damage_amt < threshold) + return TRUE + return FALSE + +/datum/nanite_rule/damage/copy_to(datum/nanite_program/new_program) + var/datum/nanite_rule/damage/rule = new(new_program) + rule.above = above + rule.threshold = threshold + rule.damage_type = damage_type + +/datum/nanite_rule/damage/display() + return "[damage_type] [above ? ">" : "<"] [threshold]" diff --git a/modular_zubbers/code/modules/nanites/spawners.dm b/modular_zubbers/code/modules/nanites/spawners.dm new file mode 100644 index 00000000000..d0a775cfa6a --- /dev/null +++ b/modular_zubbers/code/modules/nanites/spawners.dm @@ -0,0 +1,11 @@ + +/obj/effect/spawner/random/techstorage/rnd_all/Initialize(mapload) + loot += list( + /obj/item/circuitboard/computer/nanite_chamber_control, + /obj/item/circuitboard/computer/nanite_cloud_controller, + /obj/item/circuitboard/machine/nanite_chamber, + /obj/item/circuitboard/machine/nanite_programmer, + /obj/item/circuitboard/machine/nanite_program_hub, + /obj/item/circuitboard/computer/scan_consolenew, + ) + . = ..() diff --git a/modular_zubbers/code/modules/nanites/techweb_nodes.dm b/modular_zubbers/code/modules/nanites/techweb_nodes.dm new file mode 100644 index 00000000000..8aebe364c94 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/techweb_nodes.dm @@ -0,0 +1,180 @@ +/datum/techweb_node/nanite_base + id = "nanite_base" + display_name = "Basic Nanite Programming" + description = "The basics of nanite construction and programming. Nanites will passively generate science points based on how many are hosting them." + prereq_ids = list(TECHWEB_NODE_BCI) + design_ids = list( + // "access_nanites", + "debugging_nanites", + "monitoring_nanites", + "nanite_chamber", + "nanite_chamber_control", + "nanite_cloud_control", + "nanite_comm_remote", + "nanite_disk", + "nanite_program_hub", + "nanite_programmer", + "nanite_remote", + "nanite_scanner", + "public_nanite_chamber", + "relay_nanites", + "relay_repeater_nanites", + "repairing_nanites", + "repeater_nanites", + "sensor_nanite_volume", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/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", TECHWEB_NODE_PROGRAMMING) + design_ids = list( + "memleak_nanites", + "metabolic_nanites", + "purging_nanites", + "sensor_voice_nanites", + "stealth_nanites", + "voice_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_1_POINTS) + +/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", TECHWEB_NODE_MOD_ENGI_ADV) + design_ids = list( + "conductive_nanites", + "cryo_nanites", + "dermal_button_nanites", + "emp_nanites", + "hardening_nanites", + "refractive_nanites", + "shock_nanites", + "temperature_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_2_POINTS) + +/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", TECHWEB_NODE_MOD_MEDICAL_ADV) + design_ids = list( + "bloodheal_nanites", + "coagulating_nanites", + "flesheating_nanites", + "poison_nanites", + "sensor_crit_nanites", + "sensor_damage_nanites", + "sensor_death_nanites", + "sensor_health_nanites", + "sensor_species_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_3_POINTS) + +/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( + "bad_mood_nanites", + "brainheal_nanites", + "good_mood_nanites", + "nervous_nanites", + "paralyzing_nanites", + "selfscan_nanites", + "stun_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_1_POINTS) + +/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", TECHWEB_NODE_SURGERY_EXP) + design_ids = list( + "blinding_nanites", + "hallucination_nanites", + "mindshield_nanites", + "mute_nanites", + "pacifying_nanites", + "sleep_nanites", + // "speech_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/nanite_harmonic + id = "nanite_harmonic" + display_name = "Harmonic Nanite Programming" + description = "Nanite programs that require seamless integration between nanites and biology. Passively increases nanite regeneration rate for all clouds upon researching." + prereq_ids = list("nanite_bio","nanite_smart","nanite_mesh") + design_ids = list( + "regenerative_nanites", + "aggressive_nanites", + "brainheal_plus_nanites", + "defib_nanites", + "fakedeath_nanites", + "purging_plus_nanites", + // "regenerative_plus_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_2_POINTS) + +/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", TECHWEB_NODE_SYNDICATE_BASIC) + design_ids = list( + // "explosive_nanites", + "meltdown_nanites", + "nanite_sting_nanites", + "pyro_nanites", + "viral_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_3_POINTS) + +/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", TECHWEB_NODE_ALIENTECH) + design_ids = list( + "mindcontrol_nanites", + "mitosis_nanites", + // "spreading_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/nanite_replication_protocols + id = "nanite_replication_protocols" + display_name = "Nanite Replication Protocols" + description = "Protocols that overwrite the default nanite replication routine to achieve more efficiency in certain circumstances." + prereq_ids = list("nanite_smart") + design_ids = list( + "factory_nanites", + "kickstart_nanites", + "offline_nanites", + "pyramid_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_3_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/nanite_storage_protocols + id = "nanite_storage_protocols" + display_name = "Nanite Storage Protocols" + description = "Protocols that overwrite the default nanite storage routine to achieve more efficiency or greater capacity." + prereq_ids = list("nanite_smart") + design_ids = list( + "free_range_nanites", + "hive_nanites", + "unsafe_storage_nanites", + "zip_nanites", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS, TECHWEB_POINT_TYPE_NANITE = TECHWEB_TIER_3_POINTS) + hidden = TRUE + experimental = TRUE diff --git a/modular_zubbers/code/modules/nanites/unit_test.dm b/modular_zubbers/code/modules/nanites/unit_test.dm new file mode 100644 index 00000000000..1b725f6ac91 --- /dev/null +++ b/modular_zubbers/code/modules/nanites/unit_test.dm @@ -0,0 +1,9 @@ + +/datum/unit_test/nanite_designs/Run() +//Can't use allocate because of bug with certain datums + var/datum/design/nanites/default_design_nanites = new /datum/design/nanites() + + for(var/path in subtypesof(/datum/design)) + var/datum/design/nanites/current_design = new path //Create an instance of each design + if (isnull(current_design.program_type) || current_design.program_type == default_design_nanites.program_type) //Check if the Nanite design provides a program + Fail("Nanite Design [current_design.type] does not have have any program_type set") diff --git a/modular_zubbers/icons/areas/nanite_area.dmi b/modular_zubbers/icons/areas/nanite_area.dmi new file mode 100644 index 0000000000000000000000000000000000000000..132b954307e03f598e7c47d4c36a4f61ab4d2729 GIT binary patch literal 329 zcmV-P0k-~$P)V=-0C=1w$2$suFc1a6I(v$T_TsNiBN0iVcL=zeEsT&XdVLGKnHtl)_ziCL z^l&b6Cs>S4OXihbBP@oVOk_Eu{wW%iVNs=!M7bifOD?eJ$Q(Ib{JX}yIk?r+2Uxcn ziaUtfEdT%jmq|oHR9J=Wmfa12APj^L<4Er03_1WiuoFAsQxh!3Y7F7!E-@{C>8EhS zkW)D@QOnHY1Rwwb2tWV;SdG3ou->UV^cRTR9smFmdwCt@dC_iO&fEfBFsIT5%Beg? z$?LWYpeNS_t#MC!y$j$0ebv+Y-!8Duj5Vh>9@HPvNC${+PS7@NY%*HYFCqdEfB*y_ bz;u8M|F1G{CSqIH00000NkvXXu0mjf1X+Q& literal 0 HcmV?d00001 diff --git a/modular_zubbers/icons/effects/decals/nanite_decal.dmi b/modular_zubbers/icons/effects/decals/nanite_decal.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a4384c24bd0ecf31f1c7c10b68b8287a9713754b GIT binary patch literal 364 zcmV-y0h9iTP)+kZmvNT!^T~S??KX?Px?oWDcA%$K50000< KMNUMnLSTZ^TbMrp literal 0 HcmV?d00001 diff --git a/modular_zubbers/icons/mob/huds/hud.dmi b/modular_zubbers/icons/mob/huds/hud.dmi index e123a7b9966a118288c1651d2a08ea2310cc5264..3c31a58122d07f82d0e6f14b9b868abed6326c69 100644 GIT binary patch literal 15116 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 literal 14910 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 R@CideSJP0VRNW!+KL91lOYi^y literal 0 HcmV?d00001 diff --git a/modular_zubbers/icons/obj/signs/nanite_sign.dmi b/modular_zubbers/icons/obj/signs/nanite_sign.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a4384c24bd0ecf31f1c7c10b68b8287a9713754b GIT binary patch literal 364 zcmV-y0h9iTP)+kZmvNT!^T~S??KX?Px?oWDcA%$K50000< KMNUMnLSTZ^TbMrp literal 0 HcmV?d00001 diff --git a/strings/cas_white.txt b/strings/cas_white.txt index f8f324272df..58c5b96e931 100644 --- a/strings/cas_white.txt +++ b/strings/cas_white.txt @@ -92,6 +92,7 @@ Bluespace artillery. Brain cakes. Breaking spacetime with thousands of bluespace tomatoes. Buttbots. +The primal, nerve-slapping sex that nanites are having inside you. Button spam. BWOINK! Calling a shuttle because I broke a toenail. diff --git a/strings/locations.json b/strings/locations.json index 00befdaee7c..867060cda2a 100644 --- a/strings/locations.json +++ b/strings/locations.json @@ -92,6 +92,7 @@ "Virology", "Warehouse", "Waste Disposal", - "Xenobiology Lab" + "Xenobiology Lab", + "Nanite Lab" ] } diff --git a/tgstation.dme b/tgstation.dme index a0bfd6a121b..7cf552d9c2a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -521,6 +521,7 @@ #include "code\__DEFINES\~~bubber_defines\loadout.dm" #include "code\__DEFINES\~~bubber_defines\misc.dm" #include "code\__DEFINES\~~bubber_defines\mood.dm" +#include "code\__DEFINES\~~bubber_defines\nanites.dm" #include "code\__DEFINES\~~bubber_defines\research_categories.dm" #include "code\__DEFINES\~~bubber_defines\say.dm" #include "code\__DEFINES\~~bubber_defines\signals.dm" @@ -531,9 +532,11 @@ #include "code\__DEFINES\~~bubber_defines\surgery.dm" #include "code\__DEFINES\~~bubber_defines\transport.dm" #include "code\__DEFINES\~~bubber_defines\vehicles.dm" +#include "code\__DEFINES\~~bubber_defines\vomit.dm" #include "code\__DEFINES\~~bubber_defines\___HELPERS\global_lists.dm" #include "code\__DEFINES\~~bubber_defines\research\techweb_nodes.dm" #include "code\__DEFINES\~~bubber_defines\traits\declarations.dm" +#include "code\__DEFINES\~~bubber_defines\traits\nanites.dm" #include "code\__DEFINES\~~bubber_defines\traits\sources.dm" #include "code\__HELPERS\_auxtools_api.dm" #include "code\__HELPERS\_dreamluau.dm" @@ -8783,6 +8786,7 @@ #include "modular_zubbers\code\controllers\subsystem\mapping.dm" #include "modular_zubbers\code\controllers\subsystem\research.dm" #include "modular_zubbers\code\controllers\subsystem\vote.dm" +#include "modular_zubbers\code\controllers\subsystem\processing\nanites.dm" #include "modular_zubbers\code\controllers\subsystem\processing\sol_subsystem.dm" #include "modular_zubbers\code\datums\action.dm" #include "modular_zubbers\code\datums\akula_overrides.dm" @@ -8793,6 +8797,7 @@ #include "modular_zubbers\code\datums\ai_laws\laws_neutral.dm" #include "modular_zubbers\code\datums\ai_laws\laws_station_sided.dm" #include "modular_zubbers\code\datums\brain_damage\magic.dm" +#include "modular_zubbers\code\datums\components\nanites.dm" #include "modular_zubbers\code\datums\components\sign_language.dm" #include "modular_zubbers\code\datums\components\squeak.dm" #include "modular_zubbers\code\datums\components\surgery_initiator.dm" @@ -8823,6 +8828,7 @@ #include "modular_zubbers\code\datums\mood_events\dominant_mood.dm" #include "modular_zubbers\code\datums\mood_events\food_events.dm" #include "modular_zubbers\code\datums\mood_events\miasma_events.dm" +#include "modular_zubbers\code\datums\mood_events\nanite_events.dm" #include "modular_zubbers\code\datums\mutations\visuals_override.dm" #include "modular_zubbers\code\datums\quirks\_quirk.dm" #include "modular_zubbers\code\datums\quirks\negative_quirks\all_nighter.dm" @@ -8869,6 +8875,7 @@ #include "modular_zubbers\code\datums\weather\weather_types\sand_storm.dm" #include "modular_zubbers\code\datums\wounds\permanent_limp.dm" #include "modular_zubbers\code\game\area\areas.dm" +#include "modular_zubbers\code\game\area\nanite.dm" #include "modular_zubbers\code\game\area\areas\centcom.dm" #include "modular_zubbers\code\game\area\areas\moonstation.dm" #include "modular_zubbers\code\game\area\areas\station.dm" @@ -9294,6 +9301,7 @@ #include "modular_zubbers\code\modules\mob\living\carbon\alien\adult\adult.dm" #include "modular_zubbers\code\modules\mob\living\carbon\human\_species.dm" #include "modular_zubbers\code\modules\mob\living\carbon\human\human.dm" +#include "modular_zubbers\code\modules\mob\living\carbon\human\physiology.dm" #include "modular_zubbers\code\modules\mob\living\carbon\human\species\akula.dm" #include "modular_zubbers\code\modules\mob\living\carbon\human\species\tajaran.dm" #include "modular_zubbers\code\modules\mob\living\carbon\human\species\xeno.dm" @@ -9357,6 +9365,38 @@ #include "modular_zubbers\code\modules\more_renaming\renaming_overrides.dm" #include "modular_zubbers\code\modules\movespeed\_movespeed_modifier.dm" #include "modular_zubbers\code\modules\movespeed\modifiers\status_effects.dm" +#include "modular_zubbers\code\modules\nanites\designs.dm" +#include "modular_zubbers\code\modules\nanites\living.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs.dm" +#include "modular_zubbers\code\modules\nanites\nanite_sign.dm" +#include "modular_zubbers\code\modules\nanites\nanite_symptom.dm" +#include "modular_zubbers\code\modules\nanites\program_designs.dm" +#include "modular_zubbers\code\modules\nanites\rules.dm" +#include "modular_zubbers\code\modules\nanites\spawners.dm" +#include "modular_zubbers\code\modules\nanites\techweb_nodes.dm" +#include "modular_zubbers\code\modules\nanites\extra_settings\_extra_setting.dm" +#include "modular_zubbers\code\modules\nanites\extra_settings\boolean.dm" +#include "modular_zubbers\code\modules\nanites\extra_settings\number.dm" +#include "modular_zubbers\code\modules\nanites\extra_settings\text.dm" +#include "modular_zubbers\code\modules\nanites\extra_settings\type.dm" +#include "modular_zubbers\code\modules\nanites\items\boards.dm" +#include "modular_zubbers\code\modules\nanites\items\items.dm" +#include "modular_zubbers\code\modules\nanites\items\program_disks.dm" +#include "modular_zubbers\code\modules\nanites\items\remote.dm" +#include "modular_zubbers\code\modules\nanites\machines\nanite_chamber.dm" +#include "modular_zubbers\code\modules\nanites\machines\nanite_chamber_computer.dm" +#include "modular_zubbers\code\modules\nanites\machines\nanite_cloud_controller.dm" +#include "modular_zubbers\code\modules\nanites\machines\nanite_program_hub.dm" +#include "modular_zubbers\code\modules\nanites\machines\nanite_programmer.dm" +#include "modular_zubbers\code\modules\nanites\machines\public_chamber.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\buffing.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\healing.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\protocols.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\rogue.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\sensor.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\suppression.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\utility.dm" +#include "modular_zubbers\code\modules\nanites\nanite_programs\weapon.dm" #include "modular_zubbers\code\modules\nyamagotchi\nyamagotchi.dm" #include "modular_zubbers\code\modules\opposing_force\code\items.dm" #include "modular_zubbers\code\modules\opposing_force\code\equipment\antagonist_powers.dm" diff --git a/tgui/packages/tgui/interfaces/NaniteChamberControl.tsx b/tgui/packages/tgui/interfaces/NaniteChamberControl.tsx new file mode 100644 index 00000000000..31d36eaaf53 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NaniteChamberControl.tsx @@ -0,0 +1,286 @@ +import { + Box, + Button, + Collapsible, + LabeledList, + NoticeBox, + NumberInput, + Section, + Stack, +} from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { Window } from '../layouts'; +import { NaniteProgram } from './Nanites/types'; + +export const NaniteChamberControl = (props, context) => { + return ( + + + + + + ); +}; + +interface NaniteChamberProps { + status_msg: string; + locked: boolean; + occupant_name: string; + has_nanites: boolean; + nanite_volume: number; + regen_rate: number; + safety_threshold: number; + cloud_id: number; + scan_level: number; + mob_programs: NaniteProgram[]; +} + +export const NaniteChamberControlContent = () => { + const { act, data } = useBackend(); + const { + status_msg, + locked, + occupant_name, + has_nanites, + nanite_volume, + regen_rate, + safety_threshold, + cloud_id, + scan_level, + mob_programs = [], + } = data; + + if (status_msg) { + return {status_msg}; + } + + return ( +
    act('toggle_lock')} + > + {locked ? 'Locked' : 'Unlocked'} + + } + > + {!has_nanites ? ( + <> + + No Nanites Detected + + + + ) : ( + <> +
    act('remove_nanites')} + > + Destroy Nanites + + } + > + + + + + {nanite_volume} + + + {regen_rate} + + + + + + + + act('set_safety', { + value: value, + }) + } + /> + + + + act('set_cloud', { + value: value, + }) + } + /> + + + + +
    +
    + {mob_programs?.map((program) => { + const extra_settings = program.extra_settings || []; + const rules = program.rules || []; + return ( + +
    + + {scan_level >= 2 && ( + + + + + {program.activated ? 'Active' : 'Inactive'} + + + + {program.use_rate}/s + + + + )} + {program.desc} + + {scan_level >= 2 && ( + + {!!program.can_trigger && ( + +
    + + + {program.trigger_cost} + + + {program.trigger_cooldown} + + {!!program.timer_trigger_delay && ( + + {program.timer_trigger_delay} s + + )} + {!!program.timer_trigger && ( + + {program.timer_trigger} s + + )} + +
    +
    + )} + {!!( + program.timer_restart || program.timer_shutdown + ) && ( + +
    + + {/* I mean, bruh, this indentation level + is ABSOLUTELY INSANE!!! */} + {program.timer_restart && ( + + {program.timer_restart} s + + )} + {program.timer_shutdown && ( + + {program.timer_shutdown} s + + )} + +
    +
    + )} +
    + )} + {scan_level >= 3 && !!program.has_extra_settings && ( +
    + + {extra_settings.map((extra_setting) => ( + + {extra_setting.value} + + ))} + +
    + )} + {scan_level >= 4 && ( + + +
    + + {!!program.activation_code && ( + + {program.activation_code} + + )} + {!!program.deactivation_code && ( + + {program.deactivation_code} + + )} + {!!program.kill_code && ( + + {program.kill_code} + + )} + {!!program.can_trigger && + !!program.trigger_code && ( + + {program.trigger_code} + + )} + +
    +
    + {program.has_rules && ( + +
    + {rules.map((rule) => ( + {rule.display} + ))} +
    +
    + )} +
    + )} +
    +
    + ); + })} +
    + + )} +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/NaniteCloudControl.tsx b/tgui/packages/tgui/interfaces/NaniteCloudControl.tsx new file mode 100644 index 00000000000..ab3095c4ffc --- /dev/null +++ b/tgui/packages/tgui/interfaces/NaniteCloudControl.tsx @@ -0,0 +1,366 @@ +import { + Box, + Button, + Collapsible, + LabeledList, + NoticeBox, + NumberInput, + Section, + Stack, +} from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { Window } from '../layouts'; +import { TechwebWarning } from './Nanites/NoTechwebWarning'; +import { NaniteProgram, Techweb } from './Nanites/types'; + +interface NaniteInfoBoxProps { + has_disk: boolean; + has_program: boolean; + disk: NaniteProgram; + current_view: number; + backup_id: number; + new_backup_id: number; + techweb: Techweb; +} + +export const NaniteDiskBox = (props, context) => { + const { data } = useBackend(); + const { has_disk, has_program, disk } = data; + if (!has_disk) { + return No disk inserted; + } + if (!has_program) { + return Inserted disk has no program; + } + return ; +}; + +export const NaniteInfoBox = (props) => { + const { program } = props; + const { + name, + desc, + activated, + use_rate, + can_trigger, + trigger_cost, + trigger_cooldown, + activation_code, + deactivation_code, + kill_code, + trigger_code, + timer_restart, + timer_shutdown, + timer_trigger, + timer_trigger_delay, + extra_settings, + }: NaniteProgram = program; + return ( +
    + {activated ? 'Activated' : 'Deactivated'} + + } + > + + {desc} + + + + {use_rate} + {!!can_trigger && ( + <> + + {trigger_cost} + + + {trigger_cooldown} + + + )} + +
    +
    +
    + + +
    + + + {activation_code} + + + {deactivation_code} + + {kill_code} + {!!can_trigger && ( + + {trigger_code} + + )} + +
    +
    + +
    + + + {timer_restart} s + + + {timer_shutdown} s + + {!!can_trigger && ( + <> + + {timer_trigger} s + + + {timer_trigger_delay} s + + + )} + +
    +
    +
    +
    + + {extra_settings?.map((setting) => { + const naniteTypesDisplayMap = { + number: ( + <> + {setting.value} + {setting.unit} + + ), + text: setting.value, + type: setting.value, + boolean: setting.value ? setting.true_text : setting.false_text, + }; + return ( + + {naniteTypesDisplayMap[setting.type]} + + ); + })} + +
    +
    + ); +}; + +interface NaniteCloudBackupProps { + cloud_id: number; + cloud_programs: NaniteProgram[]; + cloud_backups: CloudBackups[]; +} + +interface CloudBackups { + cloud_id: number; + cloud_programs: NaniteProgram[]; +} + +export const NaniteCloudBackupList = () => { + const { act, data } = useBackend(); + const { cloud_backups = [] } = data; + + return cloud_backups.map((backup) => ( + + )); +}; + +interface NaniteCloudBackupDetailsProps { + cloud_programs: NaniteProgram[]; + cloud_backup: CloudBackups; + current_view: number; + disk: NaniteProgram; + has_program: boolean; +} + +export const NaniteCloudBackupDetails = () => { + const { act, data } = useBackend(); + const { current_view, disk, has_program, cloud_backup } = data; + const can_rule = (disk && disk.can_rule) || false; + if (!cloud_backup) { + return ERROR: Backup not found; + } + const cloud_programs = data.cloud_programs || []; + return ( +
    act('upload_program')} + > + Upload Program from Disk + + ) + } + > + {cloud_programs.map((program) => { + const rules = program.rules || []; + return ( + + act('remove_program', { + program_id: program.id, + }) + } + /> + } + > +
    + + {(!!can_rule || !!program.has_rules) && ( +
    + {!!can_rule && ( + + )} + + + } + > + {program.has_rules ? ( + rules.map((rule) => ( + +
    + )} +
    +
    + ); + })} +
    + ); +}; + +export const NaniteCloudControl = () => { + const { act, data } = useBackend(); + const { has_disk, current_view, new_backup_id, techweb } = data; + return ( + + + +
    act('eject')} + > + Eject + + } + > + +
    +
    + act('set_view', { + view: 0, + }) + } + > + Return + + ) : ( + <> + {'New Backup: '} + + act('update_new_backup_value', { + value: value, + }) + } + /> +
    +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/NaniteProgramHub.tsx b/tgui/packages/tgui/interfaces/NaniteProgramHub.tsx new file mode 100644 index 00000000000..e57cfa71ebb --- /dev/null +++ b/tgui/packages/tgui/interfaces/NaniteProgramHub.tsx @@ -0,0 +1,177 @@ +import { map } from 'common/collections'; +import React from 'react'; +import { + Button, + Flex, + LabeledList, + NoticeBox, + Section, + Tabs, +} from 'tgui-core/components'; + +import { useBackend, useSharedState } from '../backend'; +import { Window } from '../layouts'; +import { TechwebWarning } from './Nanites/NoTechwebWarning'; +import { NaniteProgram, Techweb } from './Nanites/types'; + +interface NaniteProgramHubProps { + detail_view: boolean; + disk: { + name: string; + desc: string; + }; + techweb: Techweb; + has_disk: boolean; + has_program: boolean; + programs: Record>; +} + +export const NaniteProgramHub = (props, context) => { + const { act, data } = useBackend(); + const { + detail_view, + disk, + has_disk, + has_program, + programs = {}, + techweb, + } = data; + const [selectedCategory, setSelectedCategory] = useSharedState( + context, + 'category', + ); + const programsInCategory = (programs && programs[selectedCategory]) || []; + return ( + + + +
    + + + + } + > + {has_disk ? ( + has_program ? ( + + + {disk.name} + + + {disk.desc} + + + ) : ( + No Program Installed + ) + ) : ( + Insert Disk + )} +
    +
    + + + + } + > + {programs !== null ? ( + + + + {map(programs, (cat_contents, category) => { + // Backend was sending stupid data that would have been + // annoying to fix + const tabLabel = category.substring(0, category.length - 8); + return ( + setSelectedCategory(category)} + > + {tabLabel} + + ); + })} + + + + {detail_view ? ( + programsInCategory.map((program) => ( +
    + act('download', { + program_id: program.id, + }) + } + > + Download + + } + > + {program.desc} +
    + )) + ) : ( + + {programsInCategory.map((program) => ( + + act('download', { + program_id: program.id, + }) + } + > + Download + + } + /> + ))} + + )} +
    +
    + ) : ( + No nanite programs are currently researched. + )} +
    +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/NaniteProgrammer.tsx b/tgui/packages/tgui/interfaces/NaniteProgrammer.tsx new file mode 100644 index 00000000000..a4dbc80aef3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NaniteProgrammer.tsx @@ -0,0 +1,402 @@ +import { + Button, + Dropdown, + Input, + LabeledList, + NoticeBox, + NumberInput, + Section, + Stack, +} from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { Window } from '../layouts'; +import { NaniteProgram } from './Nanites/types'; + +interface ExtraSetting { + name: string; + value: string; + types: string[]; + unit: string; + true_text: string; + false_text: string; + type: string; +} + +export const NaniteCodes = (props, context) => { + const { act, data } = useBackend(); + const { activation_code, deactivation_code, kill_code, trigger_code } = data; + return ( +
    + + + + act('set_code', { + target_code: 'activation', + code: value, + }) + } + /> + + + + act('set_code', { + target_code: 'deactivation', + code: value, + }) + } + /> + + + + act('set_code', { + target_code: 'kill', + code: value, + }) + } + /> + + {!!data.can_trigger && ( + + + act('set_code', { + target_code: 'trigger', + code: value, + }) + } + /> + + )} + +
    + ); +}; + +export const NaniteDelays = (props, context) => { + const { act, data } = useBackend(); + + const { timer_restart, timer_shutdown, timer_trigger, timer_trigger_delay } = + data; + + return ( +
    + + + + act('set_restart_timer', { + delay: value, + }) + } + /> + + + + act('set_shutdown_timer', { + delay: value, + }) + } + /> + + {!!data.can_trigger && ( + <> + + + act('set_trigger_timer', { + delay: value, + }) + } + /> + + + + act('set_timer_trigger_delay', { + delay: value, + }) + } + /> + + + )} + +
    + ); +}; + +export const NaniteExtraEntry = (props, context) => { + const { extra_setting } = props; + const { name, type } = extra_setting; + const typeComponentMap = { + number: , + text: , + type: , + boolean: , + }; + return ( + {typeComponentMap[type]} + ); +}; + +export const NaniteExtraNumber = (props, context) => { + const { extra_setting } = props; + const { act } = useBackend(); + const { name, value, min, max, unit } = extra_setting; + return ( + + act('set_extra_setting', { + target_setting: name, + value: val, + }) + } + /> + ); +}; + +export const NaniteExtraText = (props, context) => { + const { extra_setting } = props; + const { act } = useBackend(); + const { name, value }: ExtraSetting = extra_setting; + return ( + + act('set_extra_setting', { + target_setting: name, + value: val, + }) + } + /> + ); +}; + +export const NaniteExtraType = (props, context) => { + const { extra_setting } = props; + const { act } = useBackend(); + const { name, value, types }: ExtraSetting = extra_setting; + return ( + + act('set_extra_setting', { + target_setting: name, + value: val, + }) + } + /> + ); +}; + +interface ExtraSettingBoolean { + name: string; + true_text: string; + false_text: string; + value: boolean; +} + +export const NaniteExtraBoolean = (props, context) => { + const { extra_setting } = props; + const { act } = useBackend(); + const { name, value, true_text, false_text }: ExtraSettingBoolean = + extra_setting; + return ( + + act('set_extra_setting', { + target_setting: name, + }) + } + > + {value ? true_text : false_text} + + ); +}; + +export const NaniteProgrammer = (props, context) => { + return ( + + + + + + ); +}; + +interface NaniteProgrammerContentProps { + has_disk: boolean; + has_program: boolean; + name: string; + desc: string; + use_rate: string; + can_trigger: boolean; + trigger_cost: number; + trigger_cooldown: number; + activated: boolean; + has_extra_settings: boolean; + extra_settings: ExtraSetting[]; +} + +export const NaniteProgrammerContent = (props, context) => { + const { act, data } = useBackend(); + const { + has_disk, + has_program, + name, + desc, + use_rate, + can_trigger, + trigger_cost, + trigger_cooldown, + activated, + has_extra_settings, + extra_settings, + } = data; + if (!has_disk) { + return ( + Insert a nanite program disk + ); + } + if (!has_program) { + return ( +
    act('eject')} + > + Eject + + } + /> + ); + } + return ( +
    act('eject')}> + Eject + + } + > +
    + + {desc} + + + + {use_rate} + {!!can_trigger && ( + <> + + {trigger_cost} + + + {trigger_cooldown} + + + )} + +
    +
    +
    +
    +
    act('toggle_active')} + > + {activated ? 'Active' : 'Inactive'} + + } + > + + + + + + + + + {!!has_extra_settings && ( +
    + + {extra_settings.map((setting) => ( + + ))} + +
    + )} +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/NaniteRemote.tsx b/tgui/packages/tgui/interfaces/NaniteRemote.tsx new file mode 100644 index 00000000000..fbba3c1f56f --- /dev/null +++ b/tgui/packages/tgui/interfaces/NaniteRemote.tsx @@ -0,0 +1,198 @@ +import { + Button, + Input, + LabeledList, + NoticeBox, + NumberInput, + Section, + Table, +} from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { Window } from '../layouts'; + +export const NaniteRemote = (props, context) => { + return ( + + + + + + ); +}; + +interface NaniteProgramProps { + code: number; + locked: boolean; + mode: string; + program_name: string; + relay_code: number; + comms: boolean; + message: string; + saved_settings: Array; +} + +interface SavedSetting { + id: string; + name: string; + mode: string; + code: number; + relay_code: number; +} + +export const NaniteRemoteContent = () => { + const { act, data } = useBackend(); + const { + code, + locked, + mode, + program_name, + relay_code, + comms, + message, + saved_settings = [], + } = data; + + const modes = ['Off', 'Local', 'Targeted', 'Area', 'Relay']; + + if (locked) { + return This interface is locked.; + } + + return ( + <> +
    act('lock')}> + Lock Interface + + } + > + + + + act('update_name', { + name: value, + }) + } + /> + + + + + act('set_code', { + code: value, + }) + } + /> + + {!!comms && ( + + + act('set_message', { + value: value, + }) + } + /> + + )} + {mode === 'Relay' && ( + + + act('set_relay_code', { + code: value, + }) + } + /> + + )} + + {modes.map((key) => ( + + ))} + + +
    +
    + {saved_settings.length > 0 ? ( + + + Name + Mode + Code + Relay + + {saved_settings.map((setting) => ( + + + {setting.name}: + + {setting.mode} + {setting.code} + + {setting.mode === 'Relay' && setting.relay_code} + + +
    + ) : ( + No settings currently saved + )} +
    + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Nanites/NoTechwebWarning.tsx b/tgui/packages/tgui/interfaces/Nanites/NoTechwebWarning.tsx new file mode 100644 index 00000000000..d84c5336d18 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Nanites/NoTechwebWarning.tsx @@ -0,0 +1,17 @@ +import { NoticeBox } from 'tgui-core/components'; + +interface TechwebWarningProps { + display: boolean; +} + +export const TechwebWarning = (props: TechwebWarningProps) => { + const { display } = props; + if (!display) { + return null; + } + return ( + + Warning: No techweb connected! + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Nanites/types.d.ts b/tgui/packages/tgui/interfaces/Nanites/types.d.ts new file mode 100644 index 00000000000..6105f8acea9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Nanites/types.d.ts @@ -0,0 +1,34 @@ +export interface NaniteProgram { + name: string; + id: string; + desc: string; + activated: boolean; + activation_code: number; + use_rate: number; + deactivation_code: number; + kill_code: number; + trigger_cost: number; + trigger_cooldown: number; + trigger_code: number; + can_trigger: boolean; + timer_restart: number; + timer_shutdown: number; + timer_trigger: number; + timer_trigger_delay: number; + has_extra_settings: boolean; + extra_settings: ExtraSetting[]; + rules: NaniteRules[]; + can_rule?: boolean; + has_rules?: boolean; + all_rules_required?: boolean; +} + +export interface NaniteRules { + display: string; + id: string; +} + +export interface Techweb { + name: string; + organization: string; +} diff --git a/tgui/packages/tgui/interfaces/ScannerGate.jsx b/tgui/packages/tgui/interfaces/ScannerGate.jsx index ca2c4f02968..a9a9f246283 100644 --- a/tgui/packages/tgui/interfaces/ScannerGate.jsx +++ b/tgui/packages/tgui/interfaces/ScannerGate.jsx @@ -1,4 +1,10 @@ -import { Box, Button, LabeledList, Section } from 'tgui-core/components'; +import { + Box, + Button, + LabeledList, + NumberInput, + Section, +} from 'tgui-core/components'; import { useBackend } from '../backend'; import { Window } from '../layouts'; @@ -87,6 +93,16 @@ const SCANNER_GATE_ROUTES = { component: () => ScannerGateGender, }, // SKYRAT EDIT END - MORE SCANNER GATE OPTIONS + Contraband: { + title: 'Scanner Mode: Contraband', + component: () => ScannerGateContraband, + }, + // BUBBER EDIT START - NANITES + Nanites: { + title: 'Scanner Mode: Nanites', + component: () => ScannerGateNanites, + }, + // BUBBER EDIT END - NANITES }; const ScannerGateControl = (props) => { @@ -146,6 +162,18 @@ const ScannerGateOff = (props) => { content="Nutrition" onClick={() => act('set_mode', { new_mode: 'Nutrition' })} /> + {/* BUBBER EDIT START - NANITES */} +