From ab365f9fb4f69972e08cef985cc3d82c2114cf13 Mon Sep 17 00:00:00 2001 From: vect0r <71346830+Vect0r2@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:24:43 -0700 Subject: [PATCH] Adds the ability for an AI to remotely charge an APC with an upgrade disk (#86470) ## About The Pull Request Adds an upgrade disk that gives the ability to remotely charge an APC with the AIs backup power (the one that runs down when there is no power in an APC). This tech disk is under advanced AI tech Also added the ability to make new disks with the new object type /obj/item/aiupgrade, and made it so not every AI module is malf, now only subtypes of /datum/ai_module/malf show up on malf upgrade screens ## Why It's Good For The Game Adds the ability for an AI to assist crewmembers who do not have power, which is a pretty interesting interaction. Does chem not have power and is trying to make some healing chems? you can provide power for them for a bit, but they better hurry! ## Changelog :cl: add: Added the remote power AI disk code: made it possible to easily add new AI upgrade disks /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/is_helpers.dm | 2 + code/game/objects/items/robot/ai_upgrades.dm | 72 ++++++++++++++----- code/modules/antagonists/malf_ai/malf_ai.dm | 4 +- .../antagonists/malf_ai/malf_ai_modules.dm | 58 +++++++-------- code/modules/mob/living/silicon/ai/ai.dm | 2 +- .../silicon/ai/ai_actions/remote_power.dm | 41 +++++++++++ code/modules/mob/living/silicon/ai/life.dm | 10 +-- .../research/designs/electronics_designs.dm | 14 +++- .../research/techweb/nodes/robo_nodes.dm | 3 +- tgstation.dme | 1 + 10 files changed, 149 insertions(+), 58 deletions(-) create mode 100644 code/modules/mob/living/silicon/ai/ai_actions/remote_power.dm diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 8846672efe1..38f39437fac 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -279,6 +279,8 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define is_reagent_container(O) (istype(O, /obj/item/reagent_containers)) +#define isapc(A) (istype(A, /obj/machinery/power/apc)) + //Assemblies #define isassembly(O) (istype(O, /obj/item/assembly)) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index f6357b229ef..b630a3b8a42 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -1,4 +1,45 @@ ///AI Upgrades +/obj/item/aiupgrade + name = "ai upgrade disk" + desc = "You really shouldn't be seeing this" + icon = 'icons/obj/devices/circuitry_n_data.dmi' + icon_state = "datadisk3" + ///The upgrade that will be applied to the AI when installed + var/datum/ai_module/to_gift = /datum/ai_module + +/obj/item/aiupgrade/pre_attack(atom/target, mob/living/user, proximity) + if(!proximity) + return ..() + if(!isAI(target)) + return ..() + var/mob/living/silicon/ai/AI = target + var/datum/action/innate/ai/action = locate(to_gift.power_type) in AI.actions + var/datum/ai_module/gifted_ability = new to_gift + if(!to_gift.upgrade) + if(!action) + var/ability = to_gift.power_type + var/datum/action/gifted_action = new ability + gifted_action.Grant(AI) + else if(gifted_ability.one_purchase) + to_chat(user, "[AI] already has an [src] installed!") + return + else + action.uses += initial(action.uses) + action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining." + action.build_all_button_icons() + else + if(!action) + gifted_ability.upgrade(AI) + if(gifted_ability.unlock_text) + to_chat(AI, gifted_ability.unlock_text) + if(gifted_ability.unlock_sound) + AI.playsound_local(AI, gifted_ability.unlock_sound, 50, 0) + update_static_data(AI) + to_chat(user, span_notice("You install [src], upgrading [AI].")) + to_chat(AI, span_userdanger("[user] has upgraded you with [src]!")) + user.log_message("has upgraded [key_name(AI)] with a [src].", LOG_GAME) + qdel(src) + return TRUE //Malf Picker @@ -34,28 +75,21 @@ //Lipreading -/obj/item/surveillance_upgrade +/obj/item/aiupgrade/surveillance_upgrade name = "surveillance software upgrade" desc = "An illegal software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading and hidden microphones." - icon = 'icons/obj/devices/circuitry_n_data.dmi' - icon_state = "datadisk3" + to_gift = /datum/ai_module/malf/upgrade/eavesdrop -/obj/item/surveillance_upgrade/Initialize(mapload) +/obj/item/aiupgrade/surveillance_upgrade/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT) -/obj/item/surveillance_upgrade/pre_attack(atom/A, mob/living/user, proximity) - if(!proximity) - return ..() - if(!isAI(A)) - return ..() - var/mob/living/silicon/ai/AI = A - if(AI.eyeobj) - AI.eyeobj.relay_speech = TRUE - to_chat(AI, span_userdanger("[user] has upgraded you with surveillance software!")) - to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.") - to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) - user.log_message("has upgraded [key_name(AI)] with a [src].", LOG_GAME) - message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") - qdel(src) - return TRUE + +/obj/item/aiupgrade/power_transfer + name = "power transfer upgrade" + desc = "A legal upgrade that allows an artificial intelligence to directly provide power to APCs from a distance" + to_gift = /datum/ai_module/power_apc + + + + diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm index 5b217115171..dc92289f66b 100644 --- a/code/modules/antagonists/malf_ai/malf_ai.dm +++ b/code/modules/antagonists/malf_ai/malf_ai.dm @@ -198,7 +198,7 @@ "name" = category, "items" = (category == malf_ai.malf_picker.selected_cat ? list() : null)) for(var/module in malf_ai.malf_picker.possible_modules[category]) - var/datum/ai_module/mod = malf_ai.malf_picker.possible_modules[category][module] + var/datum/ai_module/malf/mod = malf_ai.malf_picker.possible_modules[category][module] cat["items"] += list(list( "name" = mod.name, "cost" = mod.cost, @@ -223,7 +223,7 @@ for(var/category in malf_ai.malf_picker.possible_modules) buyable_items += malf_ai.malf_picker.possible_modules[category] for(var/key in buyable_items) - var/datum/ai_module/valid_mod = buyable_items[key] + var/datum/ai_module/malf/valid_mod = buyable_items[key] if(valid_mod.name == item_name) malf_ai.malf_picker.purchase_module(malf_ai, valid_mod) return TRUE diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 90f3b766492..a9f84c51dad 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( /obj/machinery/computer/gateway_control, ))) -GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) +GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf)) /// The malf AI action subtype. All malf actions are subtypes of this. /datum/action/innate/ai @@ -137,19 +137,19 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return /// Modules causing destruction -/datum/ai_module/destructive +/datum/ai_module/malf/destructive category = "Destructive Modules" /// Modules with stealthy and utility uses -/datum/ai_module/utility +/datum/ai_module/malf/utility category = "Utility Modules" /// Modules that are improving AI abilities and assets -/datum/ai_module/upgrade +/datum/ai_module/malf/upgrade category = "Upgrade Modules" /// Doomsday Device: Starts the self-destruct timer. It can only be stopped by killing the AI completely. -/datum/ai_module/destructive/nuke_station +/datum/ai_module/malf/destructive/nuke_station name = "Doomsday Device" description = "Activate a weapon that will disintegrate all organic life on the station after a 450 second delay. \ Can only be used while on the station, will fail if your core is moved off station or destroyed. \ @@ -372,7 +372,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return TRUE /// Hostile Station Lockdown: Locks, bolts, and electrifies every airlock on the station. After 90 seconds, the doors reset. -/datum/ai_module/destructive/lockdown +/datum/ai_module/malf/destructive/lockdown name = "Hostile Station Lockdown" description = "Overload the airlock, blast door and fire control networks, locking them down. \ Caution! This command also electrifies all airlocks. The networks will automatically reset after 90 seconds, briefly \ @@ -424,7 +424,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) CHECK_TICK /// Override Machine: Allows the AI to override a machine, animating it into an angry, living version of itself. -/datum/ai_module/destructive/override_machine +/datum/ai_module/malf/destructive/override_machine name = "Machine Override" description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. Four uses per purchase." cost = 30 @@ -481,7 +481,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(to_animate), to_animate, caller, TRUE) /// Destroy RCDs: Detonates all non-cyborg RCDs on the station. -/datum/ai_module/destructive/destroy_rcd +/datum/ai_module/malf/destructive/destroy_rcd name = "Destroy RCDs" description = "Send a specialised pulse to detonate all hand-held and exosuit Rapid Construction Devices on the station." cost = 25 @@ -506,7 +506,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) owner.playsound_local(owner, 'sound/machines/twobeep.ogg', 50, 0) /// Overload Machine: Allows the AI to overload a machine, detonating it after a delay. Two uses per purchase. -/datum/ai_module/destructive/overload_machine +/datum/ai_module/malf/destructive/overload_machine name = "Machine Overload" description = "Overheats an electrical machine, causing a small explosion and destroying it. Two uses per purchase." cost = 20 @@ -567,7 +567,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return TRUE /// Blackout: Overloads a random number of lights across the station. Three uses. -/datum/ai_module/destructive/blackout +/datum/ai_module/malf/destructive/blackout name = "Blackout" description = "Attempts to overload the lighting circuits on the station, destroying some bulbs. Three uses per purchase." cost = 15 @@ -601,7 +601,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) build_all_button_icons() /// HIGH IMPACT HONKING -/datum/ai_module/destructive/megahonk +/datum/ai_module/malf/destructive/megahonk name = "Percussive Intercomm Interference" description = "Emit a debilitatingly percussive auditory blast through the station intercoms. Does not overpower hearing protection. Two uses per purchase." cost = 20 @@ -632,7 +632,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) to_chat(honk_victim, span_clown("HOOOOONK!")) /// Robotic Factory: Places a large machine that converts humans that go through it into cyborgs. Unlocking this ability removes shunting. -/datum/ai_module/utility/place_cyborg_transformer +/datum/ai_module/malf/utility/place_cyborg_transformer name = "Robotic Factory (Removes Shunting)" description = "Build a machine anywhere, using expensive nanomachines, that can convert a living human into a loyal cyborg slave when placed inside." cost = 100 @@ -707,7 +707,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return success /// Air Alarm Safety Override: Unlocks the ability to enable dangerous modes on all air alarms. -/datum/ai_module/utility/break_air_alarms +/datum/ai_module/malf/utility/break_air_alarms name = "Air Alarm Safety Override" description = "Gives you the ability to disable safeties on all air alarms. This will allow you to use extremely dangerous environmental modes. \ Anyone can check the air alarm's interface and may be tipped off by their nonfunctionality." @@ -733,7 +733,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0) /// Thermal Sensor Override: Unlocks the ability to disable all fire alarms from doing their job. -/datum/ai_module/utility/break_fire_alarms +/datum/ai_module/malf/utility/break_fire_alarms name = "Thermal Sensor Override" description = "Gives you the ability to override the thermal sensors on all fire alarms. \ This will remove their ability to scan for fire and thus their ability to alert." @@ -764,7 +764,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0) /// Disable Emergency Lights -/datum/ai_module/utility/emergency_lights +/datum/ai_module/malf/utility/emergency_lights name = "Disable Emergency Lights" description = "Cuts emergency lights across the entire station. If power is lost to light fixtures, \ they will not attempt to fall back on emergency power reserves." @@ -791,7 +791,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) owner.playsound_local(owner, 'sound/effects/light_flicker.ogg', 50, FALSE) /// Reactivate Camera Network: Reactivates up to 30 cameras across the station. -/datum/ai_module/utility/reactivate_cameras +/datum/ai_module/malf/utility/reactivate_cameras name = "Reactivate Camera Network" description = "Runs a network-wide diagnostic on the camera network, resetting focus and re-routing power to failed cameras. \ Can be used to repair up to 30 cameras." @@ -832,7 +832,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) build_all_button_icons() /// Upgrade Camera Network: EMP-proofs all cameras, in addition to giving them X-ray vision. -/datum/ai_module/upgrade/upgrade_cameras +/datum/ai_module/malf/upgrade/upgrade_cameras name = "Upgrade Camera Network" description = "Install broad-spectrum scanning and electrical redundancy firmware to the camera network, enabling EMP-proofing and light-amplified X-ray vision. Upgrade is done immediately upon purchase." //I <3 pointless technobabble //This used to have motion sensing as well, but testing quickly revealed that giving it to the whole cameranet is PURE HORROR. @@ -841,7 +841,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: CAMSUPGRADED. Light amplification system online.") unlock_sound = 'sound/items/rped.ogg' -/datum/ai_module/upgrade/upgrade_cameras/upgrade(mob/living/silicon/ai/AI) +/datum/ai_module/malf/upgrade/upgrade_cameras/upgrade(mob/living/silicon/ai/AI) // Sets up nightvision RegisterSignal(AI, COMSIG_MOB_UPDATE_SIGHT, PROC_REF(on_update_sight)) AI.update_sight() @@ -864,13 +864,13 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) upgraded_cameras++ unlock_text = replacetext(unlock_text, "CAMSUPGRADED", "[upgraded_cameras]") //This works, since unlock text is called after upgrade() -/datum/ai_module/upgrade/upgrade_cameras/proc/on_update_sight(mob/source) +/datum/ai_module/malf/upgrade/upgrade_cameras/proc/on_update_sight(mob/source) SIGNAL_HANDLER // Dim blue, pretty source.lighting_color_cutoffs = blend_cutoff_colors(source.lighting_color_cutoffs, list(5, 25, 35)) /// AI Turret Upgrade: Increases the health and damage of all turrets. -/datum/ai_module/upgrade/upgrade_turrets +/datum/ai_module/malf/upgrade/upgrade_turrets name = "AI Turret Upgrade" description = "Improves the power and health of all AI turrets. This effect is permanent. Upgrade is done immediately upon purchase." cost = 30 @@ -878,7 +878,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) unlock_text = span_notice("You establish a power diversion to your turrets, upgrading their health and damage.") unlock_sound = 'sound/items/rped.ogg' -/datum/ai_module/upgrade/upgrade_turrets/upgrade(mob/living/silicon/ai/AI) +/datum/ai_module/malf/upgrade/upgrade_turrets/upgrade(mob/living/silicon/ai/AI) for(var/obj/machinery/porta_turret/ai/turret as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/porta_turret/ai)) turret.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) turret.max_integrity = 200 @@ -887,7 +887,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) turret.lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg' /// Enhanced Surveillance: Enables AI to hear conversations going on near its active vision. -/datum/ai_module/upgrade/eavesdrop +/datum/ai_module/malf/upgrade/eavesdrop name = "Enhanced Surveillance" description = "Via a combination of hidden microphones and lip reading software, \ you are able to use your cameras to listen in on conversations. Upgrade is done immediately upon purchase." @@ -896,12 +896,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: Enhanced surveillance package online.") unlock_sound = 'sound/items/rped.ogg' -/datum/ai_module/upgrade/eavesdrop/upgrade(mob/living/silicon/ai/AI) +/datum/ai_module/malf/upgrade/eavesdrop/upgrade(mob/living/silicon/ai/AI) if(AI.eyeobj) AI.eyeobj.relay_speech = TRUE /// Unlock Mech Domination: Unlocks the ability to dominate mechs. Big shocker, right? -/datum/ai_module/upgrade/mecha_domination +/datum/ai_module/malf/upgrade/mecha_domination name = "Unlock Mech Domination" description = "Allows you to hack into a mech's onboard computer, shunting all processes into it and ejecting any occupants. \ Do not allow the mech to leave the station's vicinity or allow it to be destroyed. \ @@ -912,10 +912,10 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) Loss of signal will result in total system lockout.") unlock_sound = 'sound/mecha/nominal.ogg' -/datum/ai_module/upgrade/mecha_domination/upgrade(mob/living/silicon/ai/AI) +/datum/ai_module/malf/upgrade/mecha_domination/upgrade(mob/living/silicon/ai/AI) AI.can_dominate_mechs = TRUE //Yep. This is all it does. Honk! -/datum/ai_module/upgrade/voice_changer +/datum/ai_module/malf/upgrade/voice_changer name = "Voice Changer" description = "Allows you to change the AI's voice. Upgrade is active immediately upon purchase." cost = 40 @@ -1053,7 +1053,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) if("name") say_name = strip_html(params["name"], MAX_NAME_LEN) -/datum/ai_module/utility/emag +/datum/ai_module/malf/utility/emag name = "Targeted Safeties Override" description = "Allows you to disable the safeties of any machinery on the station, provided you can access it." cost = 20 @@ -1147,7 +1147,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) return TRUE -/datum/ai_module/utility/core_tilt +/datum/ai_module/malf/utility/core_tilt name = "Rolling Servos" description = "Allows you to slowly roll around, crushing anything in your way with your bulk." cost = 10 @@ -1246,7 +1246,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) stack_trace("non-standard dir entered to get_rotation_from_dir. (got: [dir])") return 0 -/datum/ai_module/utility/remote_vendor_tilt +/datum/ai_module/malf/utility/remote_vendor_tilt name = "Remote vendor tilting" description = "Lets you remotely tip vendors over in any direction." cost = 15 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index f0712766fa6..d53d1ddda4d 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1034,7 +1034,7 @@ malf_picker.processing_time += 10 var/area/apcarea = apc.area - var/datum/ai_module/destructive/nuke_station/doom_n_boom = locate(/datum/ai_module/destructive/nuke_station) in malf_picker.possible_modules["Destructive Modules"] + var/datum/ai_module/malf/destructive/nuke_station/doom_n_boom = locate(/datum/ai_module/malf/destructive/nuke_station) in malf_picker.possible_modules["Destructive Modules"] if(doom_n_boom && (is_type_in_list (apcarea, doom_n_boom.discount_areas)) && !(is_type_in_list (apcarea, doom_n_boom.hacked_command_areas))) doom_n_boom.hacked_command_areas += apcarea doom_n_boom.cost = max(50, 130 - (length(doom_n_boom.hacked_command_areas) * 20)) diff --git a/code/modules/mob/living/silicon/ai/ai_actions/remote_power.dm b/code/modules/mob/living/silicon/ai/ai_actions/remote_power.dm new file mode 100644 index 00000000000..fd45ed3d687 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_actions/remote_power.dm @@ -0,0 +1,41 @@ +/datum/ai_module/power_apc + name = "Remote Power" + description = "remotely powers an APC from a distance" + one_purchase = TRUE + power_type = /datum/action/innate/ai/ranged/power_apc + unlock_text = span_notice("Remote APC power systems online.") + +/datum/action/innate/ai/ranged/power_apc + name = "remotely power APC" + desc = "Use to remotely power an APC." + button_icon = 'icons/obj/machines/wallmounts.dmi' + button_icon_state = "apc0" + ranged_mousepointer = 'icons/effects/mouse_pointers/supplypod_target.dmi' + enable_text = span_notice("You prepare to power any APC you see.") + disable_text = span_notice("You stop focusing on powering APCs.") + +/datum/action/innate/ai/ranged/power_apc/do_ability(mob/living/caller, atom/clicked_on) + + if (!isAI(caller)) + return FALSE + var/mob/living/silicon/ai/ai_caller = caller + + if(caller.incapacitated) + unset_ranged_ability(caller) + return FALSE + + if(!isapc(clicked_on)) + clicked_on.balloon_alert(ai_caller, "not an APC!") + return FALSE + + if(ai_caller.battery - 50 <= 0) + to_chat(ai_caller, span_warning("You do not have the battery to charge an APC!")) + return FALSE + + var/obj/machinery/power/apc/apc = clicked_on + var/obj/item/stock_parts/power_store/cell = apc.get_cell() + cell.give(STANDARD_BATTERY_CHARGE) + ai_caller.battery -= 50 + + + diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 34aa7a0714a..4adfe057c59 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -13,13 +13,13 @@ view_core() // Handle power damage (oxy) + if (battery <= 0) + to_chat(src, span_warning("Your backup battery's output drops below usable levels. It takes only a moment longer for your systems to fail, corrupted and unusable.")) + adjustOxyLoss(200) + if(aiRestorePowerRoutine) // Lost power - if (!battery) - to_chat(src, span_warning("Your backup battery's output drops below usable levels. It takes only a moment longer for your systems to fail, corrupted and unusable.")) - adjustOxyLoss(200) - else - battery-- + battery-- else // Gain Power if (battery < 200) diff --git a/code/modules/research/designs/electronics_designs.dm b/code/modules/research/designs/electronics_designs.dm index ce607639e22..b1da9f2c1c0 100644 --- a/code/modules/research/designs/electronics_designs.dm +++ b/code/modules/research/designs/electronics_designs.dm @@ -33,7 +33,19 @@ id = "ai_cam_upgrade" build_type = PROTOLATHE | AWAY_LATHE materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/gold = SHEET_MATERIAL_AMOUNT * 7.5, /datum/material/silver = SHEET_MATERIAL_AMOUNT * 7.5, /datum/material/diamond = SHEET_MATERIAL_AMOUNT * 10, /datum/material/plasma = SHEET_MATERIAL_AMOUNT * 5) - build_path = /obj/item/surveillance_upgrade + build_path = /obj/item/aiupgrade/surveillance_upgrade + category = list( + RND_CATEGORY_AI + RND_SUBCATEGORY_AI_UPGRADES + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/ai_power_transfer + name = "AI Power Transfer Update" + desc = "An upgrade package that lets an AI charge an APC from a distance" + id = "ai_power_upgrade" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5) + build_path = /obj/item/aiupgrade/power_transfer category = list( RND_CATEGORY_AI + RND_SUBCATEGORY_AI_UPGRADES ) diff --git a/code/modules/research/techweb/nodes/robo_nodes.dm b/code/modules/research/techweb/nodes/robo_nodes.dm index 9cfa3028961..2b43ba0e425 100644 --- a/code/modules/research/techweb/nodes/robo_nodes.dm +++ b/code/modules/research/techweb/nodes/robo_nodes.dm @@ -69,7 +69,7 @@ /datum/techweb_node/ai_laws id = TECHWEB_NODE_AI_LAWS - display_name = "Advanced AI Laws" + display_name = "Advanced AI Upgrades" description = "Delving into sophisticated AI directives, with hopes that they won't lead to humanity's extinction." prereq_ids = list(TECHWEB_NODE_AI) design_ids = list( @@ -94,6 +94,7 @@ "freeformcore_module", "onehuman_module", "purge_module", + "ai_power_upgrade" ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) announce_channels = list(RADIO_CHANNEL_SCIENCE, RADIO_CHANNEL_COMMAND) diff --git a/tgstation.dme b/tgstation.dme index 468ff56552f..9f805fd9adc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5207,6 +5207,7 @@ #include "code\modules\mob\living\silicon\ai\multicam.dm" #include "code\modules\mob\living\silicon\ai\robot_control.dm" #include "code\modules\mob\living\silicon\ai\vox_sounds.dm" +#include "code\modules\mob\living\silicon\ai\ai_actions\remote_power.dm" #include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm" #include "code\modules\mob\living\silicon\ai\freelook\chunk.dm" #include "code\modules\mob\living\silicon\ai\freelook\eye.dm"