Skip to content

Commit

Permalink
AI eyes see emotes. (#28247)
Browse files Browse the repository at this point in the history
  • Loading branch information
FunnyMan3595 authored Feb 26, 2025
1 parent 56a29c4 commit 43d48e5
Show file tree
Hide file tree
Showing 9 changed files with 34 additions and 16 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
5 changes: 5 additions & 0 deletions code/__DEFINES/sight.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
17 changes: 13 additions & 4 deletions code/__HELPERS/game.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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?
Expand All @@ -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

Expand Down
6 changes: 5 additions & 1 deletion code/datums/emote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/devices/megaphone.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/devices/radio/radio_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 5 additions & 5 deletions code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand Down

0 comments on commit 43d48e5

Please sign in to comment.