diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm
index d90dca1da185..ac50f313351c 100644
--- a/code/__DEFINES/ai.dm
+++ b/code/__DEFINES/ai.dm
@@ -1,8 +1,8 @@
///All AI machinery heat production is multiplied by this value
-#define AI_TEMPERATURE_MULTIPLIER 8 //Thermodynamics? No... No I don't think that's a thing. Balance so we don't use an insane amount of power to produce noticeable heat
+#define AI_TEMPERATURE_MULTIPLIER 5 //Thermodynamics? No... No I don't think that's a thing. Balance so we don't use an insane amount of power to produce noticeable heat
///Temperature limit of all AI machinery
-#define AI_TEMP_LIMIT 283.15 //10C, much hotter than a normal server room for leniency :)
+#define AI_TEMP_LIMIT 288.15 //15C, much hotter than a normal server room for leniency :)
///How many ticks can an AI data core store? When this amount of ticks have passed while it's in an INVALID state it can no longer be used by an AI
@@ -18,6 +18,7 @@
#define AI_PROJECT_CAMERAS "Visiblity Upgrades"
#define AI_PROJECT_INDUCTION "Induction"
#define AI_PROJECT_SURVEILLANCE "Surveillance"
+#define AI_PROJECT_EFFICIENCY "Efficiency"
#define AI_PROJECT_MISC "Misc."
//Update this list if you add any new ones, else the category won't show up in the UIs
GLOBAL_LIST_INIT(ai_project_categories, list(
@@ -25,6 +26,7 @@ GLOBAL_LIST_INIT(ai_project_categories, list(
AI_PROJECT_CAMERAS,
AI_PROJECT_SURVEILLANCE,
AI_PROJECT_INDUCTION,
+ AI_PROJECT_EFFICIENCY,
AI_PROJECT_MISC
))
@@ -35,9 +37,9 @@ GLOBAL_LIST_INIT(ai_project_categories, list(
//AI hardware
-#define AI_CPU_BASE_POWER_USAGE 1500
+#define AI_CPU_BASE_POWER_USAGE 1250
-#define AI_RAM_POWER_USAGE 750
+#define AI_RAM_POWER_USAGE 500
//Needs UI change to properly work!
#define AI_MAX_CPUS_PER_RACK 4
@@ -45,4 +47,7 @@ GLOBAL_LIST_INIT(ai_project_categories, list(
#define AI_MAX_RAM_PER_RACK 4
///How many AI research points does 1 THz generate?
-#define AI_RESEARCH_PER_CPU 10
+#define AI_RESEARCH_PER_CPU 7.5
+
+//How long between each data core being able to send a warning. Wouldn't want any spam if we had jittery temps would we?
+#define AI_DATA_CORE_WARNING_COOLDOWN (5 MINUTES)
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 4396f12506d4..da14f1ca0d32 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -366,6 +366,7 @@
name = "secure AI circuit board spawner"
loot = list(
/obj/item/circuitboard/computer/aiupload,
+ /obj/item/circuitboard/computer/ai_upload_download,
/obj/item/circuitboard/computer/borgupload
)
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 7d8b9156a986..459b20876d39 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -999,9 +999,10 @@
icon_state = "science"
build_path = /obj/machinery/ai/server_cabinet
req_components = list(
- /obj/item/stock_parts/matter_bin = 4,
- /obj/item/stock_parts/manipulator = 2,
- /obj/item/stack/sheet/glass = 2)
+ /obj/item/stock_parts/matter_bin = 2,
+ /obj/item/stock_parts/capacitor = 2,
+ /obj/item/stack/sheet/glass = 2,
+ /obj/item/stack/cable_coil = 1)
/obj/item/circuitboard/machine/ai_core_display
name = "AI Core Display (Machine Board)"
diff --git a/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm b/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm
index 40cc76b078ad..f8a6d0f1857d 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm
@@ -1,4 +1,7 @@
+#define AI_MACHINE_TOO_HOT "Environment too hot"
+#define AI_MACHINE_NO_MOLES "Environment lacks an atmosphere"
+
/obj/machinery/ai
name = "You shouldn't see this!"
desc = "You shouldn't see this!"
@@ -18,6 +21,22 @@
if(istype(T, /turf/open/space) || total_moles < 10)
return FALSE
- if(env.return_temperature() > AI_TEMP_LIMIT || !env.heat_capacity())
+ if(env.return_temperature() > GLOB.ai_os.get_temp_limit() || !env.heat_capacity())
return FALSE
return TRUE
+
+/obj/machinery/ai/proc/get_holder_status()
+ if(stat & (BROKEN|NOPOWER|EMPED))
+ return FALSE
+
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/env = T.return_air()
+ if(!env)
+ return AI_MACHINE_NO_MOLES
+ var/total_moles = env.total_moles()
+ if(istype(T, /turf/open/space) || total_moles < 10)
+ return AI_MACHINE_NO_MOLES
+
+ if(env.return_temperature() > GLOB.ai_os.get_temp_limit() || !env.heat_capacity())
+ return AI_MACHINE_TOO_HOT
+
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm b/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm
index 013775886293..f3ead86565ed 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm
@@ -4,8 +4,8 @@ GLOBAL_VAR_INIT(primary_data_core, null)
/obj/machinery/ai/data_core
name = "AI Data Core"
desc = "A complicated computer system capable of emulating the neural functions of an organic being at near-instantanous speeds."
- icon = 'icons/obj/machines/telecomms.dmi'
- icon_state = "hub"
+ icon = 'icons/obj/machines/ai_core.dmi'
+ icon_state = "core-offline"
circuit = /obj/item/circuitboard/machine/ai_data_core
@@ -18,8 +18,14 @@ GLOBAL_VAR_INIT(primary_data_core, null)
var/valid_ticks = MAX_AI_DATA_CORE_TICKS //Limited to MAX_AI_DATA_CORE_TICKS. Decrement by 1 every time we have an invalid tick, opposite when valid
var/warning_sent = FALSE
+ COOLDOWN_DECLARE(warning_cooldown)
var/TimerID //party time
+ //Heat production multiplied by this
+ var/heat_modifier = 1
+ //Power modifier, power modified by this. Be aware this indirectly changes heat since power => heat
+ var/power_modifier = 1
+
/obj/machinery/ai/data_core/Initialize()
. = ..()
@@ -27,6 +33,20 @@ GLOBAL_VAR_INIT(primary_data_core, null)
if(primary && !GLOB.primary_data_core)
GLOB.primary_data_core = src
update_icon()
+ RefreshParts()
+
+/obj/machinery/ai/data_core/RefreshParts()
+ var/new_heat_mod = 1
+ var/new_power_mod = 1
+ for(var/obj/item/stock_parts/capacitor/C in component_parts)
+ new_power_mod -= (C.rating - 1) / 50 //Max -24% at tier 4 parts, min -0% at tier 1
+
+ for(var/obj/item/stock_parts/matter_bin/M in component_parts)
+ new_heat_mod -= (M.rating - 1) / 15 //Max -40% at tier 4 parts, min -0% at tier 1
+
+ heat_modifier = new_heat_mod
+ power_modifier = new_power_mod
+ active_power_usage = AI_DATA_CORE_POWER_USAGE * power_modifier
/obj/machinery/ai/data_core/process()
calculate_validity()
@@ -66,6 +86,9 @@ GLOBAL_VAR_INIT(primary_data_core, null)
//NOTE: See /obj/machinery/status_display/examine in ai_core_display.dm
/obj/machinery/ai/data_core/examine(mob/user)
. = ..()
+ var/holder_status = get_holder_status()
+ if(holder_status)
+ . += span_warning("Machinery non-functional. Reason: [holder_status]")
if(!isobserver(user))
return
. += "Networked AI Laws:"
@@ -92,6 +115,7 @@ GLOBAL_VAR_INIT(primary_data_core, null)
return TRUE
return FALSE
+
/obj/machinery/ai/data_core/proc/calculate_validity()
valid_ticks = clamp(valid_ticks, 0, MAX_AI_DATA_CORE_TICKS)
@@ -109,8 +133,9 @@ GLOBAL_VAR_INIT(primary_data_core, null)
for(var/mob/living/silicon/ai/AI in contents)
if(!AI.is_dying)
AI.relocate()
- if(!warning_sent)
+ if(!warning_sent && COOLDOWN_FINISHED(src, warning_cooldown))
warning_sent = TRUE
+ COOLDOWN_START(src, warning_cooldown, AI_DATA_CORE_WARNING_COOLDOWN)
var/list/send_to = GLOB.ai_list.Copy()
for(var/mob/living/silicon/ai/AI in send_to)
if(AI.is_dying)
@@ -126,7 +151,7 @@ GLOBAL_VAR_INIT(primary_data_core, null)
var/turf/T = get_turf(src)
var/datum/gas_mixture/env = T.return_air()
if(env.heat_capacity())
- var/temperature_increase = active_power_usage / env.heat_capacity() //1 CPU = 1000W. Heat capacity = somewhere around 3000-4000. Aka we generate 0.25 - 0.33 K per second, per CPU.
+ var/temperature_increase = (active_power_usage / env.heat_capacity()) * heat_modifier //1 CPU = 1000W. Heat capacity = somewhere around 3000-4000. Aka we generate 0.25 - 0.33 K per second, per CPU.
env.set_temperature(env.return_temperature() + temperature_increase * AI_TEMPERATURE_MULTIPLIER) //assume all input power is dissipated
T.air_update_turf()
@@ -148,8 +173,9 @@ GLOBAL_VAR_INIT(primary_data_core, null)
if(!(stat & (BROKEN|NOPOWER|EMPED)))
if(!valid_data_core())
return
- var/mutable_appearance/on_overlay = mutable_appearance(icon, "[initial(icon_state)]_on")
- add_overlay(on_overlay)
+ icon_state = "core"
+ else
+ icon_state = "core-offline"
/obj/machinery/ai/data_core/proc/partytime()
var/current_color = random_color()
diff --git a/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm b/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm
index 485a68832eac..8fbd22d0cff4 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm
@@ -11,6 +11,8 @@ GLOBAL_DATUM_INIT(ai_os, /datum/ai_os, new)
var/list/cpu_assigned
var/list/ram_assigned
+ var/temp_limit = AI_TEMP_LIMIT
+
/datum/ai_os/New()
update_hardware()
cpu_assigned = list()
@@ -124,3 +126,6 @@ GLOBAL_DATUM_INIT(ai_os, /datum/ai_os, new)
cpu_assigned[AI] = 0
update_allocations()
+
+/datum/ai_os/proc/get_temp_limit()
+ return temp_limit
diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm
index a5346b8e6f92..d0d78d20e65e 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm
@@ -4,7 +4,6 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
name = "\improper AI control console"
desc = "Used for accessing the central AI repository from which AIs can be downloaded or uploaded."
req_access = list(ACCESS_RD)
- circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm
index 1793ee159e1d..8b69d332974a 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm
@@ -6,6 +6,7 @@
//What we're currently using, not what we're being granted by the ai data core
var/list/cpu_usage
var/list/ram_usage
+ var/free_ram = 0
var/completed_projects
@@ -28,7 +29,7 @@
/datum/ai_dashboard/proc/is_interactable(mob/user)
- if(IsAdminGhost(user))
+ if(user?.client?.holder)
return TRUE
if(user != owner || owner.incapacitated())
return FALSE
@@ -56,6 +57,7 @@
data["current_cpu"] = GLOB.ai_os.cpu_assigned[owner] ? GLOB.ai_os.cpu_assigned[owner] : 0
data["current_ram"] = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0
+ data["current_ram"] += free_ram
var/total_cpu_used = 0
for(var/I in cpu_usage)
@@ -207,6 +209,7 @@
/datum/ai_dashboard/proc/run_project(datum/ai_project/project)
var/current_ram = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0
+ current_ram += free_ram
var/total_ram_used = 0
for(var/I in ram_usage)
@@ -260,6 +263,8 @@
/datum/ai_dashboard/proc/tick(seconds)
var/current_cpu = GLOB.ai_os.cpu_assigned[owner] ? GLOB.ai_os.total_cpu * GLOB.ai_os.cpu_assigned[owner] : 0
var/current_ram = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0
+ current_ram += free_ram
+
var/total_ram_used = 0
for(var/I in ram_usage)
@@ -299,6 +304,8 @@
cpu_usage[project_being_researched] = 0
continue
if(has_completed_project(project.type)) //This means we're an ability recharging
+ if(!project.ability_recharge_cost) //No ability, just waste the CPU
+ continue
project.ability_recharge_invested += used_cpu
if(project.ability_recharge_invested > project.ability_recharge_cost)
owner.playsound_local(owner, 'sound/machines/ping.ogg', 50, 0)
diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_server_overview.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_server_overview.dm
index e7aadd20ee72..5891d0695f21 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_server_overview.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/management/ai_server_overview.dm
@@ -1,7 +1,6 @@
/obj/machinery/computer/ai_server_console
name = "\improper AI server overview console"
desc = "Used for monitoring the various servers assigned to the AI network."
- req_access = list(ACCESS_RD)
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm b/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm
index 5a16c4b54cf5..1bbd36bb6573 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm
@@ -1,8 +1,8 @@
/obj/machinery/computer/ai_resource_distribution
name = "\improper AI system resource distribution"
desc = "Used for distributing processing resources across the current artificial intelligences."
- req_access = list(ACCESS_ROBOTICS)
- circuit = /obj/item/circuitboard/computer/aifixer
+ req_one_access = list(ACCESS_RD, ACCESS_NETWORK)
+
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/ai_huds.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/ai_huds.dm
index fcf9d353a458..c7c480bb78d1 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/ai_huds.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/ai_huds.dm
@@ -1,7 +1,7 @@
/datum/ai_project/security_hud
name = "Advanced Security HUD"
description = "Using experimental long range passive sensors should allow you to detect various implants such as loyalty implants and tracking implants."
- research_cost = 1000
+ research_cost = 1250
ram_required = 2
research_requirements_text = "None"
category = AI_PROJECT_HUDS
@@ -29,7 +29,7 @@
/datum/ai_project/diag_med_hud
name = "Advanced Medical & Diagnostic HUD"
description = "Various data processing optimizations should allow you to gain extra knowledge about users when your medical and diagnostic hud is active."
- research_cost = 750
+ research_cost = 1000
ram_required = 1
research_requirements_text = "None"
category = AI_PROJECT_HUDS
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/camera_mobility.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/camera_mobility.dm
index acf11e390240..eef4f43d11d0 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/camera_mobility.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/camera_mobility.dm
@@ -1,7 +1,7 @@
/datum/ai_project/camera_speed
name = "Optimised Camera Acceleration"
description = "Using advanced deep learning algorithms you could boost your camera traverse speed."
- research_cost = 500
+ research_cost = 250
ram_required = 1
research_requirements_text = "None"
category = AI_PROJECT_CAMERAS
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm
new file mode 100644
index 000000000000..32bb902377d8
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm
@@ -0,0 +1,12 @@
+/datum/ai_project/coolant_manager
+ name = "Enhanced Coolant Management"
+ description = "Dedicating processing power to figuring out the optimal way to cool our hardware should allow us to increase the temperature limit of our hardware by 10C."
+ category = AI_PROJECT_EFFICIENCY
+
+ research_cost = 2250
+ can_be_run = FALSE
+
+/datum/ai_project/coolant_manager/finish()
+ if(GLOB.ai_os.temp_limit == AI_TEMP_LIMIT) //Limit to only 1 AI doing it.
+ GLOB.ai_os.temp_limit += 10
+
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/examine.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/examine.dm
index c947fadc08c0..25f0a5e70985 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/examine.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/examine.dm
@@ -1,10 +1,8 @@
-
-
/datum/ai_project/examine_humans
name = "Examination Upgrade"
description = "Using experimental image enhancing algorithms will allow you to examine humans, albeit you won't be able to point out every detail.."
- research_cost = 2500
- ram_required = 3
+ research_cost = 4000
+ ram_required = 4
research_requirements_text = "Advanced Security HUD & Advanced Medical & Diagnostic HUD"
research_requirements = list(/datum/ai_project/security_hud, /datum/ai_project/diag_med_hud)
category = AI_PROJECT_SURVEILLANCE
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/firewall.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/firewall.dm
index 9186e9b71e53..1f2f2c2266bb 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/firewall.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/firewall.dm
@@ -1,7 +1,7 @@
/datum/ai_project/firewall
name = "Download Firewall"
description = "By hiding your various functions you should be able to prolong the time it takes to download your consciousness by 2x."
- research_cost = 1000
+ research_cost = 1500
ram_required = 2
research_requirements_text = "None"
category = AI_PROJECT_MISC
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/induction.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/induction.dm
index 07fb52d7e25c..aa3696c2ab09 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/induction.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/induction.dm
@@ -1,7 +1,7 @@
/datum/ai_project/induction_basic
name = "Bluespace Induction Basics"
description = "This research functions as a prerequisite for other induction research such as remote borg charging and APC emergency power."
- research_cost = 3000
+ research_cost = 1500
ram_required = 0
research_requirements_text = "None"
can_be_run = FALSE
@@ -10,7 +10,7 @@
/datum/ai_project/induction_cyborg
name = "Bluespace Induction - Cyborgs"
description = "This ability will allow you to charge any visible cyborgs by 33%"
- research_cost = 3000
+ research_cost = 2500
ram_required = 0
research_requirements_text = "Bluespace Induction Basics"
research_requirements = list(/datum/ai_project/induction_basic)
@@ -39,7 +39,7 @@
/datum/ai_project/induction_apc
name = "Bluespace Induction - APCs"
description = "This ability will allow you to charge any visible APCs by 33%"
- research_cost = 3000
+ research_cost = 2500
ram_required = 0
research_requirements_text = "Bluespace Induction Basics"
research_requirements = list(/datum/ai_project/induction_basic)
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/memory_compressor.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/memory_compressor.dm
new file mode 100644
index 000000000000..3345445b9338
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/memory_compressor.dm
@@ -0,0 +1,30 @@
+/datum/ai_project/memory_compressor
+ name = "Memory Compressor"
+ description = "Using an advanced compression algorithm it should be possible to compress memory dedicated to our kernel. This should increase our available RAM by 3TB. Requires 15% available CPU."
+ category = AI_PROJECT_EFFICIENCY
+
+ research_cost = 2250
+
+
+/datum/ai_project/memory_compressor/run_project(force_run = FALSE)
+ . = ..(force_run)
+ if(!.)
+ return .
+ dashboard.free_ram += 3
+ dashboard.cpu_usage[name] = 0.15
+
+/datum/ai_project/memory_compressor/stop()
+ dashboard.free_ram -= 3
+ dashboard.cpu_usage[name] = 0
+ ..()
+
+/datum/ai_project/memory_compressor/canRun()
+ . = ..()
+ if(!.)
+ return
+ var/total_cpu_used = 0
+ for(var/I in dashboard.cpu_usage)
+ total_cpu_used += dashboard.cpu_usage[I]
+ if(total_cpu_used < 0.85)
+ return TRUE
+ to_chat(ai, span_warning("Unable to run this program. You require 15% free CPU!"))
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/rgb.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/rgb.dm
index e89a25e8a1ee..4ed4baebea36 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/rgb.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/rgb.dm
@@ -1,7 +1,7 @@
/datum/ai_project/rgb
name = "RGB Lighting"
description = "By varying the current levels in the lighting subsystems of your servers, you can make pretty colors."
- research_cost = 250
+ research_cost = 500
ram_required = 0
research_requirements_text = "None"
category = AI_PROJECT_MISC
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm
index 9d1cb987727f..2e1c35d976c3 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm
@@ -1,7 +1,7 @@
/datum/ai_project/shock_defense
name = "Shock Defense"
description = "This research enables the option to shock people within 2 tiles of all of your data cores."
- research_cost = 5000
+ research_cost = 3000
ram_required = 0
research_requirements_text = "Bluespace Induction Basics"
research_requirements = list(/datum/ai_project/induction_basic)
@@ -10,7 +10,7 @@
category = AI_PROJECT_INDUCTION
ability_path = /datum/action/innate/ai/shock_defense
- ability_recharge_cost = 3000
+ ability_recharge_cost = 2000
/datum/ai_project/shock_defense/finish()
add_ability(/datum/action/innate/ai/shock_defense)
diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/surveillance.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/surveillance.dm
index e88ab17fec35..9325bd724172 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/projects/surveillance.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/projects/surveillance.dm
@@ -1,8 +1,8 @@
/datum/ai_project/camera_tracker
name = "Camera Memory Tracker"
description = "Using complex LSTM nodes it is possible to automatically detect when a tagged individual enters camera visiblity."
- research_cost = 4000
- ram_required = 4
+ research_cost = 2500
+ ram_required = 3
research_requirements_text = "Examination Upgrade"
research_requirements = list(/datum/ai_project/examine_humans)
category = AI_PROJECT_SURVEILLANCE
diff --git a/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm b/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm
index f5e5e6ba8fd1..6f78d163e88e 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm
@@ -28,6 +28,10 @@ GLOBAL_LIST_EMPTY(server_cabinets)
var/roundstart = FALSE
///How many ticks we can go without fulfilling the criteria before shutting off
var/valid_ticks = MAX_AI_EXPANSION_TICKS
+ ///Heat production multiplied by this
+ var/heat_modifier = 1
+ ///Power modifier, power modified by this. Be aware this indirectly changes heat since power => heat
+ var/power_modifier = 1
/obj/machinery/ai/server_cabinet/Initialize(mapload)
@@ -36,6 +40,7 @@ GLOBAL_LIST_EMPTY(server_cabinets)
installed_racks = list()
GLOB.server_cabinets += src
update_icon()
+ RefreshParts()
/obj/machinery/ai/server_cabinet/Destroy()
installed_racks = list()
@@ -44,16 +49,31 @@ GLOBAL_LIST_EMPTY(server_cabinets)
GLOB.ai_os.update_hardware()
..()
+/obj/machinery/ai/server_cabinet/RefreshParts()
+ var/new_heat_mod = 1
+ var/new_power_mod = 1
+ for(var/obj/item/stock_parts/capacitor/C in component_parts)
+ new_power_mod -= (C.rating - 1) / 40 //Max -15% at tier 4 parts, min -0% at tier 1
+
+ for(var/obj/item/stock_parts/matter_bin/M in component_parts)
+ new_heat_mod -= (M.rating - 1) / 30 //Max -20% at tier 4 parts, min -0% at tier 1
+ //68% total heat reduction in total at tier 4
+
+ heat_modifier = new_heat_mod
+ power_modifier = new_power_mod
+
+ idle_power_usage = initial(idle_power_usage) * power_modifier
+
/obj/machinery/ai/server_cabinet/process()
valid_ticks = clamp(valid_ticks, 0, MAX_AI_EXPANSION_TICKS)
if(valid_holder())
- var/total_usage = cached_power_usage
+ var/total_usage = (cached_power_usage * power_modifier)
use_power(total_usage)
var/turf/T = get_turf(src)
var/datum/gas_mixture/env = T.return_air()
if(env.heat_capacity())
- var/temperature_increase = total_usage / env.heat_capacity()
+ var/temperature_increase = (total_usage / env.heat_capacity()) * heat_modifier
env.set_temperature(env.return_temperature() + temperature_increase * AI_TEMPERATURE_MULTIPLIER) //assume all input power is dissipated
T.air_update_turf()
@@ -138,13 +158,18 @@ GLOBAL_LIST_EMPTY(server_cabinets)
/obj/machinery/ai/server_cabinet/examine()
. = ..()
+ var/holder_status = get_holder_status()
+ if(holder_status)
+ . += span_warning("Machinery non-functional. Reason: [holder_status]")
if(!valid_ticks)
- . += "A small screen is displaying the words 'OFFLINE.'"
- . += "The machine has [installed_racks.len] racks out of a maximum of [max_racks] installed."
+ . += span_notice("A small screen is displaying the words 'OFFLINE.'")
+ . += span_notice("The machine has [installed_racks.len] racks out of a maximum of [max_racks] installed.")
+ . += span_notice("Current Power Usage Multiplier: [span_bold("[power_modifier * 100]%")]")
+ . += span_notice("Current Heat Multiplier: [span_bold("[heat_modifier * 100]%")]")
for(var/obj/item/server_rack/R in installed_racks)
- . += "There is a rack installed with a processing capacity of [R.get_cpu()]THz and a memory capacity of [R.get_ram()]TB"
- . += "Use a crowbar to remove all currently inserted racks."
+ . += span_notice("There is a rack installed with a processing capacity of [R.get_cpu()]THz and a memory capacity of [R.get_ram()]TB. Uses [R.get_power_usage()]W")
+ . += span_notice("Use a crowbar to remove all currently inserted racks.")
/obj/machinery/ai/server_cabinet/prefilled/Initialize()
diff --git a/code/modules/mob/living/silicon/ai/decentralized/systech/cpu.dm b/code/modules/mob/living/silicon/ai/decentralized/systech/cpu.dm
index fa83d42c88fa..e8e2a9b165e2 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/systech/cpu.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/systech/cpu.dm
@@ -72,7 +72,7 @@
icon_state = "cpuboard_adv"
speed = 2
- power_multiplier = 2.5
+ base_power_usage = 1.75 * AI_CPU_BASE_POWER_USAGE
/obj/item/ai_cpu/bluespace
@@ -81,7 +81,7 @@
icon_state = "cpuboard_super"
speed = 3
- power_multiplier = 4
+ base_power_usage = 2.5 * AI_CPU_BASE_POWER_USAGE
/obj/item/ai_cpu/experimental
name = "experimental neural processing unit"
@@ -89,7 +89,7 @@
icon_state = "cpuboard_adv"
speed = 2
- power_multiplier = 3
+ base_power_usage = 2 * AI_CPU_BASE_POWER_USAGE
minimum_max_power = 1.1
maximum_max_power = 2.5
diff --git a/code/modules/mob/living/silicon/ai/decentralized/systech/rack_creator.dm b/code/modules/mob/living/silicon/ai/decentralized/systech/rack_creator.dm
index efdbc3730252..c4709cbb6291 100644
--- a/code/modules/mob/living/silicon/ai/decentralized/systech/rack_creator.dm
+++ b/code/modules/mob/living/silicon/ai/decentralized/systech/rack_creator.dm
@@ -180,7 +180,10 @@
to_chat(user, span_warning("This socket has not been researched!"))
return ..()
-
+ if(default_deconstruction_screwdriver(user, "[initial(icon_state)]_t", initial(icon_state), I))
+ return
+ if(default_deconstruction_crowbar(I))
+ return
return ..()
diff --git a/code/modules/research/designs/AI_hardware_designs.dm b/code/modules/research/designs/AI_hardware_designs.dm
index 48f941ca5a73..7a81c279e6af 100644
--- a/code/modules/research/designs/AI_hardware_designs.dm
+++ b/code/modules/research/designs/AI_hardware_designs.dm
@@ -48,8 +48,9 @@
name = "neural processing unit"
id = "basic_ai_cpu"
build_type = IMPRINTER
- materials = list(/datum/material/glass = 8000, /datum/material/iron = 2000)
+ materials = list(/datum/material/glass = 2000, /datum/material/iron = 2000)
build_path = /obj/item/ai_cpu
+ construction_time = 5 SECONDS
category = list("Computer Parts")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_NETMIN
@@ -57,8 +58,9 @@
name = "advanced neural processing unit"
id = "advanced_ai_cpu"
build_type = IMPRINTER
- materials = list(/datum/material/glass = 10000, /datum/material/iron = 4000, /datum/material/gold = 2000)
+ materials = list(/datum/material/glass = 4000, /datum/material/iron = 4000, /datum/material/gold = 2000)
build_path = /obj/item/ai_cpu/advanced
+ construction_time = 7.5 SECONDS
category = list("Computer Parts")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_NETMIN
@@ -66,8 +68,9 @@
name = "bluespace neural processing unit"
id = "bluespace_ai_cpu"
build_type = IMPRINTER
- materials = list(/datum/material/glass = 14000, /datum/material/iron = 4000, /datum/material/gold = 4000, /datum/material/bluespace = 2000)
+ materials = list(/datum/material/glass = 8000, /datum/material/iron = 4000, /datum/material/gold = 4000, /datum/material/bluespace = 2000)
build_path = /obj/item/ai_cpu/bluespace
+ construction_time = 10 SECONDS
category = list("Computer Parts")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_NETMIN
@@ -75,7 +78,8 @@
name = "experimental neural processing unit"
id = "experimental_ai_cpu"
build_type = IMPRINTER
- materials = list(/datum/material/glass = 12000, /datum/material/iron = 4000, /datum/material/gold = 6000)
+ materials = list(/datum/material/glass = 6000, /datum/material/iron = 4000, /datum/material/gold = 6000)
build_path = /obj/item/ai_cpu/experimental
+ construction_time = 7.5 SECONDS
category = list("Computer Parts")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_NETMIN
diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm
index 6fdc79fa813f..56ff85dcf5c6 100644
--- a/code/modules/research/designs/comp_board_designs.dm
+++ b/code/modules/research/designs/comp_board_designs.dm
@@ -302,13 +302,6 @@
category = list("Computer Boards", "Shuttle Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
-/datum/design/board/ai_upload_download
- name = "Computer Design (AI Control Console)"
- desc = "Allows for the construction of circuit boards used to build an AI Control console."
- id = "ai_control"
- build_path = /obj/item/circuitboard/computer/ai_upload_download
- category = list("Computer Boards")
- departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/board/ai_server_overview
name = "Computer Design (AI Server Overview Console)"
@@ -324,4 +317,4 @@
id = "ai_resource_distribution"
build_path = /obj/item/circuitboard/computer/ai_resource_distribution
category = list("Computer Boards")
- departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 5cb8a63230d9..37545cd557a3 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -377,7 +377,7 @@
display_name = "Artificial Intelligence"
description = "AI unit research."
prereq_ids = list("robotics", "posibrain")
- design_ids = list("server_cabinet", "ai_data_core", "ai_core_display", "ai_control", "ai_server_overview", "ram1", "basic_ai_cpu", "ai_resource_distribution", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "druid_module", "detective_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard")
+ design_ids = list("server_cabinet", "ai_data_core", "ai_core_display", "ai_server_overview", "ram1", "basic_ai_cpu", "ai_resource_distribution", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "druid_module", "detective_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -1134,7 +1134,7 @@
description = "Using breakthroughs in high-efficiency fabrication it should be possible to drastically increase the speed of Neural Processing Units, at the cost of increased power consumption."
design_ids = list("advanced_ai_cpu")
prereq_ids = list("high_efficiency", "ai")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 3000)
/datum/techweb_node/ai_cpu_experimental
id = "ai_cpu_experimental"
@@ -1142,7 +1142,7 @@
description = "Previously discarded NPUs could be repurposed with minor tweaks. This comes at the expense of increased powerconsumption, but enhanced overclocking capabilities."
design_ids = list("experimental_ai_cpu")
prereq_ids = list("ai_cpu_advanced")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
/datum/techweb_node/ai_cpu_bluespace
id = "ai_cpu_bluespace"
@@ -1150,7 +1150,7 @@
description = "Breakthroughts in bluespace allows the fabrication of ultra fast NPUs. This however comes at the expense of greatly higher power consumption."
design_ids = list("bluespace_ai_cpu")
prereq_ids = list("ai_cpu_advanced", "practical_bluespace")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 10000)
/datum/techweb_node/ai_ram_high_cap
id = "ai_ram_high_cap"
@@ -1158,7 +1158,7 @@
description = "Further advances in memory production should allow higher density sticks."
design_ids = list("ram2")
prereq_ids = list("high_efficiency", "ai")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 3000)
/datum/techweb_node/ai_ram_hyper
id = "ai_ram_hyper"
@@ -1166,7 +1166,7 @@
description = "Further refinement of memory technology allows previously unimaginable data-density."
design_ids = list("ram3")
prereq_ids = list("ai_ram_high_cap")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
/datum/techweb_node/ai_ram_bluespace
id = "ai_ram_bluespace"
@@ -1174,7 +1174,7 @@
description = "Breakthroughs in bluespace technology allows memory chips to store data in special bluespace pockets. Greatly improves data density at the cost of higher fabrication costs."
design_ids = list("ram4")
prereq_ids = list("ai_ram_hyper", "practical_bluespace")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 7500)
@@ -1183,14 +1183,14 @@
display_name = "Improved CPU Sockets"
description = "Refinements in general data theory should allow the mounting of an extra CPU core in each AI server rack."
prereq_ids = list("ai")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
/datum/techweb_node/ai_ram_1
id = "ai_ram_2"
display_name = "Improved Memory Bus"
description = "Refinements in general data theory should allow the addition of another memory stick in each AI server rack."
prereq_ids = list("ai")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
/datum/techweb_node/ai_architecture_256
id = "ai_arch_256"
@@ -1204,7 +1204,7 @@
display_name = "Bluespace Computing"
description = "Bluespace advances allow the instant teleportation of data across a server rack. This acts as a gateway to the final tier of computing."
prereq_ids = list("ai_arch_256", "practical_bluespace")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 7500)
/datum/techweb_node/ai_cpu_2
@@ -1212,28 +1212,28 @@
display_name = "Advanced CPU Sockets"
description = "256 bit computing allows the introduction of another CPU core."
prereq_ids = list("ai_arch_256", "ai_cpu_2")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
/datum/techweb_node/ai_cpu_3
id = "ai_cpu_4"
display_name = "Bluespace CPU Sockets"
description = "Instant teleportation of data across CPU caches allows the installation of a fourth CPU core."
prereq_ids = list("ai_arch_bluespace", "ai_cpu_3")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 10000)
/datum/techweb_node/ai_ram_2
id = "ai_ram_3"
display_name = "Advanced Memory Bus"
description = "256 bit computing allows the introduction of another memory module."
prereq_ids = list("ai_arch_256", "ai_ram_2")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 2500)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 4000)
/datum/techweb_node/ai_ram_3
id = "ai_ram_4"
display_name = "Bluespace Memory Bus"
description = "Bluespace teleportation allows the removal of all bottlenecks. Allows for the introduction of a fourth memory module."
prereq_ids = list("ai_ram_3", "ai_arch_bluespace")
- research_costs = list(TECHWEB_POINT_TYPE_AI = 5000)
+ research_costs = list(TECHWEB_POINT_TYPE_AI = 8000)
diff --git a/icons/obj/machines/ai_core.dmi b/icons/obj/machines/ai_core.dmi
new file mode 100644
index 000000000000..9ef38e6c6c6a
Binary files /dev/null and b/icons/obj/machines/ai_core.dmi differ
diff --git a/tgui/packages/tgui/interfaces/AiDashboard.js b/tgui/packages/tgui/interfaces/AiDashboard.js
index d54b70e41663..b43d6ce67572 100644
--- a/tgui/packages/tgui/interfaces/AiDashboard.js
+++ b/tgui/packages/tgui/interfaces/AiDashboard.js
@@ -13,7 +13,7 @@ export const AiDashboard = (props, context) => {
const [activeProjectsOnly, setActiveProjectsOnly] = useSharedState(context, 'activeProjectsOnly', true);
let remaining_cpu = (1 - data.used_cpu) * 100;
- let amount_of_cpu = data.current_cpu ? data.current_cpu * amount_of_cpu : 0;
+ let amount_of_cpu = data.current_cpu ? data.current_cpu * data.max_cpu : 0;
return (
{
{amount_of_cpu}/{data.max_cpu} THz
diff --git a/yogstation.dme b/yogstation.dme
index 0e758251b063..efbb153c4757 100644
--- a/yogstation.dme
+++ b/yogstation.dme
@@ -2429,9 +2429,11 @@
#include "code\modules\mob\living\silicon\ai\decentralized\projects\_ai_project.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\ai_huds.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\camera_mobility.dm"
+#include "code\modules\mob\living\silicon\ai\decentralized\projects\coolant_manager.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\examine.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\firewall.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\induction.dm"
+#include "code\modules\mob\living\silicon\ai\decentralized\projects\memory_compressor.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\research_booster.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\rgb.dm"
#include "code\modules\mob\living\silicon\ai\decentralized\projects\self_defense.dm"
diff --git a/yogstation/icons/mob/hud.dmi b/yogstation/icons/mob/hud.dmi
index a800423a878b..e3a3a76ce0a2 100644
Binary files a/yogstation/icons/mob/hud.dmi and b/yogstation/icons/mob/hud.dmi differ