mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
AI detection multitools can show camera static and AI eyes (#38255)
The old color-change functionality of the multitool remains unchanged. The hud is toggled with an action button, because multitools already have an attack_self() that does something. When toggled on, you get the hud as long as the multitool is in any slot on your body. The only way I could find to reliably show exactly where an AI is looking was to place an image on every turf they are looking at. Because AI eyes move around a lot and I do not want them placing images all over the place when they do not have to, if there is nobody in the world currently using an ai detection multitool, they will not update the images until someone is. Only AI eyes and multicamera zones currently appear. Advanced camera consoles do not appear on the hud, and no longer trigger the proximity color change. Also fixed multitools not appearing in-hands if their icon state changed.
This commit is contained in:
+17
-15
@@ -20,8 +20,9 @@
|
||||
#define DIAG_PATH_HUD "16"//Bot path indicators
|
||||
#define GLAND_HUD "17"//Gland indicators for abductors
|
||||
#define SENTIENT_DISEASE_HUD "18"
|
||||
#define AI_DETECT_HUD "19"
|
||||
//for antag huds. these are used at the /mob level
|
||||
#define ANTAG_HUD "19"
|
||||
#define ANTAG_HUD "20"
|
||||
|
||||
//by default everything in the hud_list of an atom is an image
|
||||
//a value in hud_list with one of these will change that behavior
|
||||
@@ -37,22 +38,23 @@
|
||||
#define DATA_HUD_DIAGNOSTIC_ADVANCED 6
|
||||
#define DATA_HUD_ABDUCTOR 7
|
||||
#define DATA_HUD_SENTIENT_DISEASE 8
|
||||
#define DATA_HUD_AI_DETECT 9
|
||||
|
||||
//antag HUD defines
|
||||
#define ANTAG_HUD_CULT 9
|
||||
#define ANTAG_HUD_REV 10
|
||||
#define ANTAG_HUD_OPS 11
|
||||
#define ANTAG_HUD_WIZ 12
|
||||
#define ANTAG_HUD_SHADOW 13
|
||||
#define ANTAG_HUD_TRAITOR 14
|
||||
#define ANTAG_HUD_NINJA 15
|
||||
#define ANTAG_HUD_CHANGELING 16
|
||||
#define ANTAG_HUD_ABDUCTOR 17
|
||||
#define ANTAG_HUD_DEVIL 18
|
||||
#define ANTAG_HUD_SINTOUCHED 19
|
||||
#define ANTAG_HUD_SOULLESS 20
|
||||
#define ANTAG_HUD_CLOCKWORK 21
|
||||
#define ANTAG_HUD_BROTHER 22
|
||||
#define ANTAG_HUD_CULT 10
|
||||
#define ANTAG_HUD_REV 11
|
||||
#define ANTAG_HUD_OPS 12
|
||||
#define ANTAG_HUD_WIZ 13
|
||||
#define ANTAG_HUD_SHADOW 14
|
||||
#define ANTAG_HUD_TRAITOR 15
|
||||
#define ANTAG_HUD_NINJA 16
|
||||
#define ANTAG_HUD_CHANGELING 17
|
||||
#define ANTAG_HUD_ABDUCTOR 18
|
||||
#define ANTAG_HUD_DEVIL 19
|
||||
#define ANTAG_HUD_SINTOUCHED 20
|
||||
#define ANTAG_HUD_SOULLESS 21
|
||||
#define ANTAG_HUD_CLOCKWORK 22
|
||||
#define ANTAG_HUD_BROTHER 23
|
||||
|
||||
// Notification action types
|
||||
#define NOTIFY_JUMP "jump"
|
||||
|
||||
+15
-13
@@ -85,20 +85,22 @@
|
||||
#define BYOND_LIGHTING_PLANE 17
|
||||
#define BYOND_LIGHTING_LAYER 17
|
||||
|
||||
#define CAMERA_STATIC_PLANE 18
|
||||
#define CAMERA_STATIC_LAYER 18
|
||||
//HUD layer defines
|
||||
|
||||
#define FULLSCREEN_PLANE 18
|
||||
#define FLASH_LAYER 18
|
||||
#define FULLSCREEN_LAYER 18.1
|
||||
#define UI_DAMAGE_LAYER 18.2
|
||||
#define BLIND_LAYER 18.3
|
||||
#define CRIT_LAYER 18.4
|
||||
#define CURSE_LAYER 18.5
|
||||
#define FULLSCREEN_PLANE 19
|
||||
#define FLASH_LAYER 19
|
||||
#define FULLSCREEN_LAYER 19.1
|
||||
#define UI_DAMAGE_LAYER 19.2
|
||||
#define BLIND_LAYER 19.3
|
||||
#define CRIT_LAYER 19.4
|
||||
#define CURSE_LAYER 19.5
|
||||
|
||||
#define HUD_PLANE 19
|
||||
#define HUD_LAYER 19
|
||||
#define ABOVE_HUD_PLANE 20
|
||||
#define ABOVE_HUD_LAYER 20
|
||||
#define HUD_PLANE 20
|
||||
#define HUD_LAYER 20
|
||||
#define ABOVE_HUD_PLANE 21
|
||||
#define ABOVE_HUD_LAYER 21
|
||||
|
||||
#define SPLASHSCREEN_LAYER 21
|
||||
#define SPLASHSCREEN_PLANE 21
|
||||
#define SPLASHSCREEN_LAYER 22
|
||||
#define SPLASHSCREEN_PLANE 22
|
||||
|
||||
@@ -28,3 +28,8 @@
|
||||
#define VISOR_VISIONFLAGS (1<<2) //all following flags only matter for glasses
|
||||
#define VISOR_DARKNESSVIEW (1<<3)
|
||||
#define VISOR_INVISVIEW (1<<4)
|
||||
|
||||
//for whether AI eyes see static, and whether it is mouse-opaque or not
|
||||
#define USE_STATIC_NONE 0
|
||||
#define USE_STATIC_TRANSPARENT 1
|
||||
#define USE_STATIC_OPAQUE 2
|
||||
|
||||
@@ -26,6 +26,7 @@ GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for e
|
||||
GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs
|
||||
GLOBAL_LIST_EMPTY(bots_list)
|
||||
GLOBAL_LIST_EMPTY(living_cameras)
|
||||
GLOBAL_LIST_EMPTY(aiEyes)
|
||||
|
||||
GLOBAL_LIST_EMPTY(language_datum_instances)
|
||||
GLOBAL_LIST_EMPTY(all_languages)
|
||||
|
||||
@@ -124,14 +124,16 @@
|
||||
vis_contents -= viewing_turfs
|
||||
if(!width || !height)
|
||||
return
|
||||
var/turf/T = get_turf(center)
|
||||
if(!T)
|
||||
return
|
||||
var/turf/lowerleft = locate(max(1, T.x - round(width/2)), max(1, T.y - round(height/2)), T.z)
|
||||
var/turf/upperright = locate(min(world.maxx, lowerleft.x + width - 1), min(world.maxy, lowerleft.y + height - 1), lowerleft.z)
|
||||
viewing_turfs = block(lowerleft, upperright)
|
||||
viewing_turfs = get_visible_turfs()
|
||||
vis_contents += viewing_turfs
|
||||
|
||||
/obj/screen/movable/pic_in_pic/proc/get_visible_turfs()
|
||||
var/turf/T = get_turf(center)
|
||||
if(!T)
|
||||
return list()
|
||||
var/turf/lowerleft = locate(max(1, T.x - round(width/2)), max(1, T.y - round(height/2)), T.z)
|
||||
var/turf/upperright = locate(min(world.maxx, lowerleft.x + width - 1), min(world.maxy, lowerleft.y + height - 1), lowerleft.z)
|
||||
return block(lowerleft, upperright)
|
||||
|
||||
/obj/screen/movable/pic_in_pic/proc/show_to(client/C)
|
||||
if(C)
|
||||
|
||||
@@ -52,3 +52,9 @@
|
||||
/obj/screen/plane_master/lighting/backdrop(mob/mymob)
|
||||
mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit)
|
||||
mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit)
|
||||
|
||||
/obj/screen/plane_master/camera_static
|
||||
name = "camera static plane master"
|
||||
plane = CAMERA_STATIC_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
user.remote_control = null
|
||||
|
||||
if(!QDELETED(eye))
|
||||
eye.RemoveImages()
|
||||
QDEL_NULL(eye)
|
||||
|
||||
if(connected_holopad && !QDELETED(hologram))
|
||||
|
||||
+3
-1
@@ -12,6 +12,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
|
||||
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
|
||||
DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(),
|
||||
DATA_HUD_AI_DETECT = new/datum/atom_hud/ai_detector(),
|
||||
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
|
||||
@@ -100,7 +101,8 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
return FALSE
|
||||
hudatoms |= A
|
||||
for(var/mob/M in hudusers)
|
||||
add_to_single_hud(M, A)
|
||||
if(!queued_to_see[M])
|
||||
add_to_single_hud(M, A)
|
||||
return TRUE
|
||||
|
||||
/datum/atom_hud/proc/add_to_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
/datum/atom_hud/sentient_disease
|
||||
hud_icons = list(SENTIENT_DISEASE_HUD)
|
||||
|
||||
/datum/atom_hud/ai_detector
|
||||
hud_icons = list(AI_DETECT_HUD)
|
||||
|
||||
/datum/atom_hud/ai_detector/add_hud_to(mob/M)
|
||||
..()
|
||||
if(M && (hudusers.len == 1))
|
||||
for(var/V in GLOB.aiEyes)
|
||||
var/mob/camera/aiEye/E = V
|
||||
E.update_ai_detect_hud()
|
||||
|
||||
/* MED/SEC/DIAG HUD HOOKS */
|
||||
|
||||
/*
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
C.remove(eyeobj)
|
||||
if(user.client)
|
||||
user.reset_perspective(null)
|
||||
eyeobj.RemoveImages()
|
||||
if(eyeobj.visible_icon && user.client)
|
||||
user.client.images -= eyeobj.user_image
|
||||
eyeobj.eye_user = null
|
||||
user.remote_control = null
|
||||
|
||||
@@ -108,7 +109,7 @@
|
||||
if(!eyeobj.eye_initialized)
|
||||
var/camera_location
|
||||
var/turf/myturf = get_turf(src)
|
||||
if(eyeobj.use_static)
|
||||
if(eyeobj.use_static != USE_STATIC_NONE)
|
||||
if((!z_lock.len || (myturf.z in z_lock)) && GLOB.cameranet.checkTurfVis(myturf))
|
||||
camera_location = myturf
|
||||
else
|
||||
@@ -151,6 +152,7 @@
|
||||
|
||||
/mob/camera/aiEye/remote
|
||||
name = "Inactive Camera Eye"
|
||||
ai_detector_visible = FALSE
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
var/acceleration = 1
|
||||
@@ -166,14 +168,9 @@
|
||||
user.see_in_dark = 2
|
||||
return 1
|
||||
|
||||
/mob/camera/aiEye/remote/RemoveImages()
|
||||
..()
|
||||
if(visible_icon)
|
||||
var/client/C = GetViewerClient()
|
||||
if(C)
|
||||
C.images -= user_image
|
||||
|
||||
/mob/camera/aiEye/remote/Destroy()
|
||||
if(origin && eye_user)
|
||||
origin.remove_eye_control(eye_user)
|
||||
origin = null
|
||||
. = ..()
|
||||
eye_user = null
|
||||
@@ -185,15 +182,14 @@
|
||||
|
||||
/mob/camera/aiEye/remote/setLoc(T)
|
||||
if(eye_user)
|
||||
if(!isturf(eye_user.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
if (T)
|
||||
forceMove(T)
|
||||
else
|
||||
moveToNullspace()
|
||||
if(use_static)
|
||||
GLOB.cameranet.visibility(src, GetViewerClient())
|
||||
update_ai_detect_hud()
|
||||
if(use_static != USE_STATIC_NONE)
|
||||
GLOB.cameranet.visibility(src, GetViewerClient(), null, use_static)
|
||||
if(visible_icon)
|
||||
if(eye_user.client)
|
||||
eye_user.client.images -= user_image
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "multitool"
|
||||
item_state = "multitool"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
force = 5
|
||||
@@ -40,8 +41,6 @@
|
||||
if(selected_io)
|
||||
selected_io = null
|
||||
to_chat(user, "<span class='notice'>You clear the wired connection from the multitool.</span>")
|
||||
else
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/multitool/update_icon()
|
||||
@@ -98,30 +97,89 @@
|
||||
|
||||
// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby.
|
||||
|
||||
|
||||
/obj/item/multitool/ai_detect
|
||||
var/track_cooldown = 0
|
||||
var/track_delay = 10 //How often it checks for proximity
|
||||
var/detect_state = PROXIMITY_NONE
|
||||
var/rangealert = 8 //Glows red when inside
|
||||
var/rangewarning = 20 //Glows yellow when inside
|
||||
var/hud_type = DATA_HUD_AI_DETECT
|
||||
var/hud_on = FALSE
|
||||
var/mob/camera/aiEye/remote/ai_detector/eye
|
||||
var/datum/action/item_action/toggle_multitool/toggle_action
|
||||
|
||||
/obj/item/multitool/ai_detect/New()
|
||||
..()
|
||||
/obj/item/multitool/ai_detect/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
eye = new /mob/camera/aiEye/remote/ai_detector()
|
||||
toggle_action = new /datum/action/item_action/toggle_multitool(src)
|
||||
|
||||
/obj/item/multitool/ai_detect/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(hud_on && ismob(loc))
|
||||
remove_hud(loc)
|
||||
QDEL_NULL(toggle_action)
|
||||
QDEL_NULL(eye)
|
||||
return ..()
|
||||
|
||||
/obj/item/multitool/ai_detect/ui_action_click()
|
||||
return
|
||||
|
||||
/obj/item/multitool/ai_detect/update_icon()
|
||||
if(selected_io)
|
||||
icon_state = "multitool_red"
|
||||
else
|
||||
icon_state = "[initial(icon_state)][detect_state]"
|
||||
|
||||
/obj/item/multitool/ai_detect/equipped(mob/living/carbon/human/user, slot)
|
||||
..()
|
||||
if(hud_on)
|
||||
show_hud(user)
|
||||
|
||||
/obj/item/multitool/ai_detect/dropped(mob/living/carbon/human/user)
|
||||
..()
|
||||
if(hud_on)
|
||||
remove_hud(user)
|
||||
|
||||
/obj/item/multitool/ai_detect/process()
|
||||
if(track_cooldown > world.time)
|
||||
return
|
||||
detect_state = PROXIMITY_NONE
|
||||
if(eye.eye_user)
|
||||
eye.setLoc(get_turf(src))
|
||||
multitool_detect()
|
||||
icon_state = "[initial(icon_state)][detect_state]"
|
||||
update_icon()
|
||||
track_cooldown = world.time + track_delay
|
||||
|
||||
/obj/item/multitool/ai_detect/proc/toggle_hud(mob/user)
|
||||
hud_on = !hud_on
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You toggle the ai detection HUD on [src] [hud_on ? "on" : "off"].</span>")
|
||||
if(hud_on)
|
||||
show_hud(user)
|
||||
else
|
||||
remove_hud(user)
|
||||
|
||||
/obj/item/multitool/ai_detect/proc/show_hud(mob/user)
|
||||
if(user && hud_type)
|
||||
var/obj/screen/plane_master/camera_static/PM = user.hud_used.plane_masters["[CAMERA_STATIC_PLANE]"]
|
||||
PM.alpha = 150
|
||||
var/datum/atom_hud/H = GLOB.huds[hud_type]
|
||||
if(!H.hudusers[user])
|
||||
H.add_hud_to(user)
|
||||
eye.eye_user = user
|
||||
eye.setLoc(get_turf(src))
|
||||
|
||||
/obj/item/multitool/ai_detect/proc/remove_hud(mob/user)
|
||||
if(user && hud_type)
|
||||
var/obj/screen/plane_master/camera_static/PM = user.hud_used.plane_masters["[CAMERA_STATIC_PLANE]"]
|
||||
PM.alpha = 255
|
||||
var/datum/atom_hud/H = GLOB.huds[hud_type]
|
||||
H.remove_hud_from(user)
|
||||
if(eye)
|
||||
eye.setLoc(null)
|
||||
eye.eye_user = null
|
||||
|
||||
/obj/item/multitool/ai_detect/proc/multitool_detect()
|
||||
var/turf/our_turf = get_turf(src)
|
||||
for(var/mob/living/silicon/ai/AI in GLOB.ai_list)
|
||||
@@ -134,6 +192,8 @@
|
||||
var/datum/camerachunk/chunk = GLOB.cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(chunk && chunk.seenby.len)
|
||||
for(var/mob/camera/aiEye/A in chunk.seenby)
|
||||
if(!A.ai_detector_visible)
|
||||
continue
|
||||
var/turf/detect_turf = get_turf(A)
|
||||
if(get_dist(our_turf, detect_turf) < rangealert)
|
||||
detect_state = PROXIMITY_ON_SCREEN
|
||||
@@ -142,6 +202,24 @@
|
||||
detect_state = PROXIMITY_NEAR
|
||||
break
|
||||
|
||||
/mob/camera/aiEye/remote/ai_detector
|
||||
name = "AI detector eye"
|
||||
ai_detector_visible = FALSE
|
||||
use_static = USE_STATIC_TRANSPARENT
|
||||
visible_icon = FALSE
|
||||
|
||||
/datum/action/item_action/toggle_multitool
|
||||
name = "Toggle AI detector HUD"
|
||||
check_flags = NONE
|
||||
|
||||
/datum/action/item_action/toggle_multitool/Trigger()
|
||||
if(!..())
|
||||
return 0
|
||||
if(target)
|
||||
var/obj/item/multitool/ai_detect/M = target
|
||||
M.toggle_hud(owner)
|
||||
return 1
|
||||
|
||||
/obj/item/multitool/cyborg
|
||||
name = "multitool"
|
||||
desc = "Optimised and stripped-down version of a regular multitool."
|
||||
|
||||
@@ -331,9 +331,9 @@
|
||||
var/datum/camerachunk/C = GLOB.cameranet.chunkGenerated(x, y, z)
|
||||
if(C)
|
||||
if(C.obscuredTurfs[src])
|
||||
vis_contents += GLOB.cameranet.vis_contents
|
||||
vis_contents += GLOB.cameranet.vis_contents_objects
|
||||
else
|
||||
vis_contents -= GLOB.cameranet.vis_contents
|
||||
vis_contents -= GLOB.cameranet.vis_contents_objects
|
||||
|
||||
/turf/proc/burn_tile()
|
||||
|
||||
|
||||
@@ -1003,7 +1003,7 @@
|
||||
target_ai = src //cheat! just give... ourselves as the spawned AI, because that's technically correct
|
||||
|
||||
/mob/living/silicon/ai/proc/camera_visibility(mob/camera/aiEye/moved_eye)
|
||||
GLOB.cameranet.visibility(moved_eye, client, all_eyes)
|
||||
GLOB.cameranet.visibility(moved_eye, client, all_eyes, USE_STATIC_OPAQUE)
|
||||
|
||||
/mob/living/silicon/ai/forceMove(atom/destination)
|
||||
. = ..()
|
||||
|
||||
@@ -18,15 +18,24 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
// The object used for the clickable stat() button.
|
||||
var/obj/effect/statclick/statclick
|
||||
|
||||
// The object used in vis_contents of obscured turfs
|
||||
var/vis_contents
|
||||
// The objects used in vis_contents of obscured turfs
|
||||
var/list/vis_contents_objects
|
||||
var/obj/effect/overlay/camera_static/vis_contents_opaque
|
||||
var/obj/effect/overlay/camera_static/vis_contents_transparent
|
||||
// The image given to the effect in vis_contents on AI clients
|
||||
var/image/obscured
|
||||
var/image/obscured_transparent
|
||||
|
||||
/datum/cameranet/New()
|
||||
vis_contents = new /obj/effect/overlay/camera_static()
|
||||
obscured = new('icons/effects/cameravis.dmi', vis_contents, null, BYOND_LIGHTING_LAYER + 0.1)
|
||||
obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
vis_contents_opaque = new /obj/effect/overlay/camera_static()
|
||||
vis_contents_transparent = new /obj/effect/overlay/camera_static/transparent()
|
||||
vis_contents_objects = list(vis_contents_opaque, vis_contents_transparent)
|
||||
|
||||
obscured = new('icons/effects/cameravis.dmi', vis_contents_opaque, null, CAMERA_STATIC_LAYER)
|
||||
obscured.plane = CAMERA_STATIC_PLANE
|
||||
|
||||
obscured_transparent = new('icons/effects/cameravis.dmi', vis_contents_transparent, null, CAMERA_STATIC_LAYER)
|
||||
obscured_transparent.plane = CAMERA_STATIC_PLANE
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
@@ -46,7 +55,7 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
|
||||
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
|
||||
|
||||
/datum/cameranet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
|
||||
/datum/cameranet/proc/visibility(list/moved_eyes, client/C, list/other_eyes, use_static = USE_STATIC_OPAQUE)
|
||||
if(!islist(moved_eyes))
|
||||
moved_eyes = moved_eyes ? list(moved_eyes) : list()
|
||||
if(islist(other_eyes))
|
||||
@@ -54,19 +63,28 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
else
|
||||
other_eyes = list()
|
||||
|
||||
if(C)
|
||||
switch(use_static)
|
||||
if(USE_STATIC_TRANSPARENT)
|
||||
C.images += obscured_transparent
|
||||
if(USE_STATIC_OPAQUE)
|
||||
C.images += obscured
|
||||
|
||||
for(var/V in moved_eyes)
|
||||
var/mob/camera/aiEye/eye = V
|
||||
var/static_range = eye.static_visibility_range
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
if(eye.loc)
|
||||
// 0xf = 15
|
||||
var/static_range = eye.static_visibility_range
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
visibleChunks |= getCameraChunk(x, y, eye.z)
|
||||
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
visibleChunks |= getCameraChunk(x, y, eye.z)
|
||||
|
||||
var/list/remove = eye.visibleCameraChunks - visibleChunks
|
||||
var/list/add = visibleChunks - eye.visibleCameraChunks
|
||||
@@ -79,9 +97,6 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
var/datum/camerachunk/c = chunk
|
||||
c.add(eye)
|
||||
|
||||
if(C)
|
||||
C.images += obscured
|
||||
|
||||
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
|
||||
|
||||
/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1)
|
||||
@@ -173,5 +188,8 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
layer = BYOND_LIGHTING_LAYER + 0.1
|
||||
plane = BYOND_LIGHTING_PLANE + 1
|
||||
layer = CAMERA_STATIC_LAYER
|
||||
plane = CAMERA_STATIC_PLANE
|
||||
|
||||
/obj/effect/overlay/camera_static/transparent
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -29,6 +29,14 @@
|
||||
/datum/camerachunk/proc/remove(mob/camera/aiEye/eye)
|
||||
eye.visibleCameraChunks -= src
|
||||
seenby -= eye
|
||||
if(!eye.visibleCameraChunks.len)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
if(client)
|
||||
switch(eye.use_static)
|
||||
if(USE_STATIC_TRANSPARENT)
|
||||
client.images -= GLOB.cameranet.obscured_transparent
|
||||
if(USE_STATIC_OPAQUE)
|
||||
client.images -= GLOB.cameranet.obscured
|
||||
|
||||
// Called when a chunk has changed. I.E: A wall was deleted.
|
||||
|
||||
@@ -81,12 +89,12 @@
|
||||
|
||||
for(var/turf in visAdded)
|
||||
var/turf/t = turf
|
||||
t.vis_contents -= GLOB.cameranet.vis_contents
|
||||
t.vis_contents -= GLOB.cameranet.vis_contents_objects
|
||||
|
||||
for(var/turf in visRemoved)
|
||||
var/turf/t = turf
|
||||
if(obscuredTurfs[t] && !istype(t, /turf/open/ai_visible))
|
||||
t.vis_contents += GLOB.cameranet.vis_contents
|
||||
t.vis_contents += GLOB.cameranet.vis_contents_objects
|
||||
|
||||
changed = 0
|
||||
|
||||
@@ -128,7 +136,7 @@
|
||||
|
||||
for(var/turf in obscuredTurfs)
|
||||
var/turf/t = turf
|
||||
t.vis_contents += GLOB.cameranet.vis_contents
|
||||
t.vis_contents += GLOB.cameranet.vis_contents_objects
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
#undef CHUNK_SIZE
|
||||
|
||||
@@ -7,28 +7,81 @@
|
||||
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 = TRUE
|
||||
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)
|
||||
/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)
|
||||
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))
|
||||
@@ -47,11 +100,6 @@
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/aiEye/proc/RemoveImages()
|
||||
var/client/C = GetViewerClient()
|
||||
if(C && use_static)
|
||||
C.images -= GLOB.cameranet.obscured
|
||||
|
||||
/mob/camera/aiEye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
@@ -59,6 +107,12 @@
|
||||
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()
|
||||
@@ -131,3 +185,12 @@
|
||||
/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
|
||||
|
||||
@@ -124,6 +124,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
|
||||
var/list/cameras_telegraphed = list()
|
||||
var/telegraph_cameras = TRUE
|
||||
var/telegraph_range = 7
|
||||
ai_detector_color = COLOR_ORANGE
|
||||
|
||||
/mob/camera/aiEye/pic_in_pic/GetViewerClient()
|
||||
if(screen && screen.ai)
|
||||
@@ -139,6 +140,10 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
|
||||
else
|
||||
GLOB.cameranet.visibility(src)
|
||||
update_camera_telegraphing()
|
||||
update_ai_detect_hud()
|
||||
|
||||
/mob/camera/aiEye/pic_in_pic/get_visible_turfs()
|
||||
return screen ? screen.get_visible_turfs() : list()
|
||||
|
||||
/mob/camera/aiEye/pic_in_pic/proc/update_camera_telegraphing()
|
||||
if(!telegraph_cameras)
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_docker
|
||||
visible_icon = FALSE
|
||||
use_static = FALSE
|
||||
use_static = USE_STATIC_NONE
|
||||
var/list/placement_images = list()
|
||||
var/list/placed_images = list()
|
||||
|
||||
|
||||
@@ -1002,8 +1002,10 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
|
||||
/datum/uplink_item/device_tools/ai_detector
|
||||
name = "Artificial Intelligence Detector"
|
||||
desc = "A functional multitool that turns red when it detects an artificial intelligence watching it or its \
|
||||
holder. Knowing when an artificial intelligence is watching you is useful for knowing when to maintain cover."
|
||||
desc = "A functional multitool that turns red when it detects an artificial intelligence watching it, and can be \
|
||||
activated to display their exact viewing location and nearby security camera blind spots. Knowing when \
|
||||
an artificial intelligence is watching you is useful for knowing when to maintain cover, and finding nearby \
|
||||
blind spots can help you identify escape routes."
|
||||
item = /obj/item/multitool/ai_detect
|
||||
cost = 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user