AI eyes see emotes. (#28247)

This commit is contained in:
Charlie Nolan
2025-02-26 10:18:20 +00:00
committed by GitHub
parent 56a29c4649
commit 43d48e5f3d
9 changed files with 34 additions and 16 deletions
+1 -1
View File
@@ -273,7 +273,7 @@
#define ispathanimal(A) (ispath(A, /mob/living/simple_animal))
#define iscameramob(A) (istype((A), /mob/camera))
#define is_ai_eye(A) (istype((A), /mob/camera/eye))
#define is_ai_eye(A) (istype((A), /mob/camera/eye/ai))
#define isovermind(A) (istype((A), /mob/camera/blob))
#define isobserver(A) (istype((A), /mob/dead/observer))
+5
View File
@@ -48,3 +48,8 @@
#define VISOR_VISIONFLAGS (1<<2) //all following flags only matter for glasses
#define VISOR_DARKNESSVIEW (1<<3)
#define VISOR_INVISVIEW (1<<4)
// Should AI eyes be counted for get_mobs_in_view?
#define AI_EYE_EXCLUDE 0
#define AI_EYE_REQUIRE_HEAR 1
#define AI_EYE_INCLUDE 2
+13 -4
View File
@@ -146,7 +146,7 @@
return turfs
/// Recursively loops through the contents of this atom looking for mobs, optionally requiring them to have a client.
/proc/collect_nested_mobs(atom/parent, list/mobs, recursion_limit = 3, client_check = TRUE)
/proc/collect_nested_mobs(atom/parent, list/mobs, recursion_limit = 3, client_check = TRUE, ai_eyes = AI_EYE_EXCLUDE)
var/list/next_layer = list(parent)
for(var/depth in 1 to recursion_limit)
var/list/layer = next_layer
@@ -156,7 +156,16 @@
continue
var/mob/this_mob = thing
if(!client_check || this_mob.client)
mobs += this_mob
if(is_ai(this_mob))
// AIs can get messages from their eye as well as themselves, so use |= to make sure they don't get double messages.
mobs |= this_mob
else
// Everything else can only be visited once, so use += for efficiency.
mobs += this_mob
else if(ai_eyes != AI_EYE_EXCLUDE && is_ai_eye(this_mob))
var/mob/camera/eye/ai/eye = this_mob
if((ai_eyes == AI_EYE_INCLUDE || eye.relay_speech) && eye.ai && (!client_check || eye.ai.client))
mobs |= eye.ai
for(var/mob/dead/observer/ghost in this_mob.observers)
if(!client_check || ghost.client)
mobs += ghost
@@ -166,7 +175,7 @@
// The old system would loop through lists for a total of 5000 per function call, in an empty server.
// This new system will loop at around 1000 in an empty server.
/proc/get_mobs_in_view(R, atom/source, include_clientless = FALSE)
/proc/get_mobs_in_view(R, atom/source, include_clientless = FALSE, ai_eyes = AI_EYE_EXCLUDE)
// Returns a list of mobs in range of R from source. Used in radio and say code.
#ifdef GAME_TESTS
// kind of feels cleaner clobbering here than changing the loop?
@@ -181,7 +190,7 @@
for(var/atom/A in hear(R, T))
if(isobj(A) || ismob(A))
collect_nested_mobs(A, hear, 3, !include_clientless)
collect_nested_mobs(A, hear, 3, !include_clientless, ai_eyes)
return hear
+5 -1
View File
@@ -292,7 +292,7 @@
var/runechat_text = text
if(length(text) > 100)
runechat_text = "[copytext(text, 1, 101)]..."
var/list/can_see = get_mobs_in_view(1, user) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around.
var/list/can_see = get_mobs_in_view(1, user, ai_eyes=AI_EYE_INCLUDE) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around.
can_see |= viewers(user, null)
for(var/mob/O as anything in can_see)
if(O.status_flags & PASSEMOTES)
@@ -304,6 +304,10 @@
if(O.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
O.create_chat_message(user, runechat_text, symbol = RUNECHAT_SYMBOL_EMOTE)
if(is_ai_eye(O))
var/mob/camera/eye/ai/eye = O
if(!(eye.ai in can_see) && eye.ai?.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
eye.ai.create_chat_message(user, runechat_text, symbol = RUNECHAT_SYMBOL_EMOTE)
/**
* Check whether or not an emote can be used due to a cooldown.
+1 -1
View File
@@ -1170,7 +1170,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
if(!message)
return
var/list/speech_bubble_hearers = list()
for(var/mob/M as anything in get_mobs_in_view(7, src))
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes=AI_EYE_REQUIRE_HEAR))
M.show_message("<span class='game say'><span class='name'>[src]</span> [atom_say_verb], \"[message]\"</span>", 2, null, 1)
if(M.client)
speech_bubble_hearers += M.client
@@ -578,7 +578,7 @@
else if(istype(loc, /obj/machinery/hologram/holopad))
var/obj/machinery/hologram/holopad/H = loc
name = "[H]"
for(var/mob/M as anything in get_mobs_in_view(7, H))
for(var/mob/M as anything in get_mobs_in_view(7, H, ai_eyes = AI_EYE_REQUIRE_HEAR))
M.hear_say(message_pieces, verb, FALSE, src)
name = real_name
return TRUE
@@ -594,7 +594,7 @@
/mob/living/simple_animal/demon/pulse_demon/visible_message(message, self_message, blind_message, chat_message_type)
// overriden because pulse demon is quite often in non-turf locs, and /mob/visible_message acts differently there
for(var/mob/M as anything in get_mobs_in_view(7, src))
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes = AI_EYE_INCLUDE))
if(M.see_invisible < invisibility)
continue //can't view the invisible
var/msg = message
+1 -1
View File
@@ -83,7 +83,7 @@
for(var/obj/O in view(14, get_turf(src)))
O.hear_talk(user, message_to_multilingual("<span class='[span]'>[message]</span>"))
for(var/mob/M as anything in get_mobs_in_view(7, src))
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes = AI_EYE_REQUIRE_HEAR))
if((M.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT) && M.can_hear())
M.create_chat_message(user, message, FALSE, "big")
@@ -547,7 +547,7 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems)
/obj/item/radio/proc/send_announcement()
if(is_listening())
return get_mobs_in_view(canhear_range, src)
return get_mobs_in_view(canhear_range, src, ai_eyes = AI_EYE_REQUIRE_HEAR)
return null
+5 -5
View File
@@ -150,7 +150,7 @@
/mob/visible_message(message, self_message, blind_message, chat_message_type)
if(!isturf(loc)) // mobs inside objects (such as lockers) shouldn't have their actions visible to those outside the object
for(var/mob/M as anything in get_mobs_in_view(3, src))
for(var/mob/M as anything in get_mobs_in_view(3, src, ai_eyes = AI_EYE_INCLUDE))
if(M.see_invisible < invisibility)
continue //can't view the invisible
var/msg = message
@@ -162,7 +162,7 @@
msg = blind_message
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE, chat_message_type)
return
for(var/mob/M as anything in get_mobs_in_view(7, src))
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes = AI_EYE_INCLUDE))
if(M.see_invisible < invisibility)
continue //can't view the invisible
var/msg = message
@@ -175,7 +175,7 @@
// message is output to anyone who can see, e.g. "The [src] does something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
/atom/proc/visible_message(message, blind_message)
for(var/mob/M as anything in get_mobs_in_view(7, src))
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes = AI_EYE_INCLUDE))
if(!M.client)
continue
M.show_message(message, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
@@ -191,7 +191,7 @@
if(hearing_distance)
range = hearing_distance
var/msg = message
for(var/mob/M as anything in get_mobs_in_view(range, src))
for(var/mob/M as anything in get_mobs_in_view(range, src, ai_eyes = AI_EYE_REQUIRE_HEAR))
M.show_message(msg, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
// based on say code
@@ -217,7 +217,7 @@
var/range = 7
if(hearing_distance)
range = hearing_distance
for(var/mob/M as anything in get_mobs_in_view(range, src))
for(var/mob/M as anything in get_mobs_in_view(range, src, ai_eyes = AI_EYE_REQUIRE_HEAR))
M.show_message(message, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
/mob/proc/findname(msg)