Moves and documents AI's definition (+ minor cleanup) (#88928)

## About The Pull Request

The AI's definition is big and unorganized, which makes figuring out
what does what really annoying, so I took the time to document and
organize the file

Some vars have been renamed to better communicate what they actually do
when reading code
Unused vars have been deleted:
* var/chnotify
* var/waypoint
* var/interfaceButton

### Misc changes:
The check to see if malf modules could be used was written incorrectly,
and therefore all malf modules could be used without cooldown. The check
has been fixed, so actions which used to have no cooldown should now

AI bot summoning was supposed to have a cooldown, but it was broken and
not implemented for basic bots. This has been removed instead of fixed,
since I found it was an unnecessary limitation for something so simple.

## Changelog

🆑
fix: Malf modules correctly use action cooldown (affects camera repair
and detonate RCDs)
code: Minor (extremely minor) AI code maintenance
/🆑
This commit is contained in:
tonty
2025-01-15 13:37:54 +00:00
committed by GitHub
parent 15d43c63aa
commit d3866d01f1
10 changed files with 185 additions and 123 deletions
+2 -2
View File
@@ -73,8 +73,8 @@
if(world.time <= next_move)
return
if(waypoint_mode)
waypoint_mode = 0
if(setting_waypoint)
setting_waypoint = FALSE
set_waypoint(A)
return
-1
View File
@@ -309,7 +309,6 @@
using = new /atom/movable/screen/ai/modpc(null, src)
using.screen_loc = ui_ai_mod_int
static_inventory += using
myai.interfaceButton = using
var/atom/movable/screen/ai/modpc/tabletbutton = using
tabletbutton.robot = myai
@@ -63,12 +63,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf))
button_icon = 'icons/mob/actions/actions_AI.dmi'
/// The owner AI, so we don't have to typecast every time
var/mob/living/silicon/ai/owner_AI
/// If we have multiple uses of the same power
var/uses
/// Amount of uses for this action. Defining this as 0 will make this infinite-use
var/uses = FALSE
/// If we automatically use up uses on each activation
var/auto_use_uses = TRUE
/// If applicable, the time in deciseconds we have to wait before using any more modules
var/cooldown_period
var/cooldown_period = 0 SECONDS
/datum/action/innate/ai/Grant(mob/living/player)
. = ..()
@@ -79,16 +79,16 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf))
owner_AI = owner
/datum/action/innate/ai/IsAvailable(feedback = FALSE)
if(owner_AI && !COOLDOWN_FINISHED(owner_AI, malf_cooldown))
return FALSE
. = ..()
if(owner_AI && owner_AI.malf_cooldown > world.time)
return
/datum/action/innate/ai/Trigger(trigger_flags)
. = ..()
if(auto_use_uses)
adjust_uses(-1)
if(cooldown_period)
owner_AI.malf_cooldown = world.time + cooldown_period
COOLDOWN_START(owner_AI, malf_cooldown, cooldown_period)
/datum/action/innate/ai/proc/adjust_uses(amt, silent)
uses += amt
@@ -188,6 +188,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf))
set_up_us_the_bomb(owner)
/datum/action/innate/ai/nuke_station/proc/set_up_us_the_bomb(mob/living/owner)
//oh my GOD.
set waitfor = FALSE
message_admins("[key_name_admin(owner)][ADMIN_FLW(owner)] has activated AI Doomsday.")
var/pass = prob(10) ? "******" : "hunter2"
@@ -807,7 +808,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf))
button_icon_state = "reactivate_cameras"
uses = 30
auto_use_uses = FALSE
cooldown_period = 30
cooldown_period = 3 SECONDS
/datum/action/innate/ai/reactivate_cameras/New()
..()
+1 -1
View File
@@ -13,7 +13,7 @@
var/use_visibility = TRUE
/// List of [camera chunks][/datum/camerachunk] visible to this camera.
/// Please don't interface with this directly. Use the [cameranet][/datum/cameranet].
var/final/list/datum/camerachunk/visibleCameraChunks = list()
VAR_FINAL/list/datum/camerachunk/visibleCameraChunks = list()
/// NxN Range of a single camera chunk.
var/static_visibility_range = 16
+1 -106
View File
@@ -1,108 +1,7 @@
#define CALL_BOT_COOLDOWN 900
#define HOLOGRAM_CHOICE_CHARACTER "Existing Character"
#define CHARACTER_TYPE_SELF "My Character"
#define CHARACTER_TYPE_CREWMEMBER "Station Member"
/mob/living/silicon/ai
name = "AI"
real_name = "AI"
icon = 'icons/mob/silicon/ai.dmi'
icon_state = "ai"
move_resist = MOVE_FORCE_OVERPOWERING
density = TRUE
status_flags = CANSTUN|CANPUSH
combat_mode = TRUE //so we always get pushed instead of trying to swap
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
hud_type = /datum/hud/ai
silicon_huds = list(DATA_HUD_MEDICAL_BASIC, DATA_HUD_SECURITY_BASIC, DATA_HUD_DIAGNOSTIC, DATA_HUD_BOT_PATH)
mob_size = MOB_SIZE_LARGE
radio = /obj/item/radio/headset/silicon/ai
can_buckle_to = FALSE
var/battery = 200 //emergency power if the AI's APC is off
var/list/network = list(CAMERANET_NETWORK_SS13)
var/obj/machinery/camera/current
var/list/connected_robots = list()
var/aiRestorePowerRoutine = POWER_RESTORATION_OFF
var/requires_power = POWER_REQ_ALL
var/can_be_carded = TRUE
var/mutable_appearance/hologram_appearance //Default is assigned when AI is created.
var/obj/controlled_equipment //A piece of equipment, to determine whether to relaymove or use the AI eye.
var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not.
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
///Used as a fake multitoool in tcomms machinery
var/obj/item/multitool/aiMulti
///Weakref to the bot the ai's commanding right now
var/datum/weakref/bot_ref
var/datum/effect_system/spark_spread/spark_system //So they can initialize sparks whenever
//MALFUNCTION
var/datum/module_picker/malf_picker
var/list/datum/ai_module/current_modules = list()
var/can_dominate_mechs = FALSE
var/shunted = FALSE //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead
var/obj/machinery/ai_voicechanger/ai_voicechanger = null // reference to machine that holds the voicechanger
var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite
/// List of hacked APCs
var/list/hacked_apcs = list()
var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown
var/obj/machinery/power/apc/malfhack
var/explosive = FALSE //does the AI explode when it dies?
var/camera_light_on = FALSE
var/list/obj/machinery/camera/lit_cameras = list()
///The internal tool used to track players visible through cameras.
var/datum/trackable/ai_tracking_tool
var/last_tablet_note_seen = null
var/can_shunt = TRUE
var/last_announcement = "" // For AI VOX, if enabled
var/turf/waypoint //Holds the turf of the currently selected waypoint.
var/waypoint_mode = FALSE //Waypoint mode is for selecting a turf via clicking.
var/call_bot_cooldown = 0 //time of next call bot command
var/obj/machinery/power/apc/apc_override //Ref of the AI's APC, used when the AI has no power in order to access their APC.
var/nuking = FALSE
var/obj/machinery/doomsday_device/doomsday_device
var/mob/eye/camera/ai/eyeobj
var/sprint = 10
var/last_moved = 0
var/acceleration = TRUE
var/obj/structure/ai_core/deactivated/linked_core //For exosuit control
var/mob/living/silicon/robot/deployed_shell = null //For shell control
var/datum/action/innate/deploy_shell/deploy_action = new
var/datum/action/innate/deploy_last_shell/redeploy_action = new
var/datum/action/innate/choose_modules/modules_action
var/chnotify = 0
var/multicam_on = FALSE
var/atom/movable/screen/movable/pic_in_pic/ai/master_multicam
var/list/multicam_screens = list()
var/list/all_eyes = list()
var/max_multicams = 6
var/display_icon_override
var/list/cam_hotkeys = new/list(9)
var/atom/cam_prev
var/datum/robot_control/robot_control
/// Station alert datum for showing alerts UI
var/datum/station_alert/alert_control
///remember AI's last location
var/atom/lastloc
interaction_range = INFINITY
var/atom/movable/screen/ai/modpc/interfaceButton
///whether its mmi is a posibrain or regular mmi when going ai mob to ai core structure
var/posibrain_inside = TRUE
///whether its cover is opened, so you can wirecut it for deconstruction
var/opened = FALSE
///whether AI is anchored or not, used for checks
var/is_anchored = TRUE
/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai)
. = ..()
if(!target_ai) //If there is no player/brain inside.
@@ -608,9 +507,7 @@
summon_success = basic_bot.summon_bot(src, waypoint, grant_all_access = TRUE)
else
var/mob/living/simple_animal/bot/simple_bot = bot
call_bot_cooldown = world.time + CALL_BOT_COOLDOWN
summon_success = simple_bot.call_bot(src, waypoint)
call_bot_cooldown = 0
var/chat_message = summon_success ? "Sending command to bot..." : "Interface error. Unit is already in use."
to_chat(src, span_notice("[chat_message]"))
@@ -1004,7 +901,7 @@
/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc)
malfhack = null
malfhacking = 0
malfhacking = FALSE
clear_alert(ALERT_HACKING_APC)
if(!istype(apc) || QDELETED(apc) || apc.machine_stat & BROKEN)
@@ -1181,8 +1078,6 @@
return ai_voicechanger.say_name
return
#undef CALL_BOT_COOLDOWN
#undef HOLOGRAM_CHOICE_CHARACTER
#undef CHARACTER_TYPE_SELF
#undef CHARACTER_TYPE_CREWMEMBER
@@ -0,0 +1,169 @@
/mob/living/silicon/ai
name = "AI"
real_name = "AI"
icon = 'icons/mob/silicon/ai.dmi'
icon_state = "ai"
move_resist = MOVE_FORCE_OVERPOWERING
density = TRUE
status_flags = CANSTUN|CANPUSH
combat_mode = TRUE //so we always get pushed instead of trying to swap
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
hud_type = /datum/hud/ai
mob_size = MOB_SIZE_LARGE
can_buckle_to = FALSE
silicon_huds = list(DATA_HUD_MEDICAL_BASIC, DATA_HUD_SECURITY_BASIC, DATA_HUD_DIAGNOSTIC, DATA_HUD_BOT_PATH)
radio = /obj/item/radio/headset/silicon/ai
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
/* INITIALIZATION */
/// If FALSE, attempts to [obj/item/aicard][card] the AI will be rejected
var/can_be_carded = TRUE
/// If TRUE, the AI will explode when killed
var/explodes_on_death = FALSE
/// Whether its MMI is a posibrain or regular MMI, used when being [obj/structure/ai_core][deconstructed]
var/posibrain_inside = TRUE
/* STATE */
/// If this AI can use their radio
var/radio_enabled = TRUE
/// Whether its cover is opened, so you can wirecut it for deconstruction
var/opened = FALSE
/// If the AI is currently anchored to the ground, used for checks. Distinct from [atom/movable/anchored]
var/is_anchored = TRUE
/// Raw HTML containing the last page that was loaded from a held-up PDA
VAR_FINAL/last_tablet_note_seen = null
/// The last attempted VOX announcement. Exists so that failed VOXes can be retried easily
VAR_FINAL/last_announcement = ""
/// AI core icon_state selected by the AI through [verb/pick_icon]
var/display_icon_override
/* ROBOTS */
/// List of robots currently synced to the AI
VAR_FINAL/list/mob/living/silicon/robot/connected_robots = list()
/* POWER */
/// Reserve emergency power, consumed when the AI has no [var/power_requirement][power source]
var/battery = 200
/// The conditions the AI will check to see if it's powered, can be set to NONE (0) to disable requirements
var/power_requirement = POWER_REQ_ALL
/// Current stage of the AI's power restoration routine
VAR_FINAL/aiRestorePowerRoutine = POWER_RESTORATION_OFF
/// The APC the AI is powered from, set when the AI has no power in order to access their APC
VAR_FINAL/obj/machinery/power/apc/apc_override
/* CAMERA */
/// The network that the AI is currently viewing
var/list/network = list(CAMERANET_NETWORK_SS13)
/// If the AI has their camera light enabled
var/camera_light_on = FALSE
/// List of cameras that have been illuminated by the AI's camera light
VAR_FINAL/list/obj/machinery/camera/lit_cameras = list()
/// List of atoms that the AI's camera can quickly jump to through keys 1-9
VAR_FINAL/list/atom/cam_hotkeys = new/list(9)
/// The camera's last location before jumping
VAR_FINAL/atom/cam_prev
/* CAMERA EYE */
/// The AI's **main** eye
VAR_FINAL/mob/eye/camera/ai/eyeobj
/// List of [mob/eye/camera/ai][camera eyes] that the AI has created, including the [var/eyeobj][main eye]
VAR_FINAL/list/mob/eye/camera/ai/all_eyes = list()
/// The internal tool used to track players visible through cameras
VAR_FINAL/datum/trackable/ai_tracking_tool
/// The current movement speed of the camera, it's definition being the base speed. Moves 1 more tile for every 10 sprint.
var/sprint = 10
/// Time since the AI [proc/AIMove][last moved their camera eye], uses world.timeofday
VAR_FINAL/last_moved = 0
/// If the camera eye [proc/AIMove][moves progressively faster] when looking around
var/acceleration = TRUE
/* MALFUNCTION */
/// UI for picking malfunction modules
VAR_FINAL/datum/module_picker/malf_picker
/// Opens the [datum/module_picker][malf module UI]
VAR_FINAL/datum/action/innate/choose_modules/modules_action
/// Modules that the AI has already unlocked
VAR_FINAL/list/datum/ai_module/current_modules = list()
/// Cooldown between malf module usages
COOLDOWN_DECLARE(malf_cooldown)
/// Timer used when hacking an APC
VAR_FINAL/malfhacking = FALSE //--NeoFite was here
/// APC that we are currently hacking
VAR_FINAL/obj/machinery/power/apc/malfhack
/// APCs that the AI has already hacked
VAR_FINAL/list/hacked_apcs = list()
/// If TRUE, the AI can take control over mechs
var/can_dominate_mechs = FALSE
/// If TRUE, the AI can shunt themselves into APCs
var/can_shunt = TRUE
/// TRUE if the AI is currently shunted, used to differentiate between shunted and ghosted/braindead
VAR_FINAL/shunted = FALSE
/// If the AI has enabled doomsday
VAR_FINAL/nuking = FALSE
/// Reference to the doomsday device
VAR_FINAL/obj/machinery/doomsday_device/doomsday_device
/// Reference to machine that holds the voicechanger
VAR_FINAL/obj/machinery/ai_voicechanger/ai_voicechanger
/* REMOTE CONTROL */
/// Equipment that the AI is controlling remotely, to determine whether to relaymove or use the AI eye
VAR_FINAL/obj/controlled_equipment
/// AI core that this AI is linked to, used when put into an exosuit
VAR_FINAL/obj/structure/ai_core/deactivated/linked_core
/// Robot that this AI is currently using
VAR_FINAL/mob/living/silicon/robot/deployed_shell
/// Action to deploy to a shell from a list of options
VAR_FINAL/datum/action/innate/deploy_shell/deploy_action = new()
/// Action to deploy to the last shell the AI used
VAR_FINAL/datum/action/innate/deploy_last_shell/redeploy_action = new()
/* MULTICAMERA */
/// If the AI is in multicamera mode
VAR_FINAL/multicam_on = FALSE
/// Maximum multicamera windows the AI can have open
var/max_multicams = 6
/// The multicamera window that the AI is currently using
VAR_FINAL/atom/movable/screen/movable/pic_in_pic/ai/master_multicam
/// All of the AI's currently open multicamera windows
VAR_FINAL/list/atom/movable/screen/movable/pic_in_pic/ai/multicam_screens = list()
/* ROBOT CONTROL */
/// UI for robot controls
VAR_FINAL/datum/robot_control/robot_control
/// Weakref to the bot the AI is currently commanding
VAR_FINAL/datum/weakref/bot_ref
/// If TRUE, the AI will send it's [var/bot_ref][commanded bot] to the next clicked atom
VAR_FINAL/setting_waypoint = FALSE
/* HOLOGRAM */
/// The AI eye's last location, used when answering a hologram request
VAR_FINAL/atom/lastloc
/// The AI's hologram appearance, can be set by a client and is assigned on AI creation
VAR_FINAL/mutable_appearance/hologram_appearance
/// The AI's currently used holopad
VAR_FINAL/obj/machinery/holopad/current
/* UI */
/// UI for station alerts
VAR_FINAL/datum/station_alert/alert_control
/* I'M DUMB AND CAN'T SORT */
/// Used as a fake multitool in tcomms machinery
VAR_FINAL/obj/item/multitool/aiMulti
/// Helper effect that creates sparks when the AI is damaged
VAR_FINAL/datum/effect_system/spark_spread/spark_system
+1 -1
View File
@@ -36,7 +36,7 @@
if(gibbed && drop_mmi)
make_mmi_drop_and_transfer()
if(explosive)
if(explodes_on_death)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), loc, 3, 6, 12, null, 15), 1 SECONDS)
SSblackbox.ReportDeath(src)
+1 -1
View File
@@ -40,7 +40,7 @@
/mob/living/silicon/ai/proc/lacks_power()
var/turf/T = get_turf(src)
var/area/A = get_area(src)
switch(requires_power)
switch(power_requirement)
if(NONE)
return FALSE
if(POWER_REQ_ALL)
@@ -84,9 +84,6 @@
switch(action)
if("callbot") //Command a bot to move to a selected location.
if(owner.call_bot_cooldown > world.time)
to_chat(our_user, span_danger("Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route."))
return
if(isbasicbot(bot))
var/mob/living/basic/bot/basic_bot = bot
if(!(basic_bot.bot_mode_flags & BOT_MODE_REMOTE_ENABLED))
@@ -97,7 +94,7 @@
return
owner.bot_ref = WEAKREF(bot)
owner.waypoint_mode = TRUE
owner.setting_waypoint = TRUE
to_chat(our_user, span_notice("Set your waypoint by clicking on a valid location free of obstructions."))
if("interface") //Remotely connect to a bot!
owner.bot_ref = WEAKREF(bot)
+1
View File
@@ -5303,6 +5303,7 @@
#include "code\modules\mob\living\silicon\ai\_preferences.dm"
#include "code\modules\mob\living\silicon\ai\ai.dm"
#include "code\modules\mob\living\silicon\ai\ai_defense.dm"
#include "code\modules\mob\living\silicon\ai\ai_defines.dm"
#include "code\modules\mob\living\silicon\ai\ai_portrait_picker.dm"
#include "code\modules\mob\living\silicon\ai\ai_say.dm"
#include "code\modules\mob\living\silicon\ai\death.dm"