From 7a0ae57cea69ce223745982b730da2047b6fdd2c Mon Sep 17 00:00:00 2001
From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Date: Wed, 6 Aug 2025 00:06:55 -0400
Subject: [PATCH] Rebalances some existing AI programs (#29835)
* Existing program rebalance
* Science radio announcements, Excess blank lines
* Don't even know how this got changed...
* Lints
---------
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
---
code/modules/mob/living/silicon/ai/ai_mob.dm | 57 ++++++
.../mob/living/silicon/ai/ai_programs.dm | 183 ++++++++++--------
2 files changed, 154 insertions(+), 86 deletions(-)
diff --git a/code/modules/mob/living/silicon/ai/ai_mob.dm b/code/modules/mob/living/silicon/ai/ai_mob.dm
index e0fe809a664..9b1feaf64b1 100644
--- a/code/modules/mob/living/silicon/ai/ai_mob.dm
+++ b/code/modules/mob/living/silicon/ai/ai_mob.dm
@@ -80,6 +80,14 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
var/bluespace_miner_rate = 100
/// Time until next payout
var/next_payout = 10 MINUTES
+ /// Has the AI unlocked a research subsystem?
+ var/research_subsystem = FALSE
+ /// How potent is the research subsystem?
+ var/research_level = 0
+ /// How long does it take to unlock the next research?
+ var/research_time = 10 MINUTES
+ /// When did we last research something?
+ var/last_research_time
/// Do we have the enhanced tracker?
var/enhanced_tracking = FALSE
/// Who are we tracking with the enhanced tracker?
@@ -436,6 +444,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
change_power_mode(NO_POWER_USE)
if(powered_ai.anchored)
change_power_mode(ACTIVE_POWER_USE)
+ if(powered_ai.research_subsystem && powered_ai.last_research_time + powered_ai.research_time <= world.time)
+ powered_ai.do_research()
if(powered_ai.bluespace_miner)
// Money money money
if(powered_ai.next_payout <= world.time)
@@ -454,6 +464,53 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
. = ..()
update_hat_icons()
+/mob/living/silicon/ai/proc/do_research()
+ last_research_time = world.time
+ // First, find the RND server
+ var/network_manager_uid = null
+ for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
+ if(RNC.network_name == "station_rnd")
+ network_manager_uid = RNC.UID()
+ break
+ var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
+ if(!RNC) // Could not find the RND server. It probably blew up.
+ to_chat(src, "No research server found!")
+ return
+
+ var/upgraded = FALSE
+ var/datum/research/files = RNC.research_files
+ if(!files)
+ to_chat(src, "No research server found!")
+ return
+ var/list/possible_tech = list()
+ for(var/datum/tech/T in files.possible_tech)
+ possible_tech += T
+ while(!upgraded)
+ var/datum/tech/tech_to_upgrade = pick_n_take(possible_tech)
+ // If there are no possible techs to upgrade, stop the program
+ if(!tech_to_upgrade)
+ to_chat(src, "Current research cannot be discovered any further.")
+ research_subsystem = FALSE
+ return
+ // No illegals until level 10
+ if(research_level < 10 && istype(tech_to_upgrade, /datum/tech/syndicate))
+ continue
+ // No alien research
+ if(istype(tech_to_upgrade, /datum/tech/abductor))
+ continue
+ var/datum/tech/current = files.find_possible_tech_with_id(tech_to_upgrade.id)
+ if(!current)
+ continue
+ // If the tech is level 7 and the program too weak, don't upgrade
+ if(current.level >= 7 && research_level < 5)
+ continue
+ // Nothing beyond 8
+ if(current.level >= 8)
+ continue
+ files.UpdateTech(tech_to_upgrade.id, current.level + 1)
+ aiRadio.autosay("Discovered innovations have led to an increase in the field of [current]!", src, "Science")
+ upgraded = TRUE
+
/mob/living/silicon/ai/proc/pick_icon()
set category = "AI Commands"
set name = "Set AI Core Display"
diff --git a/code/modules/mob/living/silicon/ai/ai_programs.dm b/code/modules/mob/living/silicon/ai/ai_programs.dm
index b70ad4c50aa..58af60a0b77 100644
--- a/code/modules/mob/living/silicon/ai/ai_programs.dm
+++ b/code/modules/mob/living/silicon/ai/ai_programs.dm
@@ -209,6 +209,8 @@
var/cooldown = 30 SECONDS
/// Is this program installed?
var/installed = FALSE
+ /// Is this program only installable through disk?
+ var/external = FALSE
/datum/ai_program/New()
. = ..()
@@ -276,7 +278,10 @@
return
user.program_picker.ui_interact(user)
-/// RGB Lighting - Recolors Lights
+//////////////////////////////
+// MARK: RGB Lighting
+//////////////////////////////
+
/datum/ai_program/rgb_lighting
program_name = "RGB Lighting"
program_id = "rgb_lighting"
@@ -345,7 +350,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Power Shunt - Recharges things from your SMES
+//////////////////////////////
+// MARK: Power Shunt
+//////////////////////////////
+
/datum/ai_program/power_shunt
program_name = "Power Shunt"
program_id = "power_shunt"
@@ -422,7 +430,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Repair Nanites - Uses large numbers of nanites to repair things
+//////////////////////////////
+// MARK: Repair Nanites
+//////////////////////////////
+
/datum/ai_program/repair_nanites
program_name = "Repair Nanites"
program_id = "repair_nanites"
@@ -453,7 +464,7 @@
if(!check_camera_vision(user, target))
revert_cast()
return
- if(!isrobot(target) && !isapc(target) && !ismecha(target) && !ismachineperson(target))
+ if(!isrobot(target) && !isapc(target) && !ismecha(target) && !ismachineperson(target) && !isbot(target))
to_chat(user, "You can only repair borgs, mechs, and APCs!")
revert_cast()
return
@@ -462,6 +473,10 @@
to_chat(user, "This software lacks the required upgrade to repair IPCs!")
revert_cast()
return
+ if(isbot(target) && spell_level < 2)
+ to_chat(user, "This software is not upgraded enough to repair the robot!")
+ revert_cast()
+ return
if(!AI.program_picker.spend_nanites(program.nanite_cost))
to_chat(user, "Not enough nanites!")
revert_cast()
@@ -485,7 +500,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Universal Adapter - Unlocks usage of repair nanites and power shunt for IPCs
+//////////////////////////////
+// MARK: Universal Adapter
+//////////////////////////////
+
/datum/ai_program/universal_adapter
program_name = "Universal Adapter"
program_id = "universal_adapter"
@@ -514,7 +532,10 @@
user.adapter_efficiency = 0.5
user.universal_adapter = FALSE
-/// Door Override - Repairs door wires if the AI wire is not cut
+//////////////////////////////
+// MARK: Airlock Restoration
+//////////////////////////////
+
/datum/ai_program/airlock_restoration
program_name = "Airlock Restoration"
program_id = "airlock_restoration"
@@ -577,12 +598,14 @@
if(spell_level == 5)
desc += " Firmware version sufficient enough to repair damage caused by a cryptographic sequencer."
-/// Automated Extinguishing System - Deploys nanofrost to a target tile
+//////////////////////////////
+// MARK: Automated Extinguisher
+//////////////////////////////
+
/datum/ai_program/extinguishing_system
program_name = "Automated Extinguishing System"
program_id = "extinguishing_system"
description = "Deploy a nanofrost globule to a target to rapidly extinguish plasmafires."
- cost = 3
nanite_cost = 50
power_type = /datum/spell/ai_spell/ranged/extinguishing_system
unlock_text = "Nanofrost synthesizer online."
@@ -628,7 +651,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Bluespace Miner Subsystem - Makes money for science, at the cost of extra power drain
+//////////////////////////////
+// MARK: Bluespace Miner
+//////////////////////////////
+
/datum/ai_program/bluespace_miner
program_name = "Bluespace Miner Subsystem"
program_id = "bluespace_miner"
@@ -657,7 +683,10 @@
return
user.bluespace_miner_rate = 100
-/// Multimarket Analysis Subsystem - Reduce prices of things at cargo
+//////////////////////////////
+// MARK: Multimarket Analysis
+//////////////////////////////
+
/datum/ai_program/multimarket_analyser
program_name = "Multimarket Analysis Subsystem"
program_id = "multimarket_analyser"
@@ -685,7 +714,10 @@
..()
SSeconomy.pack_price_modifier = original_price_mod
-/// Light Synthesizer - Fixes lights
+//////////////////////////////
+// MARK: Light Synthesizer
+//////////////////////////////
+
/datum/ai_program/light_repair
program_name = "Light Synthesizer"
program_id = "light_repair"
@@ -738,7 +770,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Nanosurgeon Deployment - Uses large numbers of nanites to heal things
+//////////////////////////////
+// MARK: Nanosurgeon Deployment
+//////////////////////////////
+
/datum/ai_program/nanosurgeon_deployment
program_name = "Nanosurgeon Deployment"
program_id = "nanosurgeon_deployment"
@@ -810,7 +845,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-/// Enhanced Door Controls - Reduces delay in bolting and shocking doors
+//////////////////////////////
+// MARK: Enhanced Door Controls
+//////////////////////////////
+
/datum/ai_program/enhanced_doors
program_name = "Enhanced Door Controls"
program_id = "enhanced_doors"
@@ -836,87 +874,48 @@
user.door_bolt_delay = original_door_delay
-/// Experimental Research Subsystem - Knowledge is power
+//////////////////////////////
+// MARK: Experimental Research Subsystem
+//////////////////////////////
+
/datum/ai_program/research_subsystem
program_name = "Experimental Research Subsystem"
program_id = "research_subsystem"
description = "Put your processors to work spinning centrifuges and studying results. You unlock a new point of research in a random field."
cost = 5
- nanite_cost = 60
- power_type = /datum/spell/ai_spell/research_subsystem
- unlock_text = "Research and Discovery submodule installation complete."
+ max_level = 10
+ unlock_text = "Research and Discovery submodule installation complete. Automated information gathering enabled."
+ upgrade = TRUE
-/datum/spell/ai_spell/research_subsystem
- name = "Experimental Research Subsystem"
- desc = "Put your processors to work spinning centrifuges and studying results. You unlock a new point of research in a random field."
- action_icon = 'icons/obj/machines/research.dmi'
- action_icon_state = "tdoppler"
- auto_use_uses = FALSE
- base_cooldown = 600 SECONDS
- cooldown_min = 300 SECONDS
- starts_charged = FALSE
- level_max = 10
- selection_activated_message = "You spool up your research tools..."
- var/rnd_server = "station_rnd"
-
-/datum/spell/ai_spell/research_subsystem/cast(list/targets, mob/user)
- var/mob/living/silicon/ai/AI = user
- if(!AI.program_picker.spend_nanites(program.nanite_cost))
- to_chat(user, "Not enough nanites!")
- revert_cast()
+/datum/ai_program/research_subsystem/upgrade(mob/living/silicon/ai/user, first_install = FALSE)
+ ..()
+ if(!istype(user))
return
- // First, find the RND server
- var/network_manager_uid = null
- for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
- if(RNC.network_name == rnd_server)
- network_manager_uid = RNC.UID()
- break
- var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
- if(!RNC) // Could not find the RND server. It probably blew up.
- to_chat(user, "No research server found!")
+ user.research_level = upgrade_level
+ user.research_time = 10 MINUTES - (30 SECONDS * upgrade_level)
+ if(first_install)
+ user.last_research_time = 10 MINUTES - (30 SECONDS * upgrade_level)
+ user.research_subsystem = TRUE
+ installed = TRUE
+
+/datum/ai_program/research_subsystem/downgrade(mob/living/silicon/ai/user)
+ ..()
+ if(!istype(user))
return
+ user.research_level = upgrade_level
+ user.research_time = 10 MINUTES - (30 SECONDS * upgrade_level)
- var/upgraded = FALSE
- var/datum/research/files = RNC.research_files
- if(!files)
- to_chat(user, "No research server found!")
+/datum/ai_program/research_subsystem/uninstall(mob/living/silicon/ai/user)
+ ..()
+ if(!istype(user))
return
- var/list/possible_tech = list()
- for(var/datum/tech/T in files.possible_tech)
- possible_tech += T
- while(!upgraded)
- var/datum/tech/tech_to_upgrade = pick_n_take(possible_tech)
- // If there are no possible techs to upgrade, stop the program
- if(!tech_to_upgrade)
- to_chat(user, "Current research cannot be discovered any further.")
- revert_cast()
- AI.program_picker.refund_nanites(program.nanite_cost)
- return
- // No illegals until level 10
- if(spell_level < 10 && istype(tech_to_upgrade, /datum/tech/syndicate))
- continue
- // No alien research
- if(istype(tech_to_upgrade, /datum/tech/abductor))
- continue
- var/datum/tech/current = files.find_possible_tech_with_id(tech_to_upgrade.id)
- if(!current)
- continue
- // If the tech is level 7 and the program too weak, don't upgrade
- if(current.level >= 7 && spell_level < 5)
- continue
- // Nothing beyond 8
- if(current.level >= 8)
- continue
- files.UpdateTech(tech_to_upgrade.id, current.level + 1)
- to_chat(user, "Discovered innovations have led to an increase in the field of [current]!")
- upgraded = TRUE
+ user.research_time = 10 MINUTES
+ user.research_subsystem = FALSE
-/datum/spell/ai_spell/research_subsystem/on_purchase_upgrade()
- cooldown_handler.recharge_duration = max(base_cooldown - (max(spell_level - 3, 0) * 30 SECONDS), cooldown_min)
- if(cooldown_handler.is_on_cooldown())
- cooldown_handler.start_recharge()
+//////////////////////////////
+// MARK: Emergency Sealant
+//////////////////////////////
-// Emergency Sealant - Patches holes with metal foam
/datum/ai_program/emergency_sealant
program_name = "Emergency Sealant"
program_id = "emergency_sealant"
@@ -967,7 +966,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-// Holosign Deployment - Deploys a holosign on the selected turf
+//////////////////////////////
+// MARK: Holosign Deployer
+//////////////////////////////
+
/datum/ai_program/holosign_displayer
program_name = "Holosign Displayer"
program_id = "holosign_displayer"
@@ -1033,7 +1035,10 @@
playsound(H.loc, 'sound/machines/chime.ogg', 20, 1)
qdel(H)
-/// HONK Subsystem - HONK
+//////////////////////////////
+// MARK: HONK Subsystem
+//////////////////////////////
+
/datum/ai_program/honk_subsystem
program_name = "Honk Subsystem"
program_id = "honk_subsystem"
@@ -1080,7 +1085,10 @@
if(cooldown_handler.is_on_cooldown())
cooldown_handler.start_recharge()
-// Enhanced Tracking System - Select a target. Get alerted after a delay whenever that target enters camera sight
+//////////////////////////////
+// MARK: Enhanced Tracker
+//////////////////////////////
+
/datum/ai_program/enhanced_tracker
program_name = "Enhanced Tracking Subsystem"
program_id = "enhanced_tracker"
@@ -1145,7 +1153,10 @@
/mob/living/silicon/ai/proc/reset_tracker_cooldown()
tracker_alert_cooldown = FALSE
-// Pointer - Lets you put down a holographic reticle to draw attention to things
+//////////////////////////////
+// MARK: Holopointer
+//////////////////////////////
+
/datum/ai_program/pointer
program_name = "Holopointer"
program_id = "holopointer"