Merge pull request #9747 from Ghommie/Ghommie-cit329

Fixing AI holopad speech text being small and whispers ending in multiple exclamation marks oxymoron.
This commit is contained in:
BlackMajor
2019-12-10 11:18:55 +13:00
committed by Archie
parent 5d80346f8f
commit 02cb328921
20 changed files with 4046 additions and 4044 deletions
@@ -98,7 +98,7 @@
else
to_chat(M, message)
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
to_chat(src, message)
@@ -118,7 +118,7 @@ the new instance inside the host to be updated to the template's stats.
follow_next(Dir & NORTHWEST)
last_move_tick = world.time
/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
var/atom/movable/to_follow = speaker
if(radio_freq)
@@ -130,7 +130,7 @@ the new instance inside the host to be updated to the template's stats.
else
link = ""
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
to_chat(src, "[link] [message]")
+101 -101
View File
@@ -1,101 +1,101 @@
#define INCLUSIVE_MODE 1
#define EXCLUSIVE_MODE 2
#define RECOGNIZER_MODE 3
#define VOICE_SENSOR_MODE 4
/obj/item/assembly/voice
name = "voice analyzer"
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
icon_state = "voice"
materials = list(MAT_METAL=500, MAT_GLASS=50)
flags_1 = HEAR_1
attachable = TRUE
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
var/listening = FALSE
var/recorded = "" //the activation message
var/mode = 1
var/static/list/modes = list("inclusive",
"exclusive",
"recognizer",
"voice sensor")
/obj/item/assembly/voice/examine(mob/user)
. = ..()
. += "<span class='notice'>Use a multitool to swap between \"inclusive\", \"exclusive\", \"recognizer\", and \"voice sensor\" mode.</span>"
/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
if(speaker == src)
return
if(listening && !radio_freq)
record_speech(speaker, raw_message, message_language)
else
if(check_activation(speaker, raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
switch(mode)
if(INCLUSIVE_MODE)
recorded = raw_message
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(EXCLUSIVE_MODE)
recorded = raw_message
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(RECOGNIZER_MODE)
recorded = speaker.GetVoice()
listening = FALSE
say("Your voice pattern is saved.", message_language)
if(VOICE_SENSOR_MODE)
if(length(raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
. = FALSE
switch(mode)
if(INCLUSIVE_MODE)
if(findtext(raw_message, recorded))
. = TRUE
if(EXCLUSIVE_MODE)
if(raw_message == recorded)
. = TRUE
if(RECOGNIZER_MODE)
if(speaker.GetVoice() == recorded)
. = TRUE
if(VOICE_SENSOR_MODE)
if(length(raw_message))
. = TRUE
/obj/item/assembly/voice/multitool_act(mob/living/user, obj/item/I)
mode %= modes.len
mode++
to_chat(user, "<span class='notice'>You set [src] into [modes[mode]] mode.</span>")
listening = FALSE
recorded = ""
return TRUE
/obj/item/assembly/voice/activate()
if(!secured || holder)
return FALSE
listening = !listening
say("[listening ? "Now" : "No longer"] recording input.")
return TRUE
/obj/item/assembly/voice/attack_self(mob/user)
if(!user)
return FALSE
activate()
return TRUE
/obj/item/assembly/voice/toggle_secure()
. = ..()
listening = FALSE
#undef INCLUSIVE_MODE
#undef EXCLUSIVE_MODE
#undef RECOGNIZER_MODE
#undef VOICE_SENSOR_MODE
#define INCLUSIVE_MODE 1
#define EXCLUSIVE_MODE 2
#define RECOGNIZER_MODE 3
#define VOICE_SENSOR_MODE 4
/obj/item/assembly/voice
name = "voice analyzer"
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
icon_state = "voice"
materials = list(MAT_METAL=500, MAT_GLASS=50)
flags_1 = HEAR_1
attachable = TRUE
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
var/listening = FALSE
var/recorded = "" //the activation message
var/mode = 1
var/static/list/modes = list("inclusive",
"exclusive",
"recognizer",
"voice sensor")
/obj/item/assembly/voice/examine(mob/user)
. = ..()
. += "<span class='notice'>Use a multitool to swap between \"inclusive\", \"exclusive\", \"recognizer\", and \"voice sensor\" mode.</span>"
/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(speaker == src)
return
if(listening && !radio_freq)
record_speech(speaker, raw_message, message_language)
else
if(check_activation(speaker, raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
switch(mode)
if(INCLUSIVE_MODE)
recorded = raw_message
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(EXCLUSIVE_MODE)
recorded = raw_message
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(RECOGNIZER_MODE)
recorded = speaker.GetVoice()
listening = FALSE
say("Your voice pattern is saved.", message_language)
if(VOICE_SENSOR_MODE)
if(length(raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
. = FALSE
switch(mode)
if(INCLUSIVE_MODE)
if(findtext(raw_message, recorded))
. = TRUE
if(EXCLUSIVE_MODE)
if(raw_message == recorded)
. = TRUE
if(RECOGNIZER_MODE)
if(speaker.GetVoice() == recorded)
. = TRUE
if(VOICE_SENSOR_MODE)
if(length(raw_message))
. = TRUE
/obj/item/assembly/voice/multitool_act(mob/living/user, obj/item/I)
mode %= modes.len
mode++
to_chat(user, "<span class='notice'>You set [src] into [modes[mode]] mode.</span>")
listening = FALSE
recorded = ""
return TRUE
/obj/item/assembly/voice/activate()
if(!secured || holder)
return FALSE
listening = !listening
say("[listening ? "Now" : "No longer"] recording input.")
return TRUE
/obj/item/assembly/voice/attack_self(mob/user)
if(!user)
return FALSE
activate()
return TRUE
/obj/item/assembly/voice/toggle_secure()
. = ..()
listening = FALSE
#undef INCLUSIVE_MODE
#undef EXCLUSIVE_MODE
#undef RECOGNIZER_MODE
#undef VOICE_SENSOR_MODE
@@ -859,7 +859,7 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 5
/obj/item/integrated_circuit/input/microphone/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
/obj/item/integrated_circuit/input/microphone/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
. = ..()
var/translated = FALSE
if(speaker && message)
+43 -43
View File
@@ -1,43 +1,43 @@
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if (!message)
return
var/message_mode = get_message_mode(message)
if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
message = copytext(message, 3)
if(findtext(message, " ", 1, 2))
message = copytext(message, 2)
if(message_mode == MODE_ADMIN)
client.cmd_admin_say(message)
else if(message_mode == MODE_DEADMIN)
client.dsay(message)
return
src.log_talk(message, LOG_SAY, tag="ghost")
if(check_emote(message))
return
. = say_dead(message)
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
var/atom/movable/to_follow = speaker
if(radio_freq)
var/atom/movable/virtualspeaker/V = speaker
if(isAI(V.source))
var/mob/living/silicon/ai/S = V.source
to_follow = S.eyeobj
else
to_follow = V.source
var/link = FOLLOW_LINK(src, to_follow)
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
to_chat(src, "[link] [message]")
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if (!message)
return
var/message_mode = get_message_mode(message)
if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
message = copytext(message, 3)
if(findtext(message, " ", 1, 2))
message = copytext(message, 2)
if(message_mode == MODE_ADMIN)
client.cmd_admin_say(message)
else if(message_mode == MODE_DEADMIN)
client.dsay(message)
return
src.log_talk(message, LOG_SAY, tag="ghost")
if(check_emote(message))
return
. = say_dead(message)
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
var/atom/movable/to_follow = speaker
if(radio_freq)
var/atom/movable/virtualspeaker/V = speaker
if(isAI(V.source))
var/mob/living/silicon/ai/S = V.source
to_follow = S.eyeobj
else
to_follow = V.source
var/link = FOLLOW_LINK(src, to_follow)
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
to_chat(src, "[link] [message]")
+11 -11
View File
@@ -221,11 +221,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(succumbed)
succumb()
to_chat(src, compose_message(src, language, message, , spans, message_mode))
to_chat(src, compose_message(src, language, message, null, spans, message_mode))
return 1
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(!client)
return
@@ -245,8 +245,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
playsound_local(src,'sound/voice/radio.ogg', 30, 1)
// Recompose message for AI hrefs, language incomprehension.
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
show_message(message, MSG_AUDIBLE, deaf_message, deaf_type)
return message
@@ -262,8 +262,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
var/list/the_dead = list()
var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas
if(say_test(message) == "2") //CIT CHANGE - ditto
yellareas = get_areas_in_range(message_range*0.5,src) //CIT CHANGE - ditto
if(!eavesdrop_range && say_test(message) == "2") //CIT CHANGE - ditto
yellareas = get_areas_in_range(message_range*0.5, source) //CIT CHANGE - ditto
for(var/_M in GLOB.player_list)
var/mob/M = _M
if(M.stat != DEAD) //not dead, not important
@@ -274,7 +274,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
continue
if(!M.client || !client) //client is so that ghosts don't have to listen to mice
continue
if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing
if(get_dist(M, source) > 7 || M.z != z) //they're out of range of normal hearing
if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off
continue
if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off
@@ -286,15 +286,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/eavesrendered
if(eavesdrop_range)
eavesdropping = stars(message)
eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode)
eavesrendered = compose_message(src, message_language, eavesdropping, null, spans, message_mode, FALSE, source)
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
var/rendered = compose_message(src, message_language, message, null, spans, message_mode, FALSE, source)
for(var/_AM in listening)
var/atom/movable/AM = _AM
if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM]))
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
AM.Hear(eavesrendered, src, message_language, eavesdropping, null, spans, message_mode, source)
else
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
//speech bubble
+197 -197
View File
@@ -1,197 +1,197 @@
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/camera/aiEye
name = "Inactive AI Eye"
invisibility = INVISIBILITY_MAXIMUM
hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST)
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
var/relay_speech = FALSE
var/use_static = USE_STATIC_OPAQUE
var/static_visibility_range = 16
var/ai_detector_visible = TRUE
var/ai_detector_color = COLOR_RED
/mob/camera/aiEye/Initialize()
. = ..()
GLOB.aiEyes += src
update_ai_detect_hud()
setLoc(loc, TRUE)
/mob/camera/aiEye/proc/update_ai_detect_hud()
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
var/list/old_images = hud_list[AI_DETECT_HUD]
if(!ai_detector_visible)
hud.remove_from_hud(src)
QDEL_LIST(old_images)
return
if(!hud.hudusers.len)
//no one is watching, do not bother updating anything
return
hud.remove_from_hud(src)
var/static/list/vis_contents_objects = list()
var/obj/effect/overlay/ai_detect_hud/hud_obj = vis_contents_objects[ai_detector_color]
if(!hud_obj)
hud_obj = new /obj/effect/overlay/ai_detect_hud()
hud_obj.color = ai_detector_color
vis_contents_objects[ai_detector_color] = hud_obj
var/list/new_images = list()
var/list/turfs = get_visible_turfs()
for(var/T in turfs)
var/image/I = (old_images.len > new_images.len) ? old_images[new_images.len + 1] : image(null, T)
I.loc = T
I.vis_contents += hud_obj
new_images += I
for(var/i in (new_images.len + 1) to old_images.len)
qdel(old_images[i])
hud_list[AI_DETECT_HUD] = new_images
hud.add_to_hud(src)
/mob/camera/aiEye/proc/get_visible_turfs()
if(!isturf(loc))
return list()
var/client/C = GetViewerClient()
var/view = C ? getviewsize(C.view) : getviewsize(world.view)
var/turf/lowerleft = locate(max(1, x - (view[1] - 1)/2), max(1, y - (view[2] - 1)/2), z)
var/turf/upperright = locate(min(world.maxx, lowerleft.x + (view[1] - 1)), min(world.maxy, lowerleft.y + (view[2] - 1)), lowerleft.z)
return block(lowerleft, upperright)
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE)
if(ai)
if(!isturf(ai.loc))
return
T = get_turf(T)
if(!force_update && (T == get_turf(src)) )
return //we are already here!
if (T)
forceMove(T)
else
moveToNullspace()
if(use_static != USE_STATIC_NONE)
ai.camera_visibility(src)
if(ai.client && !ai.multicam_on)
ai.client.eye = src
update_ai_detect_hud()
update_parallax_contents()
//Holopad
if(istype(ai.current, /obj/machinery/holopad))
var/obj/machinery/holopad/H = ai.current
H.move_hologram(ai, T)
if(ai.camera_light_on)
ai.light_cameras()
if(ai.master_multicam)
ai.master_multicam.refresh_view()
/mob/camera/aiEye/Move()
return 0
/mob/camera/aiEye/proc/GetViewerClient()
if(ai)
return ai.client
return null
/mob/camera/aiEye/Destroy()
if(ai)
ai.all_eyes -= src
ai = null
for(var/V in visibleCameraChunks)
var/datum/camerachunk/c = V
c.remove(src)
GLOB.aiEyes -= src
if(ai_detector_visible)
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
hud.remove_from_hud(src)
var/list/L = hud_list[AI_DETECT_HUD]
QDEL_LIST(L)
return ..()
/atom/proc/move_camera_by_click()
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && (AI.multicam_on || (AI.client.eye == AI.eyeobj)) && (AI.eyeobj.z == z))
AI.cameraFollow = null
if (isturf(loc) || isturf(src))
AI.eyeobj.setLoc(src)
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.
/client/proc/AIMove(n, direct, mob/living/silicon/ai/user)
var/initial = initial(user.sprint)
var/max_sprint = 50
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
user.sprint = initial
for(var/i = 0; i < max(user.sprint, initial); i += 20)
var/turf/step = get_turf(get_step(user.eyeobj, direct))
if(step)
user.eyeobj.setLoc(step)
user.cooldown = world.timeofday + 5
if(user.acceleration)
user.sprint = min(user.sprint + 0.5, max_sprint)
else
user.sprint = initial
if(!user.tracking)
user.cameraFollow = null
// Return to the Core.
/mob/living/silicon/ai/proc/view_core()
if(istype(current,/obj/machinery/holopad))
var/obj/machinery/holopad/H = current
H.clear_holo(src)
else
current = null
cameraFollow = null
unset_machine()
if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj))
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
create_eye()
eyeobj.setLoc(loc)
/mob/living/silicon/ai/proc/create_eye()
if(eyeobj)
return
eyeobj = new /mob/camera/aiEye()
all_eyes += eyeobj
eyeobj.ai = src
eyeobj.setLoc(loc)
eyeobj.name = "[name] (AI Eye)"
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
if(incapacitated())
return
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
/obj/effect/overlay/ai_detect_hud
name = ""
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
icon = 'icons/effects/alphacolors.dmi'
icon_state = ""
alpha = 100
layer = ABOVE_ALL_MOB_LAYER
plane = GAME_PLANE
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/camera/aiEye
name = "Inactive AI Eye"
invisibility = INVISIBILITY_MAXIMUM
hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST)
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
var/relay_speech = FALSE
var/use_static = USE_STATIC_OPAQUE
var/static_visibility_range = 16
var/ai_detector_visible = TRUE
var/ai_detector_color = COLOR_RED
/mob/camera/aiEye/Initialize()
. = ..()
GLOB.aiEyes += src
update_ai_detect_hud()
setLoc(loc, TRUE)
/mob/camera/aiEye/proc/update_ai_detect_hud()
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
var/list/old_images = hud_list[AI_DETECT_HUD]
if(!ai_detector_visible)
hud.remove_from_hud(src)
QDEL_LIST(old_images)
return
if(!hud.hudusers.len)
//no one is watching, do not bother updating anything
return
hud.remove_from_hud(src)
var/static/list/vis_contents_objects = list()
var/obj/effect/overlay/ai_detect_hud/hud_obj = vis_contents_objects[ai_detector_color]
if(!hud_obj)
hud_obj = new /obj/effect/overlay/ai_detect_hud()
hud_obj.color = ai_detector_color
vis_contents_objects[ai_detector_color] = hud_obj
var/list/new_images = list()
var/list/turfs = get_visible_turfs()
for(var/T in turfs)
var/image/I = (old_images.len > new_images.len) ? old_images[new_images.len + 1] : image(null, T)
I.loc = T
I.vis_contents += hud_obj
new_images += I
for(var/i in (new_images.len + 1) to old_images.len)
qdel(old_images[i])
hud_list[AI_DETECT_HUD] = new_images
hud.add_to_hud(src)
/mob/camera/aiEye/proc/get_visible_turfs()
if(!isturf(loc))
return list()
var/client/C = GetViewerClient()
var/view = C ? getviewsize(C.view) : getviewsize(world.view)
var/turf/lowerleft = locate(max(1, x - (view[1] - 1)/2), max(1, y - (view[2] - 1)/2), z)
var/turf/upperright = locate(min(world.maxx, lowerleft.x + (view[1] - 1)), min(world.maxy, lowerleft.y + (view[2] - 1)), lowerleft.z)
return block(lowerleft, upperright)
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE)
if(ai)
if(!isturf(ai.loc))
return
T = get_turf(T)
if(!force_update && (T == get_turf(src)) )
return //we are already here!
if (T)
forceMove(T)
else
moveToNullspace()
if(use_static != USE_STATIC_NONE)
ai.camera_visibility(src)
if(ai.client && !ai.multicam_on)
ai.client.eye = src
update_ai_detect_hud()
update_parallax_contents()
//Holopad
if(istype(ai.current, /obj/machinery/holopad))
var/obj/machinery/holopad/H = ai.current
H.move_hologram(ai, T)
if(ai.camera_light_on)
ai.light_cameras()
if(ai.master_multicam)
ai.master_multicam.refresh_view()
/mob/camera/aiEye/Move()
return 0
/mob/camera/aiEye/proc/GetViewerClient()
if(ai)
return ai.client
return null
/mob/camera/aiEye/Destroy()
if(ai)
ai.all_eyes -= src
ai = null
for(var/V in visibleCameraChunks)
var/datum/camerachunk/c = V
c.remove(src)
GLOB.aiEyes -= src
if(ai_detector_visible)
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
hud.remove_from_hud(src)
var/list/L = hud_list[AI_DETECT_HUD]
QDEL_LIST(L)
return ..()
/atom/proc/move_camera_by_click()
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && (AI.multicam_on || (AI.client.eye == AI.eyeobj)) && (AI.eyeobj.z == z))
AI.cameraFollow = null
if (isturf(loc) || isturf(src))
AI.eyeobj.setLoc(src)
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.
/client/proc/AIMove(n, direct, mob/living/silicon/ai/user)
var/initial = initial(user.sprint)
var/max_sprint = 50
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
user.sprint = initial
for(var/i = 0; i < max(user.sprint, initial); i += 20)
var/turf/step = get_turf(get_step(user.eyeobj, direct))
if(step)
user.eyeobj.setLoc(step)
user.cooldown = world.timeofday + 5
if(user.acceleration)
user.sprint = min(user.sprint + 0.5, max_sprint)
else
user.sprint = initial
if(!user.tracking)
user.cameraFollow = null
// Return to the Core.
/mob/living/silicon/ai/proc/view_core()
if(istype(current,/obj/machinery/holopad))
var/obj/machinery/holopad/H = current
H.clear_holo(src)
else
current = null
cameraFollow = null
unset_machine()
if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj))
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
create_eye()
eyeobj.setLoc(loc)
/mob/living/silicon/ai/proc/create_eye()
if(eyeobj)
return
eyeobj = new /mob/camera/aiEye()
all_eyes += eyeobj
eyeobj.ai = src
eyeobj.setLoc(loc)
eyeobj.name = "[name] (AI Eye)"
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
if(incapacitated())
return
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
/obj/effect/overlay/ai_detect_hud
name = ""
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
icon = 'icons/effects/alphacolors.dmi'
icon_state = ""
alpha = 100
layer = ABOVE_ALL_MOB_LAYER
plane = GAME_PLANE
@@ -378,7 +378,7 @@ Difficulty: Very Hard
. += observer_desc
. += "It is activated by [activation_method]."
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
..()
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
. = ..()
if(speaker != src && !radio_freq && !stat)
if (speaker in Friends)