diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 200f56bed97..2238f43cc10 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -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 diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 0a4cf277712..1e50b838289 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -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 diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 00b581bcebf..22e32d8264a 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -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() ..() diff --git a/code/modules/mob/eye/camera/camera.dm b/code/modules/mob/eye/camera/camera.dm index 9f3ddc7b2ee..d407b3399b9 100644 --- a/code/modules/mob/eye/camera/camera.dm +++ b/code/modules/mob/eye/camera/camera.dm @@ -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 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index d5e74f24d4e..9c3b810dbf0 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -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 diff --git a/code/modules/mob/living/silicon/ai/ai_defines.dm b/code/modules/mob/living/silicon/ai/ai_defines.dm new file mode 100644 index 00000000000..2f63a0f9bb3 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_defines.dm @@ -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 diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 79e14d649fc..fb769563ef3 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -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) diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 3f86c64333e..b7da1203a09 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -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) diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index a04d1c3af75..94c99369b6c 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -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) diff --git a/tgstation.dme b/tgstation.dme index 78517181732..8f39003a2c3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -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"