mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-21 12:02:31 +01:00
AI Display Fix + AI.dm Improvements (#21132)
Fixes https://github.com/Aurorastation/Aurora.3/issues/20503 Adds documentation to AI.dm and refactors procs that handle AI Announcements and AI Emergency Messages --------- Co-authored-by: Ben10083 <Ben10083@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#define AI_CHECK_WIRELESS 1
|
||||
#define AI_CHECK_RADIO 2
|
||||
#define AI_ANNOUNCEMENT_COOLDOWN 1 MINUTE
|
||||
#define AI_EMERGENCY_MESSAGE_COOLDOWN 30 SECONDS
|
||||
|
||||
GLOBAL_LIST_INIT_TYPED(ai_list, /mob/living/silicon/ai, list())
|
||||
|
||||
@@ -55,19 +57,23 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/carded
|
||||
|
||||
// Holopad and holograms
|
||||
var/mob/holo_icon // an abstract mob used to store icon info
|
||||
var/hologram_follow = TRUE //This is used for the AI eye, to determine if a holopad's hologram should follow it or not
|
||||
/// An abstract mob used to store icon info
|
||||
var/mob/holo_icon
|
||||
/// This is used for the AI eye, to determine if a holopad's hologram should follow it or not
|
||||
var/hologram_follow = TRUE
|
||||
|
||||
// Equipment
|
||||
/// What camera network the AI can view
|
||||
var/list/network = list("Station")
|
||||
var/obj/machinery/camera/camera
|
||||
var/list/cameraRecords = list() //For storing what is shown to the cameras
|
||||
/// For storing what is shown to the cameras
|
||||
var/list/cameraRecords = list()
|
||||
var/obj/item/device/multitool/ai_multi
|
||||
var/obj/item/device/radio/headset/heads/ai_integrated/ai_radio
|
||||
var/datum/announcement/priority/announcement
|
||||
var/obj/machinery/ai_powersupply/psupply
|
||||
|
||||
// Borgs
|
||||
/// Borgs linked to AI
|
||||
var/list/connected_robots = list()
|
||||
|
||||
// Damage variables
|
||||
@@ -77,35 +83,59 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
// Misc variables
|
||||
var/last_announcement = ""
|
||||
/// Uses `world.time` to track when the last announcement was made. Used in `ai_announcement()`
|
||||
var/last_announcement_time
|
||||
/// Uses `world.time` to track when the last emergency message was sent. Used in `ai_emergency_message()`
|
||||
var/last_emergency_message_time
|
||||
/// If TRUE, AI is on backup power (restricts most actions)
|
||||
var/ai_restore_power_routine = FALSE
|
||||
var/view_alerts = FALSE
|
||||
var/camera_light_on = FALSE //Defines if the AI toggled the light on the camera it's looking through.
|
||||
/// Defines if the AI toggled the light on the camera it's looking through.
|
||||
var/camera_light_on = FALSE
|
||||
var/datum/trackable/track
|
||||
var/control_disabled = FALSE
|
||||
var/multitool_mode = FALSE
|
||||
|
||||
// Malf variables
|
||||
var/malfunctioning = FALSE // Master var that determines if AI is malfunctioning.
|
||||
var/datum/malf_hardware/hardware // Installed piece of hardware.
|
||||
var/datum/malf_research/research // Malfunction research datum.
|
||||
var/obj/machinery/power/apc/hack // APC that is currently being hacked.
|
||||
var/list/hacked_apcs = list() // List of all hacked APCs
|
||||
var/APU_power = FALSE // If set to 1 AI runs on APU power
|
||||
var/hacking = FALSE // Set to 1 if AI is hacking APC, cyborg, other AI, or running system override.
|
||||
var/system_override = FALSE // Set to 1 if system override is initiated, 2 if succeeded.
|
||||
var/synthetic_takeover = FALSE // 1 is started, 2 is complete.
|
||||
var/hack_can_fail = TRUE // If 0, all abilities have zero chance of failing.
|
||||
var/hack_fails = 0 // This increments with each failed hack, and determines the warning message text.
|
||||
var/errored = FALSE // Set to 1 if runtime error occurs. Only way of this happening i can think of is admin fucking up with varedit.
|
||||
var/bombing_core = FALSE // Set to 1 if core auto-destruct is activated
|
||||
var/bombing_station = FALSE // Set to 1 if station nuke auto-destruct is activated
|
||||
var/bombing_time = 1200 // How much time is remaining for the nuke
|
||||
var/override_CPUStorage = 0 // Bonus/Penalty CPU Storage. For use by admins/testers.
|
||||
var/override_CPURate = 0 // Bonus/Penalty CPU generation rate. For use by admins/testers.
|
||||
/// Master var that determines if AI is malfunctioning.
|
||||
var/malfunctioning = FALSE
|
||||
/// Installed piece of Malfunction hardware.
|
||||
var/datum/malf_hardware/hardware
|
||||
/// Malfunction research datum.
|
||||
var/datum/malf_research/research
|
||||
/// APC that is currently being hacked.
|
||||
var/obj/machinery/power/apc/hack
|
||||
/// List of all hacked APCs
|
||||
var/list/hacked_apcs = list()
|
||||
/// If set to TRUE AI runs on APU power
|
||||
var/APU_power = FALSE
|
||||
/// Set to TRUE if AI is hacking APC, cyborg, other AI, or running system override.
|
||||
var/hacking = FALSE
|
||||
/// Set to 1 if system override is initiated, 2 if succeeded.
|
||||
var/system_override = 0
|
||||
/// Set to 1 if synthetic takeover has started, 2 if it is complete.
|
||||
var/synthetic_takeover = FALSE
|
||||
/// If FALSE, all abilities have zero chance of failing.
|
||||
var/hack_can_fail = TRUE
|
||||
/// This increments with each failed hack, and determines the warning message text.
|
||||
var/hack_fails = 0
|
||||
/// Set to TRUE if runtime error occurs. Only way of this happening i can think of is admin fucking up with varedit.
|
||||
var/errored = FALSE
|
||||
/// Set to TRUE if core auto-destruct is activated
|
||||
var/bombing_core = FALSE
|
||||
/// Set to TRUE if station nuke auto-destruct is activated
|
||||
var/bombing_station = FALSE
|
||||
/// How much time is remaining for the nuke
|
||||
var/bombing_time = 1200
|
||||
/// Bonus/Penalty CPU Storage. For use by admins/testers.
|
||||
var/override_CPUStorage = 0
|
||||
/// Bonus/Penalty CPU generation rate. For use by admins/testers.
|
||||
var/override_CPURate = 0
|
||||
|
||||
// Sprites
|
||||
var/datum/ai_icon/selected_sprite // The selected icon set
|
||||
var/custom_sprite = FALSE // Whether the selected icon is custom
|
||||
/// The selected icon set
|
||||
var/datum/ai_icon/selected_sprite
|
||||
/// Whether the selected icon is custom
|
||||
var/custom_sprite = FALSE
|
||||
|
||||
/mob/living/silicon/ai/proc/add_ai_verbs()
|
||||
add_verb(src, GLOB.ai_verbs_default)
|
||||
@@ -293,6 +323,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
set src = usr.contents
|
||||
return FALSE
|
||||
|
||||
/// Proc override for AI SetName()
|
||||
/mob/living/silicon/ai/SetName(pickedName as text)
|
||||
..()
|
||||
announcement.announcer = pickedName
|
||||
@@ -311,9 +342,9 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
setup_icon() //this is because the ai custom name is related to the ai name, so, we just call the setup icon after someone named their ai
|
||||
SSrecords.reset_manifest()
|
||||
|
||||
/*
|
||||
The AI Power supply is a dummy object used for powering the AI since only machinery should be using power.
|
||||
The alternative was to rewrite a bunch of AI code instead here we are.
|
||||
/**
|
||||
* The AI Power supply is a dummy object used for powering the AI since only machinery should be using power.
|
||||
* The alternative was to rewrite a bunch of AI code instead here we are.
|
||||
*/
|
||||
/obj/machinery/ai_powersupply
|
||||
name = "power supply"
|
||||
@@ -393,16 +424,16 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
if (!custom_sprite)
|
||||
var/new_sprite = tgui_input_list(src, "Select an icon!", "AI", GLOB.ai_icons, selected_sprite)
|
||||
if(new_sprite) selected_sprite = new_sprite
|
||||
if(new_sprite) selected_sprite = GLOB.ai_icons[new_sprite]
|
||||
update_icon()
|
||||
|
||||
// this verb lets the ai see the stations manifest
|
||||
/// This verb lets the ai see the stations manifest
|
||||
/mob/living/silicon/ai/proc/ai_roster()
|
||||
set category = "AI Commands"
|
||||
set name = "Show Crew Manifest"
|
||||
SSrecords.open_manifest_tgui(usr)
|
||||
|
||||
//AI Examine code
|
||||
/// AI Examine code
|
||||
/mob/living/silicon/ai/proc/ai_examine(atom/A as mob|obj|turf in view(src.eyeobj))
|
||||
set category = "AI Commands"
|
||||
set name = "Examine"
|
||||
@@ -414,29 +445,33 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
face_atom(A)
|
||||
A.examine(src)
|
||||
|
||||
/mob/living/silicon/ai/var/message_cooldown = 0
|
||||
/**
|
||||
* AI verb to make announcements
|
||||
*
|
||||
* `last_announcement_time` is compared with `world.time` and `AI_ANNOUNCEMENT_COOLDOWN` to prevent announcement spam
|
||||
*/
|
||||
/mob/living/silicon/ai/proc/ai_announcement()
|
||||
set category = "AI Commands"
|
||||
set name = "Make Station Announcement"
|
||||
set name = "Make Ship-wide Announcement"
|
||||
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if(message_cooldown)
|
||||
to_chat(src, "Please allow one minute to pass between announcements.")
|
||||
return
|
||||
if((world.time - last_announcement_time) < AI_ANNOUNCEMENT_COOLDOWN)
|
||||
to_chat(src, SPAN_WARNING("You need to wait <b>[DisplayTimeText(AI_ANNOUNCEMENT_COOLDOWN - (world.time - last_announcement_time))]</b> before you can make another announcement."))
|
||||
return FALSE
|
||||
var/input = tgui_input_text(usr, "Please write a message to announce to the [station_name(TRUE)] crew.", "A.I. Announcement", multiline = TRUE)
|
||||
if(!input)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
announcement.Announce(input)
|
||||
message_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
message_cooldown = 0
|
||||
last_announcement_time = world.time
|
||||
return TRUE
|
||||
|
||||
/// Allows AI to call evacuation
|
||||
/mob/living/silicon/ai/proc/ai_call_shuttle()
|
||||
set category = "AI Commands"
|
||||
set name = "Call Evacuation"
|
||||
@@ -454,6 +489,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
post_display_status("shuttle")
|
||||
|
||||
/// Allows AI to cancel evacuation
|
||||
/mob/living/silicon/ai/proc/ai_recall_shuttle()
|
||||
set category = "AI Commands"
|
||||
set name = "Cancel Evacuation"
|
||||
@@ -468,28 +504,32 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
if(confirm == "Yes")
|
||||
cancel_call_proc(src)
|
||||
|
||||
/mob/living/silicon/ai/var/emergency_message_cooldown = 0
|
||||
/**
|
||||
* AI verb to send emergency message to Centcom (admins)
|
||||
*
|
||||
* `last_emergency_message_time` is compared with `world.time` and `AI_EMERGENCY_MESSAGE_COOLDOWN` to reduce message spam
|
||||
*/
|
||||
/mob/living/silicon/ai/proc/ai_emergency_message()
|
||||
set category = "AI Commands"
|
||||
set name = "Send Emergency Message"
|
||||
|
||||
if(check_unable(AI_CHECK_WIRELESS))
|
||||
return
|
||||
return FALSE
|
||||
if(!is_relay_online())
|
||||
to_chat(usr, SPAN_WARNING("No Emergency Bluespace Relay detected. Unable to transmit message."))
|
||||
return
|
||||
if(emergency_message_cooldown)
|
||||
to_chat(usr, SPAN_WARNING("Arrays recycling. Please stand by."))
|
||||
return
|
||||
return FALSE
|
||||
if((world.time - last_emergency_message_time) < AI_EMERGENCY_MESSAGE_COOLDOWN)
|
||||
to_chat(src, SPAN_WARNING("Arrays are recycling. You need to wait <b>[DisplayTimeText(AI_EMERGENCY_MESSAGE_COOLDOWN - (world.time - last_emergency_message_time))]</b> before you can send another message."))
|
||||
return FALSE
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to [SSatlas.current_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
|
||||
if(!input)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
Centcomm_announce(input, usr)
|
||||
to_chat(usr, SPAN_NOTICE("Message transmitted."))
|
||||
log_say("[key_name(usr)] has made an AI [SSatlas.current_map.boss_short] announcement: [input]")
|
||||
emergency_message_cooldown = 1
|
||||
spawn(300)
|
||||
emergency_message_cooldown = 0
|
||||
log_say("[key_name(usr)] has sent a message to [SSatlas.current_map.boss_short]: [input]")
|
||||
last_emergency_message_time = world.time
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/silicon/ai/check_eye(var/mob/user as mob)
|
||||
@@ -498,7 +538,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/restrained()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/ai/emp_act(severity)
|
||||
. = ..()
|
||||
@@ -594,9 +634,10 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
//src.cameraFollow = null
|
||||
src.view_core()
|
||||
|
||||
//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
|
||||
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead
|
||||
//Addition by Mord_Sith to define AI's network change ability
|
||||
/** Replaces `/mob/living/silicon/ai/verb/change_network()` in ai.dm & camera.dm
|
||||
* Adds in `/mob/living/silicon/ai/proc/ai_network_change()` instead
|
||||
* Addition by Mord_Sith to define AI's network change ability
|
||||
*/
|
||||
/mob/living/silicon/ai/proc/get_camera_network_list()
|
||||
if(check_unable())
|
||||
return
|
||||
@@ -633,7 +674,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
eyeobj.setLoc(get_turf(C))
|
||||
break
|
||||
to_chat(src, SPAN_NOTICE("Switched to [network] camera network."))
|
||||
//End of code by Mord_Sith
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_statuschange()
|
||||
set category = "AI Commands"
|
||||
@@ -695,7 +735,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
holo_icon.set_invisibility(0)
|
||||
holo_icon.icon = I
|
||||
|
||||
//Toggles the luminosity and applies it by re-entereing the camera.
|
||||
/// Toggles the luminosity and applies it by re-entereing the camera.
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light()
|
||||
set name = "Toggle Camera Light"
|
||||
set desc = "Toggles the light on the camera the AI is looking through."
|
||||
@@ -715,9 +755,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
|
||||
|
||||
// Handled camera lighting, when toggled.
|
||||
// It will get the nearest camera from the eyeobj, lighting it.
|
||||
|
||||
/// Handles camera lighting, when toggled, it will get the nearest camera from the `eyeobj`, lighting it.
|
||||
/mob/living/silicon/ai/proc/lightNearbyCamera()
|
||||
if(camera_light_on && camera_light_on < world.timeofday)
|
||||
if(src.camera)
|
||||
@@ -795,6 +833,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
to_chat(src, "Radio keys: [radio_keys]")
|
||||
src.ai_radio.interact(src)
|
||||
|
||||
/// Verb to call `toggle_sensor_mode()` from `silicon.dm`
|
||||
/mob/living/silicon/ai/proc/sensor_mode()
|
||||
set name = "Set Sensor Augmentation"
|
||||
set category = "AI Commands"
|
||||
@@ -829,6 +868,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
else
|
||||
SSvirtualreality.mind_transfer(src, choice)
|
||||
|
||||
/// AI verb to toggle `hologram_follow`
|
||||
/mob/living/silicon/ai/proc/toggle_hologram_movement()
|
||||
set name = "Toggle Hologram Movement"
|
||||
set category = "AI Commands"
|
||||
@@ -837,6 +877,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
hologram_follow = !hologram_follow
|
||||
to_chat(usr, "<span class='info'>Your hologram will now [hologram_follow ? "follow" : "no longer follow"] you.</span>")
|
||||
|
||||
/// Checks if AI is able to perform certain actions by checking if dead, depowered, disconnected, etc.
|
||||
/mob/living/silicon/ai/proc/check_unable(var/flags = 0, var/feedback = 1)
|
||||
if(stat == DEAD)
|
||||
if(feedback) to_chat(src, SPAN_WARNING("You are dead!"))
|
||||
@@ -858,6 +899,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
/mob/living/silicon/ai/proc/is_in_chassis()
|
||||
return istype(loc, /turf)
|
||||
|
||||
/// AI verb to toggle `multitool_mode`
|
||||
/mob/living/silicon/ai/proc/multitool_mode()
|
||||
set name = "Toggle Multitool Mode"
|
||||
set category = "AI Commands"
|
||||
@@ -878,7 +920,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
icon_state = selected_sprite.alive_icon
|
||||
set_light(1, 1, selected_sprite.alive_light)
|
||||
|
||||
// Pass lying down or getting up to our pet human, if we're in a rig.
|
||||
/// Pass lying down or getting up to our pet human, if we're in a rig.
|
||||
/mob/living/silicon/ai/lay_down()
|
||||
set name = "Rest"
|
||||
set category = "IC"
|
||||
@@ -904,8 +946,11 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
cameraRecords += list(s)
|
||||
return cameraRecords.len
|
||||
|
||||
/// Checks if AI is on backup power by checking`ai_restore_power_routine`. Returns TRUE if `ai_restore_power_routine` is FALSE
|
||||
/mob/living/silicon/ai/proc/has_power()
|
||||
return (ai_restore_power_routine == 0)
|
||||
return (ai_restore_power_routine == FALSE)
|
||||
|
||||
#undef AI_CHECK_WIRELESS
|
||||
#undef AI_CHECK_RADIO
|
||||
#undef AI_ANNOUNCEMENT_COOLDOWN
|
||||
#undef AI_EMERGENCY_MESSAGE_COOLDOWN
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GLOBAL_DATUM_INIT(default_ai_icon, /datum/ai_icon, new/datum/ai_icon/blue())
|
||||
GLOBAL_LIST_INIT_TYPED(ai_icons, /datum/ai_icon, null)
|
||||
GLOBAL_LIST_INIT_TYPED(ai_icons, /datum/ai_icon, list()) // Updated in misc_late.dm
|
||||
|
||||
/datum/ai_icon
|
||||
var/name
|
||||
@@ -19,9 +19,6 @@ GLOBAL_LIST_INIT_TYPED(ai_icons, /datum/ai_icon, null)
|
||||
src.alive_light = alive_light
|
||||
src.nopower_light = nopower_light
|
||||
src.dead_light = dead_light
|
||||
if(!GLOB.ai_icons)
|
||||
GLOB.ai_icons = list()
|
||||
init_subtypes(/datum/ai_icon, GLOB.ai_icons)
|
||||
..()
|
||||
|
||||
/datum/ai_icon/red
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
src << browse(HTML_SKELETON(dat), "window=checklanguage")
|
||||
return
|
||||
|
||||
/// Prompts the silicon mob which HUD to choose from, changes `sensor_mode` depending on choice
|
||||
/mob/living/silicon/proc/toggle_sensor_mode()
|
||||
var/sensor_type = tgui_input_list(src, "Please select sensor type.", "Sensor Integration", list("Security", "Medical", "Disable"))
|
||||
switch(sensor_type)
|
||||
|
||||
Reference in New Issue
Block a user