mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 04:27:35 +01:00
Merge pull request #3865 from tigercat2000/tgcam
Port -tg-station cameranets
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
|
||||
//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a
|
||||
#define RANGE_TURFS(RADIUS, CENTER) \
|
||||
block( \
|
||||
locate(max(CENTER.x-(RADIUS),1), max(CENTER.y-(RADIUS),1), CENTER.z), \
|
||||
locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \
|
||||
)
|
||||
|
||||
/proc/dopage(src,target)
|
||||
var/href_list
|
||||
|
||||
@@ -1664,6 +1664,25 @@ var/mob/dview/dview_mob = new
|
||||
|
||||
return I
|
||||
|
||||
//ultra range (no limitations on distance, faster than range for distances > 8); including areas drastically decreases performance
|
||||
/proc/urange(dist=0, atom/center=usr, orange=0, areas=0)
|
||||
if(!dist)
|
||||
if(!orange)
|
||||
return list(center)
|
||||
else
|
||||
return list()
|
||||
|
||||
var/list/turfs = RANGE_TURFS(dist, center)
|
||||
if(orange)
|
||||
turfs -= get_turf(center)
|
||||
. = list()
|
||||
for(var/V in turfs)
|
||||
var/turf/T = V
|
||||
. += T
|
||||
. += T.contents
|
||||
if(areas)
|
||||
. |= T.loc
|
||||
|
||||
/proc/turf_clear(turf/T)
|
||||
for(var/atom/A in T)
|
||||
if(A.simulated)
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
icon_state = "camera"
|
||||
|
||||
/obj/screen/ai/camera_list/Click()
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
var/camera = input(AI) in AI.get_camera_list()
|
||||
AI.ai_camera_list(camera)
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
var/camera = input(AI, "Choose which camera you want to view", "Cameras") as null|anything in AI.get_camera_list()
|
||||
AI.ai_camera_list(camera)
|
||||
|
||||
/obj/screen/ai/camera_track
|
||||
name = "Track With Camera"
|
||||
|
||||
@@ -38,7 +38,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32
|
||||
|
||||
if(CAMERA_WIRE_POWER)
|
||||
if(C.status && !mended || !C.status && mended)
|
||||
C.deactivate(usr, 1)
|
||||
C.toggle_cam(usr, 1)
|
||||
|
||||
if(CAMERA_WIRE_LIGHT)
|
||||
C.light_disabled = !mended
|
||||
@@ -60,7 +60,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32
|
||||
C.setViewRange(new_range)
|
||||
|
||||
if(CAMERA_WIRE_POWER)
|
||||
C.deactivate(null) // Deactivate the camera
|
||||
C.toggle_cam(null) // Deactivate the camera
|
||||
|
||||
if(CAMERA_WIRE_LIGHT)
|
||||
C.light_disabled = !C.light_disabled
|
||||
|
||||
@@ -49,7 +49,7 @@ var/const/BORG_WIRE_LAWCHECK = 16 // Not used on MoMMIs
|
||||
if (BORG_WIRE_CAMERA)
|
||||
if(!isnull(R.camera) && !R.scrambledcodes)
|
||||
R.camera.status = mended
|
||||
R.camera.deactivate(usr, 0) // Will kick anyone who is watching the Cyborg's camera.
|
||||
R.camera.toggle_cam(usr, 0) // Will kick anyone who is watching the Cyborg's camera.
|
||||
|
||||
if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh
|
||||
if (R.lawupdate)
|
||||
@@ -70,7 +70,7 @@ var/const/BORG_WIRE_LAWCHECK = 16 // Not used on MoMMIs
|
||||
|
||||
if (BORG_WIRE_CAMERA)
|
||||
if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes)
|
||||
R.camera.deactivate(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera.
|
||||
R.camera.toggle_cam(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera.
|
||||
R.visible_message("[R]'s camera lense focuses loudly.")
|
||||
R << "Your camera lense focuses loudly."
|
||||
|
||||
|
||||
@@ -386,7 +386,7 @@ rcd light flash thingy on matter drain
|
||||
var/initial_range = initial(C.view_range) //To prevent calling the proc twice
|
||||
if(camera.uses > 0)
|
||||
if(!C.status)
|
||||
C.deactivate(src, 1) //Reactivates the camera based on status. Badly named proc.
|
||||
C.toggle_cam(src, 1) //Reactivates the camera based on status. Badly named proc.
|
||||
fixedcams++
|
||||
camera.uses--
|
||||
if(C.view_range != initial_range)
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
/obj/machinery/camera/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S.DisIntegrate(src)
|
||||
deactivate(S, 0)
|
||||
toggle_cam(S, 0)
|
||||
|
||||
/obj/machinery/particle_accelerator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
S << "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>"
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
var/list/network = list("SS13")
|
||||
var/c_tag = null
|
||||
var/c_tag_order = 999
|
||||
var/status = 1.0
|
||||
anchored = 1.0
|
||||
var/status = 1
|
||||
anchored = 1
|
||||
var/start_active = 0 //If it ignores the random chance to start broken on round start
|
||||
var/invuln = null
|
||||
var/obj/item/device/camera_bug/bug = null
|
||||
@@ -38,32 +38,15 @@
|
||||
assembly.anchored = 1
|
||||
assembly.update_icon()
|
||||
|
||||
invalidateCameraCache()
|
||||
|
||||
if(cameranet.cameras_unsorted || !ticker)
|
||||
cameranet.cameras += src
|
||||
cameranet.cameras_unsorted = 1
|
||||
else
|
||||
dd_insertObjectList(cameranet.cameras, src)
|
||||
|
||||
var/list/open_networks = difflist(network,restricted_camera_networks) //...but if all of camera's networks are restricted, it only works for specific camera consoles.
|
||||
if(open_networks.len) //If there is at least one open network, chunk is available for AI usage.
|
||||
cameranet.addCamera(src)
|
||||
|
||||
/* // Use this to look for cameras that have the same c_tag.
|
||||
for(var/obj/machinery/camera/C in cameranet.cameras)
|
||||
var/list/tempnetwork = C.network&src.network
|
||||
if(C != src && C.c_tag == src.c_tag && tempnetwork.len)
|
||||
log_to_dd("[src.c_tag] [src.x] [src.y] [src.z] conflicts with [C.c_tag] [C.x] [C.y] [C.z]")
|
||||
*/
|
||||
cameranet.cameras += src
|
||||
cameranet.addCamera(src)
|
||||
|
||||
/obj/machinery/camera/initialize()
|
||||
if(z == ZLEVEL_STATION && prob(3) && !start_active)
|
||||
deactivate()
|
||||
toggle_cam()
|
||||
|
||||
/obj/machinery/camera/Destroy()
|
||||
invalidateCameraCache()
|
||||
deactivate(null, 0) //kick anyone viewing out
|
||||
toggle_cam(null, 0) //kick anyone viewing out
|
||||
if(assembly)
|
||||
qdel(assembly)
|
||||
assembly = null
|
||||
@@ -76,26 +59,24 @@
|
||||
wires = null
|
||||
cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
|
||||
cameranet.cameras -= src
|
||||
var/list/open_networks = difflist(network,restricted_camera_networks)
|
||||
if(open_networks.len)
|
||||
cameranet.removeCamera(src)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/camera/emp_act(severity)
|
||||
if(!status)
|
||||
return
|
||||
if(!isEmpProof())
|
||||
if(prob(100/severity))
|
||||
invalidateCameraCache()
|
||||
if(prob(150/severity))
|
||||
icon_state = "[initial(icon_state)]emp"
|
||||
var/list/previous_network = network
|
||||
network = list()
|
||||
cameranet.removeCamera(src)
|
||||
stat |= EMPED
|
||||
set_light(0)
|
||||
triggerCameraAlarm(10 * severity)
|
||||
emped = emped+1 //Increase the number of consecutive EMP's
|
||||
var/thisemp = emped //Take note of which EMP this proc is for
|
||||
spawn(900)
|
||||
if(loc) //qdel limbo
|
||||
triggerCameraAlarm() //camera alarm triggers even if multiple EMPs are in effect.
|
||||
if(emped == thisemp) //Only fix it if the camera hasn't been EMP'd again
|
||||
network = previous_network
|
||||
icon_state = initial(icon_state)
|
||||
@@ -104,7 +85,9 @@
|
||||
if(can_use())
|
||||
cameranet.addCamera(src)
|
||||
emped = 0 //Resets the consecutive EMP count
|
||||
invalidateCameraCache()
|
||||
spawn(100)
|
||||
if(!qdeleted(src))
|
||||
cancelCameraAlarm()
|
||||
for(var/mob/O in mob_list)
|
||||
if (O.client && O.client.eye == src)
|
||||
O.unset_machine()
|
||||
@@ -128,19 +111,18 @@
|
||||
if(!istype(user))
|
||||
return
|
||||
user.do_attack_animation(src)
|
||||
add_hiddenprint(user)
|
||||
status = 0
|
||||
visible_message("<span class='warning'>\The [user] slashes at [src]!</span>")
|
||||
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
add_hiddenprint(user)
|
||||
deactivate(user,0)
|
||||
toggle_cam(user, 0)
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(var/num = 7)
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(num = 7)
|
||||
src.view_range = num
|
||||
cameranet.updateVisibility(src, 0)
|
||||
|
||||
/obj/machinery/camera/attackby(W as obj, mob/living/user as mob, params)
|
||||
invalidateCameraCache()
|
||||
var/msg = "<span class='notice'>You attach [W] into the assembly inner circuits.</span>"
|
||||
var/msg2 = "<span class='notice'>The camera already has that upgrade!</span>"
|
||||
|
||||
@@ -214,12 +196,17 @@
|
||||
for(var/mob/O in player_list)
|
||||
if(istype(O, /mob/living/silicon/ai))
|
||||
var/mob/living/silicon/ai/AI = O
|
||||
if(U.name == "Unknown") AI << "<b>[U]</b> holds <a href='?_src_=usr;show_paper=1;'>\a [itemname]</a> up to one of your cameras ..."
|
||||
else AI << "<b><a href='byond://?src=\ref[O];track=\ref[U]'>[U]</a></b> holds <a href='?_src_=usr;show_paper=1;'>\a [itemname]</a> up to one of your cameras ..."
|
||||
if(AI.control_disabled || (AI.stat == DEAD))
|
||||
return
|
||||
if(U.name == "Unknown")
|
||||
AI << "<b>[U]</b> holds <a href='?_src_=usr;show_paper=1;'>\a [itemname]</a> up to one of your cameras ..."
|
||||
else
|
||||
AI << "<b><a href='?src=\ref[AI];track=[html_encode(U.name)]'>[U]</a></b> holds <a href='?_src_=usr;show_paper=1;'>\a [itemname]</a> up to one of your cameras ..."
|
||||
AI.last_paper_seen = "<HTML><HEAD><TITLE>[itemname]</TITLE></HEAD><BODY><TT>[info]</TT></BODY></HTML>"
|
||||
else if (O.client && O.client.eye == src)
|
||||
O << "[U] holds \a [itemname] up to one of the cameras ..."
|
||||
O << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", itemname, info), text("window=[]", itemname))
|
||||
|
||||
else if (istype(W, /obj/item/device/camera_bug))
|
||||
if (!src.can_use())
|
||||
user << "<span class='notice'>Camera non-functional.</span>"
|
||||
@@ -232,8 +219,9 @@
|
||||
user << "<span class='notice'>Camera bugged.</span>"
|
||||
src.bug = W
|
||||
src.bug.bugged_cameras[src.c_tag] = src
|
||||
|
||||
else if(istype(W, /obj/item/weapon/melee/energy/blade))//Putting it here last since it's a special case. I wonder if there is a better way to do these than type casting.
|
||||
deactivate(user,2)//Here so that you can disconnect anyone viewing the camera, regardless if it's on or off.
|
||||
toggle_cam(user, 1)
|
||||
var/datum/effect/system/spark_spread/spark_system = new /datum/effect/system/spark_spread()
|
||||
spark_system.set_up(5, 0, loc)
|
||||
spark_system.start()
|
||||
@@ -241,6 +229,7 @@
|
||||
playsound(loc, "sparks", 50, 1)
|
||||
visible_message("<span class='notice'>[user] has sliced the camera apart with an energy blade!</span>")
|
||||
qdel(src)
|
||||
|
||||
else if(istype(W, /obj/item/device/laser_pointer))
|
||||
var/obj/item/device/laser_pointer/L = W
|
||||
L.laser_act(src, user)
|
||||
@@ -248,32 +237,32 @@
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
|
||||
/obj/machinery/camera/proc/toggle_cam(mob/user, displaymessage = 1)
|
||||
status = !status
|
||||
if(can_use())
|
||||
cameranet.addCamera(src)
|
||||
else
|
||||
set_light(0)
|
||||
cameranet.removeCamera(src)
|
||||
if(choice==1)
|
||||
invalidateCameraCache()
|
||||
status = !( src.status )
|
||||
if (!(src.status))
|
||||
if(user)
|
||||
visible_message("<span class='danger'>[user] deactivates [src]!</span>")
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] deactivates!</span>")
|
||||
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
|
||||
cameranet.updateChunk(x, y, z)
|
||||
var/change_msg = "deactivates"
|
||||
if(!status)
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
change_msg = "reactivates"
|
||||
triggerCameraAlarm()
|
||||
spawn(100)
|
||||
if(!qdeleted(src))
|
||||
cancelCameraAlarm()
|
||||
if(displaymessage)
|
||||
if(user)
|
||||
visible_message("<span class='danger'>[user] [change_msg] [src]!</span>")
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
if(user)
|
||||
visible_message("<span class='danger'>[user] reactivates [src]!</span>")
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] reactivates!</span>")
|
||||
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
icon_state = initial(icon_state)
|
||||
visible_message("<span class='danger'>\The [src] [change_msg]!</span>")
|
||||
|
||||
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
|
||||
// now disconnect anyone using the camera
|
||||
//Apparently, this will disconnect anyone even if the camera was re-activated.
|
||||
@@ -286,14 +275,14 @@
|
||||
|
||||
/obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0)
|
||||
alarm_on = 1
|
||||
camera_alarm.triggerAlarm(loc, src, duration)
|
||||
motion_alarm.triggerAlarm(loc, src)
|
||||
|
||||
/obj/machinery/camera/proc/cancelCameraAlarm()
|
||||
if(wires.IsIndexCut(CAMERA_WIRE_ALARM))
|
||||
return
|
||||
|
||||
alarm_on = 0
|
||||
camera_alarm.clearAlarm(loc, src)
|
||||
motion_alarm.clearAlarm(loc, src)
|
||||
|
||||
/obj/machinery/camera/proc/can_use()
|
||||
if(!status)
|
||||
@@ -339,7 +328,6 @@
|
||||
return null
|
||||
|
||||
/proc/near_range_camera(var/mob/M)
|
||||
|
||||
for(var/obj/machinery/camera/C in range(4, M))
|
||||
if(C.can_use()) // check if camera disabled
|
||||
return C
|
||||
@@ -348,16 +336,13 @@
|
||||
return null
|
||||
|
||||
/obj/machinery/camera/proc/weld(var/obj/item/weapon/weldingtool/WT, var/mob/user)
|
||||
|
||||
if(busy)
|
||||
return 0
|
||||
if(!WT.isOn())
|
||||
if(!WT.remove_fuel(0, user))
|
||||
return 0
|
||||
|
||||
// Do after stuff here
|
||||
user << "<span class='notice'>You start to weld [src].</span>"
|
||||
user << "<span class='notice'>You start to weld [src]...</span>"
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
|
||||
WT.eyecheck(user)
|
||||
busy = 1
|
||||
if(do_after(user, 100, target = src))
|
||||
busy = 0
|
||||
@@ -367,12 +352,37 @@
|
||||
busy = 0
|
||||
return 0
|
||||
|
||||
/obj/machinery/camera/proc/Togglelight(on=0)
|
||||
for(var/mob/living/silicon/ai/A in ai_list)
|
||||
for(var/obj/machinery/camera/cam in A.lit_cameras)
|
||||
if(cam == src)
|
||||
return
|
||||
if(on)
|
||||
src.set_light(AI_CAMERA_LUMINOSITY)
|
||||
else
|
||||
src.set_light(0)
|
||||
|
||||
/obj/machinery/camera/proc/nano_structure()
|
||||
var/cam[0]
|
||||
var/turf/T = get_turf(src)
|
||||
cam["name"] = sanitize(c_tag)
|
||||
cam["deact"] = !can_use()
|
||||
cam["camera"] = "\ref[src]"
|
||||
cam["x"] = x
|
||||
cam["y"] = y
|
||||
cam["z"] = z
|
||||
return cam
|
||||
cam["x"] = T.x
|
||||
cam["y"] = T.y
|
||||
cam["z"] = T.z
|
||||
return cam
|
||||
|
||||
/obj/machinery/camera/portable //Cameras which are placed inside of things, such as helmets.
|
||||
var/turf/prev_turf
|
||||
|
||||
/obj/machinery/camera/portable/New()
|
||||
..()
|
||||
assembly.state = 0 //These cameras are portable, and so shall be in the portable state if removed.
|
||||
assembly.anchored = 0
|
||||
assembly.update_icon()
|
||||
|
||||
/obj/machinery/camera/portable/process() //Updates whenever the camera is moved.
|
||||
if(cameranet && get_turf(src) != prev_turf)
|
||||
cameranet.updatePortableCamera(src)
|
||||
prev_turf = get_turf(src)
|
||||
@@ -1,30 +1,36 @@
|
||||
/mob/living/silicon/ai/var/max_locations = 10
|
||||
/mob/living/silicon/ai/var/stored_locations[0]
|
||||
|
||||
/mob/living/silicon/ai/proc/InvalidTurf(turf/T as turf)
|
||||
if(!T)
|
||||
return 1
|
||||
if((T.z in config.admin_levels))
|
||||
return 1
|
||||
if(T.z > 6)
|
||||
if(T.z > MAX_Z)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/silicon/ai/var/max_locations = 10
|
||||
/mob/living/silicon/ai/var/stored_locations[0]
|
||||
|
||||
/mob/living/silicon/ai/proc/get_camera_list()
|
||||
|
||||
track.cameras.Cut()
|
||||
|
||||
if(src.stat == 2)
|
||||
return
|
||||
|
||||
cameranet.process_sort()
|
||||
var/list/L = list()
|
||||
for (var/obj/machinery/camera/C in cameranet.cameras)
|
||||
L.Add(C)
|
||||
|
||||
camera_sort(L)
|
||||
|
||||
var/list/T = list()
|
||||
T["Cancel"] = "Cancel"
|
||||
for (var/obj/machinery/camera/C in cameranet.cameras)
|
||||
var/list/tempnetwork = C.network&src.network
|
||||
|
||||
for (var/obj/machinery/camera/C in L)
|
||||
var/list/tempnetwork = C.network & src.network
|
||||
if (tempnetwork.len)
|
||||
T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C
|
||||
|
||||
track = new()
|
||||
track.cameras = T
|
||||
return T
|
||||
|
||||
@@ -63,7 +69,7 @@
|
||||
src << "\red There is already a stored location by this name"
|
||||
return
|
||||
|
||||
var/L = src.eyeobj.getLoc()
|
||||
var/L = get_turf(eyeobj)
|
||||
if (InvalidTurf(get_turf(L)))
|
||||
src << "\red Unable to store this location"
|
||||
return
|
||||
@@ -108,53 +114,37 @@
|
||||
|
||||
/mob/living/silicon/ai/proc/trackable_mobs()
|
||||
|
||||
track.names.Cut()
|
||||
track.namecounts.Cut()
|
||||
track.humans.Cut()
|
||||
track.others.Cut()
|
||||
|
||||
if(usr.stat == 2)
|
||||
return list()
|
||||
|
||||
var/datum/trackable/TB = new()
|
||||
for(var/mob/living/M in mob_list)
|
||||
// Easy checks first.
|
||||
// Don't detect mobs on Centcom. Since the wizard den is on Centcomm, we only need this.
|
||||
if(InvalidTurf(get_turf(M)))
|
||||
continue
|
||||
if(M == usr)
|
||||
continue
|
||||
if(M.invisibility)//cloaked
|
||||
continue
|
||||
if(M.digitalcamo)
|
||||
if(!M.can_track(usr))
|
||||
continue
|
||||
|
||||
// Human check
|
||||
var/human = 0
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
human = 1
|
||||
var/mob/living/carbon/human/H = M
|
||||
//Cameras can't track people wearing an untrackable card
|
||||
var/obj/item/weapon/card/id/id = H.wear_id
|
||||
if(istype(id) && id.is_untrackable())
|
||||
continue
|
||||
if(istype(H.head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = H.head
|
||||
if(hat.blockTracking)
|
||||
continue
|
||||
// Now, are they trackable? (This is last because it's the most intensive check)
|
||||
if(!trackable(M))
|
||||
continue
|
||||
|
||||
var/name = M.name
|
||||
if (name in TB.names)
|
||||
TB.namecounts[name]++
|
||||
name = text("[] ([])", name, TB.namecounts[name])
|
||||
if (name in track.names)
|
||||
track.namecounts[name]++
|
||||
name = text("[] ([])", name, track.namecounts[name])
|
||||
else
|
||||
TB.names.Add(name)
|
||||
TB.namecounts[name] = 1
|
||||
track.names.Add(name)
|
||||
track.namecounts[name] = 1
|
||||
if(human)
|
||||
TB.humans[name] = M
|
||||
track.humans[name] = M
|
||||
else
|
||||
TB.others[name] = M
|
||||
track.others[name] = M
|
||||
|
||||
var/list/targets = sortList(track.humans) + sortList(track.others)
|
||||
|
||||
var/list/targets = sortList(TB.humans) + sortList(TB.others)
|
||||
src.track = TB
|
||||
return targets
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_camera_track(target_name in trackable_mobs())
|
||||
@@ -162,14 +152,14 @@
|
||||
set name = "Track With Camera"
|
||||
set desc = "Select who you would like to track."
|
||||
|
||||
if(src.stat == 2)
|
||||
if(src.stat == DEAD)
|
||||
src << "You can't track with camera because you are dead!"
|
||||
return
|
||||
if(!target_name)
|
||||
src.cameraFollow = null
|
||||
return
|
||||
|
||||
var/mob/target = (isnull(track.humans[target_name]) ? track.others[target_name] : track.humans[target_name])
|
||||
src.track = null
|
||||
|
||||
ai_actual_track(target)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_cancel_tracking(var/forced = 0)
|
||||
@@ -177,65 +167,74 @@
|
||||
return
|
||||
|
||||
src << "Follow camera mode [forced ? "terminated" : "ended"]."
|
||||
cameraFollow.tracking_cancelled()
|
||||
cameraFollow = null
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_actual_track(atom/movable/target as mob|obj)
|
||||
if(!istype(target)) return
|
||||
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target)
|
||||
if(!istype(target))
|
||||
return
|
||||
var/mob/living/silicon/ai/U = usr
|
||||
|
||||
U.cameraFollow = target
|
||||
U << "Now tracking [target.name] on camera."
|
||||
target.tracking_initiated()
|
||||
U.tracking = 1
|
||||
|
||||
spawn (0)
|
||||
while (U.cameraFollow == target)
|
||||
if (U.cameraFollow == null)
|
||||
U << "<span class='notice'>Attempting to track [target.get_visible_name()]...</span>"
|
||||
sleep(min(30, get_dist(target, U.eyeobj) / 4))
|
||||
spawn(15) //give the AI a grace period to stop moving.
|
||||
U.tracking = 0
|
||||
|
||||
if(!target || !target.can_track(usr))
|
||||
U << "<span class='warning'>Target is not near any active cameras.</span>"
|
||||
U.cameraFollow = null
|
||||
return
|
||||
|
||||
U << "<span class='notice'>Now tracking [target.get_visible_name()] on camera.</span>"
|
||||
|
||||
var/cameraticks = 0
|
||||
spawn(0)
|
||||
while(U.cameraFollow == target)
|
||||
if(U.cameraFollow == null)
|
||||
return
|
||||
|
||||
if (!trackable(target))
|
||||
U << "<span class='warning'>Target is not on or near any active cameras on the station.</span>"
|
||||
sleep(100)
|
||||
continue
|
||||
if(!target.can_track(usr))
|
||||
U.tracking = 1
|
||||
if(!cameraticks)
|
||||
U << "<span class='warning'>Target is not near any active cameras. Attempting to reacquire...</span>"
|
||||
cameraticks++
|
||||
if(cameraticks > 9)
|
||||
U.cameraFollow = null
|
||||
U << "<span class='warning'>Unable to reacquire, cancelling track...</span>"
|
||||
U.tracking = 0
|
||||
return
|
||||
else
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
else
|
||||
cameraticks = 0
|
||||
U.tracking = 0
|
||||
|
||||
if(U.eyeobj)
|
||||
U.eyeobj.setLoc(get_turf(target), 0)
|
||||
U.eyeobj.setLoc(get_turf(target))
|
||||
|
||||
else
|
||||
view_core()
|
||||
U.cameraFollow = null
|
||||
return
|
||||
|
||||
sleep(10)
|
||||
|
||||
/proc/near_camera(var/mob/living/M)
|
||||
/proc/near_camera(mob/living/M)
|
||||
if (!isturf(M.loc))
|
||||
return 0
|
||||
if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(!(R.camera && R.camera.can_use()) && !cameranet.checkCameraVis(M))
|
||||
return 0
|
||||
else if(!isturf(M.loc) || !cameranet.checkCameraVis(M))
|
||||
else if(!cameranet.checkCameraVis(M))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/proc/trackable(atom/movable/M)
|
||||
var/turf/T = get_turf(M)
|
||||
if (istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/obj/item/weapon/card/id/id = H.wear_id
|
||||
if(istype(id) && id.is_untrackable())
|
||||
return 0
|
||||
if(H.digitalcamo)
|
||||
return 0
|
||||
if(istype(H.head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = H.head
|
||||
if (hat.blockTracking)
|
||||
return 0
|
||||
if(istype(M.loc,/obj/effect/dummy))
|
||||
return 0
|
||||
|
||||
if((T && (T.z in config.contact_levels)) && ((hassensorlevel(M, SUIT_SENSOR_TRACKING) || M in aibots)))
|
||||
return 1
|
||||
|
||||
return near_camera(M)
|
||||
|
||||
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
|
||||
/obj/machinery/camera/attack_ai(mob/living/silicon/ai/user)
|
||||
if (!istype(user))
|
||||
return
|
||||
if (!src.can_use())
|
||||
@@ -243,19 +242,21 @@
|
||||
user.eyeobj.setLoc(get_turf(src))
|
||||
|
||||
|
||||
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
|
||||
/mob/living/silicon/ai/attack_ai(mob/user)
|
||||
ai_camera_list()
|
||||
|
||||
/atom/movable/proc/tracking_initiated()
|
||||
/proc/camera_sort(list/L)
|
||||
var/obj/machinery/camera/a
|
||||
var/obj/machinery/camera/b
|
||||
|
||||
/mob/living/silicon/robot/tracking_initiated()
|
||||
tracking_entities++
|
||||
if(tracking_entities == 1 && has_zeroth_law())
|
||||
src << "<span class='warning'>Internal camera is currently being accessed.</span>"
|
||||
|
||||
/atom/movable/proc/tracking_cancelled()
|
||||
|
||||
/mob/living/silicon/robot/tracking_initiated()
|
||||
tracking_entities--
|
||||
if(!tracking_entities && has_zeroth_law())
|
||||
src << "<span class='notice'>Internal camera is no longer being accessed.</span>"
|
||||
for (var/i = L.len, i > 0, i--)
|
||||
for (var/j = 1 to i - 1)
|
||||
a = L[j]
|
||||
b = L[j + 1]
|
||||
if (a.c_tag_order != b.c_tag_order)
|
||||
if (a.c_tag_order > b.c_tag_order)
|
||||
L.Swap(j, j + 1)
|
||||
else
|
||||
if (sorttext(a.c_tag, b.c_tag) < 0)
|
||||
L.Swap(j, j + 1)
|
||||
return L
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/var/camera_cache_id = 1
|
||||
|
||||
/proc/invalidateCameraCache()
|
||||
camera_cache_id = (++camera_cache_id % 999999)
|
||||
|
||||
/obj/machinery/computer/security
|
||||
name = "Camera Monitor"
|
||||
desc = "Used to access the various cameras networks on the station."
|
||||
@@ -11,38 +6,35 @@
|
||||
circuit = /obj/item/weapon/circuitboard/camera
|
||||
var/obj/machinery/camera/current = null
|
||||
var/list/network = list("")
|
||||
var/last_pic = 1.0
|
||||
var/last_pic = 1
|
||||
light_color = LIGHT_COLOR_RED
|
||||
var/mapping = 0
|
||||
var/cache_id = 0
|
||||
var/list/networks[0]
|
||||
var/list/tempnets[0]
|
||||
var/list/data[0]
|
||||
var/list/access[0]
|
||||
var/camera_cache = null
|
||||
|
||||
/obj/machinery/computer/security/New() // Lists existing networks and their required access. Format: networks[<name>] = list(<access>)
|
||||
networks["SS13"] = list(access_hos,access_captain)
|
||||
networks["Telecomms"] = list(access_hos,access_captain)
|
||||
networks["Research Outpost"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Mining Outpost"] = list(access_qm,access_hop,access_hos,access_captain)
|
||||
networks["Research"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Prison"] = list(access_hos,access_captain)
|
||||
networks["Labor"] = list(access_hos,access_captain)
|
||||
networks["Interrogation"] = list(access_hos,access_captain)
|
||||
networks["SS13"] = list(access_hos,access_captain)
|
||||
networks["Telecomms"] = list(access_hos,access_captain)
|
||||
networks["Research Outpost"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Mining Outpost"] = list(access_qm,access_hop,access_hos,access_captain)
|
||||
networks["Research"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Prison"] = list(access_hos,access_captain)
|
||||
networks["Labor"] = list(access_hos,access_captain)
|
||||
networks["Interrogation"] = list(access_hos,access_captain)
|
||||
networks["Atmosphere Alarms"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Fire Alarms"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Power Alarms"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Supermatter"] = list(access_ce,access_hos,access_captain)
|
||||
networks["MiniSat"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Singularity"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Fire Alarms"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Power Alarms"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Supermatter"] = list(access_ce,access_hos,access_captain)
|
||||
networks["MiniSat"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Singularity"] = list(access_ce,access_hos,access_captain)
|
||||
networks["Anomaly Isolation"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Toxins"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Telepad"] = list(access_rd,access_hos,access_captain)
|
||||
networks["TestChamber"] = list(access_rd,access_hos,access_captain)
|
||||
networks["ERT"] = list(access_cent_specops_commander,access_cent_commander)
|
||||
networks["CentComm"] = list(access_cent_security,access_cent_commander)
|
||||
networks["Thunderdome"] = list(access_cent_thunder,access_cent_commander)
|
||||
networks["Toxins"] = list(access_rd,access_hos,access_captain)
|
||||
networks["Telepad"] = list(access_rd,access_hos,access_captain)
|
||||
networks["TestChamber"] = list(access_rd,access_hos,access_captain)
|
||||
networks["ERT"] = list(access_cent_specops_commander,access_cent_commander)
|
||||
networks["CentComm"] = list(access_cent_security,access_cent_commander)
|
||||
networks["Thunderdome"] = list(access_cent_thunder,access_cent_commander)
|
||||
|
||||
..()
|
||||
|
||||
@@ -75,50 +67,55 @@
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/computer/security/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(src.z > 6) return
|
||||
if(stat & (NOPOWER|BROKEN)) return
|
||||
if(user.stat) return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(user.stat)
|
||||
return
|
||||
|
||||
var/data[0]
|
||||
|
||||
data["current"] = null
|
||||
|
||||
if(camera_cache_id != cache_id)
|
||||
cache_id = camera_cache_id
|
||||
cameranet.process_sort()
|
||||
var/list/cameras = list()
|
||||
for(var/obj/machinery/camera/C in cameranet.cameras)
|
||||
if((z > MAX_Z || C.z > MAX_Z) && (C.z != z)) //can only recieve away mission cameras on away missions
|
||||
continue
|
||||
if(!can_access_camera(C))
|
||||
continue
|
||||
|
||||
var/cameras[0]
|
||||
for(var/obj/machinery/camera/C in cameranet.cameras)
|
||||
if(!can_access_camera(C))
|
||||
continue
|
||||
cameras[++cameras.len] = C.nano_structure()
|
||||
|
||||
var/cam = C.nano_structure()
|
||||
cameras[++cameras.len] = cam
|
||||
for(var/i = cameras.len, i > 0, i--) //based off /proc/camera_sort, sorts cameras alphabetically for the UI
|
||||
for(var/j = 1 to i - 1)
|
||||
var/a = cameras[j]
|
||||
var/b = cameras[j + 1]
|
||||
if(sorttext(a["name"], b["name"]) < 0)
|
||||
cameras.Swap(j, j + 1)
|
||||
|
||||
camera_cache=list2json(cameras)
|
||||
data["cameras"] = cameras
|
||||
|
||||
tempnets.Cut()
|
||||
if(emagged)
|
||||
access = list(access_captain) // Assume captain level access when emagged
|
||||
data["emagged"] = 1
|
||||
|
||||
if(isAI(user) || isrobot(user))
|
||||
access = list(access_captain) // Assume captain level access when AI
|
||||
|
||||
var/tempnets[0]
|
||||
// Loop through the ID's permission, and check which networks the ID has access to.
|
||||
for(var/l in networks) // Loop through networks.
|
||||
for(var/m in networks[l]) // Loop through access levels of the networks.
|
||||
if(m in access)
|
||||
if(l in network) // Checks if the network is currently active.
|
||||
tempnets.Add(list(list("name" = l, "active" = 1)))
|
||||
for(var/net in networks) // Loop through networks.
|
||||
for(var/req in networks[net]) // Loop through access levels of the networks.
|
||||
if(req in access)
|
||||
if(net in network) // Checks if the network is currently active.
|
||||
tempnets.Add(list(list("name" = net, "active" = 1)))
|
||||
else
|
||||
tempnets.Add(list(list("name" = l, "active" = 0)))
|
||||
tempnets.Add(list(list("name" = net, "active" = 0)))
|
||||
break
|
||||
|
||||
if(tempnets.len)
|
||||
data["networks"] = tempnets
|
||||
|
||||
if(current)
|
||||
data["current"] = current.nano_structure()
|
||||
data["cameras"] = list("__json_cache" = camera_cache)
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
@@ -134,20 +131,24 @@
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/security/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["switchTo"])
|
||||
if(src.z>6 || stat&(NOPOWER|BROKEN)) return
|
||||
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras
|
||||
if(!C) return
|
||||
if(!C)
|
||||
return 1
|
||||
|
||||
switch_to_camera(usr, C)
|
||||
return 1
|
||||
|
||||
else if(href_list["reset"])
|
||||
if(src.z>6 || stat&(NOPOWER|BROKEN)) return
|
||||
if(usr.stat || ((get_dist(usr, src) > 1 || !( usr.canmove ) || usr.blinded) && !istype(usr, /mob/living/silicon))) return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
reset_current()
|
||||
usr.check_eye(current)
|
||||
return 1
|
||||
|
||||
else if(href_list["activate"]) // Activate: enable or disable networks
|
||||
var/net = href_list["activate"] // Network to be enabled or disabled.
|
||||
var/active = href_list["active"] // Is the network currently active.
|
||||
@@ -159,17 +160,13 @@
|
||||
else
|
||||
src.network += net
|
||||
break
|
||||
invalidateCameraCache()
|
||||
nanomanager.update_uis(src)
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/security/attack_hand(var/mob/user as mob)
|
||||
|
||||
/obj/machinery/computer/security/attack_hand(mob/user)
|
||||
access = list()
|
||||
if (src.z > 6)
|
||||
user << "\red <b>Unable to establish a connection</b>: \black You're too far away from the station!"
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN)) return
|
||||
|
||||
if(!isAI(user))
|
||||
user.set_machine(src)
|
||||
@@ -191,9 +188,9 @@
|
||||
|
||||
// Switching to cameras
|
||||
/obj/machinery/computer/security/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
|
||||
if ((get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) || !( C.can_use() )) && (!istype(user, /mob/living/silicon/ai)))
|
||||
if((get_dist(user, src) > 1 || user.machine != src || user.blinded || !(user.canmove) || !C.can_use()) && !(istype(user, /mob/living/silicon/ai)))
|
||||
if(!C.can_use() && !isAI(user))
|
||||
src.current = null
|
||||
current = null
|
||||
return 0
|
||||
else
|
||||
if(isAI(user))
|
||||
@@ -215,18 +212,11 @@
|
||||
if(current)
|
||||
reset_current()
|
||||
|
||||
src.current = C
|
||||
current = C
|
||||
if(current)
|
||||
use_power = 2
|
||||
var/mob/living/L = current.loc
|
||||
if(istype(L))
|
||||
L.tracking_initiated()
|
||||
|
||||
/obj/machinery/computer/security/proc/reset_current()
|
||||
if(current)
|
||||
var/mob/living/L = current.loc
|
||||
if(istype(L))
|
||||
L.tracking_cancelled()
|
||||
current = null
|
||||
use_power = 1
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
var/found_eye = 0
|
||||
|
||||
for(var/mob/aiEye/A in living_mob_list)
|
||||
for(var/mob/camera/aiEye/A in living_mob_list)
|
||||
|
||||
var/turf/our_turf = get_turf(src)
|
||||
var/turf/eye_turf = get_turf(A)
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
for(var/obj/machinery/camera/C in alarm.cameras())
|
||||
if(was_raised)
|
||||
C.network.Add(category)
|
||||
invalidateCameraCache()
|
||||
else
|
||||
C.network.Remove(category)
|
||||
notify_listeners(alarm, was_raised)
|
||||
|
||||
@@ -190,7 +190,6 @@
|
||||
if(temp.len)
|
||||
L.Add(C)
|
||||
|
||||
cameranet.process_sort()
|
||||
|
||||
return L
|
||||
verify_machine(var/obj/machinery/camera/C,var/datum/file/camnet_key/key = null)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
mouse_opacity = 0
|
||||
see_in_dark = 7
|
||||
invisibility = 101 // No one can see us
|
||||
|
||||
sight = SEE_SELF
|
||||
move_on_shuttle = 0
|
||||
|
||||
/mob/camera/experience_pressure_difference()
|
||||
@@ -17,7 +17,7 @@
|
||||
/mob/camera/Destroy()
|
||||
..()
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
|
||||
/mob/camera/Login()
|
||||
..()
|
||||
update_interface()
|
||||
|
||||
@@ -694,10 +694,10 @@
|
||||
return
|
||||
|
||||
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere
|
||||
/mob/living/carbon/human/proc/get_visible_name()
|
||||
if( wear_mask && (wear_mask.flags_inv&HIDEFACE) ) //Wearing a mask which hides our face, use id-name if possible
|
||||
/mob/living/carbon/human/get_visible_name()
|
||||
if(wear_mask && (wear_mask.flags_inv & HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible
|
||||
return get_id_name("Unknown")
|
||||
if( head && (head.flags_inv&HIDEFACE) )
|
||||
if(head && (head.flags_inv & HIDEFACE))
|
||||
return get_id_name("Unknown") //Likewise for hats
|
||||
var/face_name = get_face_name()
|
||||
var/id_name = get_id_name("")
|
||||
@@ -1913,5 +1913,17 @@
|
||||
src << "<span class='notice'>You swallow a gulp of [toDrink].</span>"
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/can_track(mob/living/user)
|
||||
if(wear_id)
|
||||
var/obj/item/weapon/card/id/id = wear_id
|
||||
if(istype(id) && id.is_untrackable())
|
||||
return 0
|
||||
if(istype(head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = head
|
||||
if(hat.blockTracking)
|
||||
return 0
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/get_age_pitch()
|
||||
return 1.0 + 0.5*(30 - age)/80
|
||||
@@ -10,6 +10,28 @@
|
||||
if(rig)
|
||||
SetupStat(rig)
|
||||
|
||||
/mob/living/proc/can_track(mob/living/user)
|
||||
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return 0
|
||||
if(T.z == ZLEVEL_CENTCOMM) //dont detect mobs on centcomm
|
||||
return 0
|
||||
if(T.z >= MAX_Z)
|
||||
return 0
|
||||
if(user != null && src == user)
|
||||
return 0
|
||||
if(invisibility || alpha == 0)//cloaked
|
||||
return 0
|
||||
if(digitalcamo)
|
||||
return 0
|
||||
|
||||
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
|
||||
if(!near_camera(src))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
//mob verbs are a lot faster than object verbs
|
||||
//for more info on why this is not atom/pull, see examinate() in mob.dm
|
||||
/mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1))
|
||||
@@ -760,6 +782,9 @@
|
||||
src << "<span class='notice'>You're too exhausted to keep going...</span>"
|
||||
Weaken(5)
|
||||
|
||||
/mob/living/proc/get_visible_name()
|
||||
return name
|
||||
|
||||
/mob/living/update_gravity(has_gravity)
|
||||
if(!ticker)
|
||||
return
|
||||
|
||||
@@ -46,7 +46,7 @@ var/list/ai_verbs_default = list(
|
||||
var/list/connected_robots = list()
|
||||
var/aiRestorePowerRoutine = 0
|
||||
//var/list/laws = list()
|
||||
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list())
|
||||
var/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list())
|
||||
var/viewalerts = 0
|
||||
var/icon/holo_icon//Default is assigned when AI is created.
|
||||
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
|
||||
@@ -69,10 +69,13 @@ var/list/ai_verbs_default = list(
|
||||
var/obj/machinery/power/apc/malfhack = null
|
||||
var/explosive = 0 //does the AI explode when it dies?
|
||||
|
||||
var/mob/living/silicon/ai/parent = null
|
||||
|
||||
var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through.
|
||||
var/datum/trackable/track = null
|
||||
var/mob/living/silicon/ai/parent = null
|
||||
var/camera_light_on = 0
|
||||
var/list/obj/machinery/camera/lit_cameras = list()
|
||||
|
||||
var/datum/trackable/track = new()
|
||||
|
||||
var/last_paper_seen = null
|
||||
var/can_shunt = 1
|
||||
var/last_announcement = ""
|
||||
@@ -81,6 +84,15 @@ var/list/ai_verbs_default = list(
|
||||
var/turf/waypoint //Holds the turf of the currently selected waypoint.
|
||||
var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
|
||||
|
||||
var/obj/machinery/hologram/holopad/holo = null
|
||||
var/mob/camera/aiEye/eyeobj = new()
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
var/acceleration = 1
|
||||
var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
|
||||
|
||||
var/obj/machinery/camera/portable/builtInCamera
|
||||
|
||||
//var/obj/item/borg/sight/hud/sec/sechud = null
|
||||
//var/obj/item/borg/sight/hud/med/healthhud = null
|
||||
|
||||
@@ -175,6 +187,13 @@ var/list/ai_verbs_default = list(
|
||||
spawn(5)
|
||||
new /obj/machinery/ai_powersupply(src)
|
||||
|
||||
eyeobj.ai = src
|
||||
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
|
||||
eyeobj.loc = src.loc
|
||||
|
||||
builtInCamera = new /obj/machinery/camera/portable(src)
|
||||
builtInCamera.c_tag = name
|
||||
builtInCamera.network = list("SS13")
|
||||
|
||||
ai_list += src
|
||||
shuttle_caller_list += src
|
||||
@@ -486,8 +505,8 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if (href_list["track"])
|
||||
var/mob/target = locate(href_list["track"]) in mob_list
|
||||
if(target && trackable(target))
|
||||
var/mob/living/target = locate(href_list["track"]) in mob_list
|
||||
if(target && target.can_track())
|
||||
ai_actual_track(target)
|
||||
else
|
||||
src << "<span class='warning'>Target is not on or near any active cameras on the station.</span>"
|
||||
@@ -495,7 +514,7 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
if (href_list["trackbot"])
|
||||
var/obj/machinery/bot/target = locate(href_list["trackbot"]) in aibots
|
||||
if(target && trackable(target))
|
||||
if(target)
|
||||
ai_actual_track(target)
|
||||
else
|
||||
src << "<span class='warning'>Target is not on or near any active cameras on the station.</span>"
|
||||
@@ -633,7 +652,6 @@ var/list/ai_verbs_default = list(
|
||||
d += "<td width='30%'>[bot_area.name]</td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];interface=\ref[Bot]>Interface</A></td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];callbot=\ref[Bot]>Call</A></td>"
|
||||
d += "<td width='10%'><a href='byond://?src=\ref[src];track2=\ref[src];trackbot=\ref[Bot]'>Track</A></td>"
|
||||
d += "</tr>"
|
||||
d = format_text(d)
|
||||
|
||||
@@ -664,7 +682,10 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)
|
||||
|
||||
if (!C || stat == 2) //C.can_use())
|
||||
if(!tracking)
|
||||
cameraFollow = null
|
||||
|
||||
if (!C || stat == DEAD) //C.can_use())
|
||||
return 0
|
||||
|
||||
if(!src.eyeobj)
|
||||
@@ -825,17 +846,20 @@ var/list/ai_verbs_default = list(
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if(check_unable())
|
||||
camera_light_on = !camera_light_on
|
||||
|
||||
if (!camera_light_on)
|
||||
src << "Camera lights deactivated."
|
||||
|
||||
for (var/obj/machinery/camera/C in lit_cameras)
|
||||
C.set_light(0)
|
||||
lit_cameras = list()
|
||||
|
||||
return
|
||||
|
||||
camera_light_on = !camera_light_on
|
||||
src << "Camera lights [camera_light_on ? "activated" : "deactivated"]."
|
||||
if(!camera_light_on)
|
||||
if(current)
|
||||
current.set_light(0)
|
||||
current = null
|
||||
else
|
||||
lightNearbyCamera()
|
||||
light_cameras()
|
||||
|
||||
src << "Camera lights activated."
|
||||
|
||||
/mob/living/silicon/ai/proc/sensor_mode()
|
||||
set name = "Set Sensor Augmentation"
|
||||
@@ -856,26 +880,25 @@ var/list/ai_verbs_default = list(
|
||||
// Handled 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.current)
|
||||
var/obj/machinery/camera/camera = near_range_camera(src.eyeobj)
|
||||
if(camera && src.current != camera)
|
||||
src.current.set_light(0)
|
||||
if(!camera.light_disabled)
|
||||
src.current = camera
|
||||
src.current.set_light(AI_CAMERA_LUMINOSITY)
|
||||
else
|
||||
src.current = null
|
||||
else if(isnull(camera))
|
||||
src.current.set_light(0)
|
||||
src.current = null
|
||||
else
|
||||
var/obj/machinery/camera/camera = near_range_camera(src.eyeobj)
|
||||
if(camera && !camera.light_disabled)
|
||||
src.current = camera
|
||||
src.current.set_light(AI_CAMERA_LUMINOSITY)
|
||||
camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds.
|
||||
/mob/living/silicon/ai/proc/light_cameras()
|
||||
var/list/obj/machinery/camera/add = list()
|
||||
var/list/obj/machinery/camera/remove = list()
|
||||
var/list/obj/machinery/camera/visible = list()
|
||||
for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
|
||||
for (var/obj/machinery/camera/C in CC.cameras)
|
||||
if (!C.can_use() || get_dist(C, eyeobj) > 7)
|
||||
continue
|
||||
visible |= C
|
||||
|
||||
add = visible - lit_cameras
|
||||
remove = lit_cameras - visible
|
||||
|
||||
for (var/obj/machinery/camera/C in remove)
|
||||
lit_cameras -= C //Removed from list before turning off the light so that it doesn't check the AI looking away.
|
||||
C.Togglelight(0)
|
||||
for (var/obj/machinery/camera/C in add)
|
||||
C.Togglelight(1)
|
||||
lit_cameras |= C
|
||||
|
||||
|
||||
/mob/living/silicon/ai/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
|
||||
|
||||
@@ -2,33 +2,34 @@
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
|
||||
var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
|
||||
|
||||
var/datum/cameranet/cameranet = new()
|
||||
|
||||
/datum/cameranet
|
||||
var/name = "Camera Net" // Name to show for VV and stat()
|
||||
|
||||
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
|
||||
var/list/cameras = list()
|
||||
var/cameras_unsorted = 1
|
||||
// The chunks of the map, mapping the areas that the cameras can see.
|
||||
var/list/chunks = list()
|
||||
var/ready = 0
|
||||
|
||||
/datum/cameranet/proc/process_sort()
|
||||
if(cameras_unsorted)
|
||||
cameras = dd_sortedObjectList(cameras)
|
||||
cameras_unsorted = 0
|
||||
// The object used for the clickable stat() button.
|
||||
var/obj/effect/statclick/statclick
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
|
||||
// Returns the chunk in the x, y, z.
|
||||
// If there is no chunk, it creates a new chunk and returns that.
|
||||
/datum/cameranet/proc/getCameraChunk(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new /datum/camerachunk(null, x, y, z)
|
||||
@@ -37,12 +38,12 @@ var/datum/cameranet/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(mob/aiEye/ai)
|
||||
/datum/cameranet/proc/visibility(mob/camera/aiEye/ai)
|
||||
// 0xf = 15
|
||||
var/x1 = max(0, ai.x - 16) & ~0xf
|
||||
var/y1 = max(0, ai.y - 16) & ~0xf
|
||||
var/x2 = min(world.maxx, ai.x + 16) & ~0xf
|
||||
var/y2 = min(world.maxy, ai.y + 16) & ~0xf
|
||||
var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, ai.x + 16) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, ai.y + 16) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
|
||||
@@ -63,7 +64,7 @@ var/datum/cameranet/cameranet = new()
|
||||
|
||||
// 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, var/opacity_check = 1)
|
||||
/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1)
|
||||
|
||||
if(!ticker || (opacity_check && !A.opacity))
|
||||
return
|
||||
@@ -109,15 +110,15 @@ var/datum/cameranet/cameranet = new()
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
if(T)
|
||||
var/x1 = max(0, T.x - 8) & ~0xf
|
||||
var/y1 = max(0, T.y - 8) & ~0xf
|
||||
var/x2 = min(world.maxx, T.x + 8) & ~0xf
|
||||
var/y2 = min(world.maxy, T.y + 8) & ~0xf
|
||||
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
//world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
|
||||
if(choice == 0)
|
||||
@@ -145,6 +146,14 @@ var/datum/cameranet/cameranet = new()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/*
|
||||
/datum/cameranet/proc/stat_entry()
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug("Initializing...", src)
|
||||
|
||||
stat(name, statclick.update("Cameras: [cameranet.cameras.len] | Chunks: [cameranet.chunks.len]"))
|
||||
*/
|
||||
|
||||
// Debug verb for VVing the chunk that the turf is in.
|
||||
/*
|
||||
/turf/verb/view_chunk()
|
||||
|
||||
@@ -21,26 +21,24 @@
|
||||
|
||||
// Add an AI eye to the chunk, then update if changed.
|
||||
|
||||
/datum/camerachunk/proc/add(mob/aiEye/ai)
|
||||
if(!ai.ai)
|
||||
return
|
||||
ai.visibleCameraChunks += src
|
||||
if(ai.ai.client)
|
||||
ai.ai.client.images += obscured
|
||||
/datum/camerachunk/proc/add(mob/camera/aiEye/eye)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
if(client)
|
||||
client.images += obscured
|
||||
eye.visibleCameraChunks += src
|
||||
visible++
|
||||
seenby += ai
|
||||
seenby += eye
|
||||
if(changed && !updating)
|
||||
update()
|
||||
|
||||
// Remove an AI eye from the chunk, then update if changed.
|
||||
|
||||
/datum/camerachunk/proc/remove(mob/aiEye/ai)
|
||||
if(!ai.ai)
|
||||
return
|
||||
ai.visibleCameraChunks -= src
|
||||
if(ai.ai.client)
|
||||
ai.ai.client.images -= obscured
|
||||
seenby -= ai
|
||||
/datum/camerachunk/proc/remove(mob/camera/aiEye/eye)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
if(client)
|
||||
client.images -= obscured
|
||||
eye.visibleCameraChunks -= src
|
||||
seenby -= eye
|
||||
if(visible > 0)
|
||||
visible--
|
||||
|
||||
@@ -54,7 +52,7 @@
|
||||
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
|
||||
// instead be flagged to update the next time an AI Eye moves near it.
|
||||
|
||||
/datum/camerachunk/proc/hasChanged(var/update_now = 0)
|
||||
/datum/camerachunk/proc/hasChanged(update_now = 0)
|
||||
if(visible || update_now)
|
||||
if(!updating)
|
||||
updating = 1
|
||||
@@ -68,7 +66,7 @@
|
||||
|
||||
/datum/camerachunk/proc/update()
|
||||
|
||||
set background = 1
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
var/list/newVisibleTurfs = list()
|
||||
|
||||
@@ -81,11 +79,14 @@
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
|
||||
if(get_dist(point, c) > 24)
|
||||
var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
|
||||
if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
newVisibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
@@ -102,11 +103,12 @@
|
||||
if(t.obscured)
|
||||
obscured -= t.obscured
|
||||
for(var/eye in seenby)
|
||||
var/mob/aiEye/m = eye
|
||||
if(!m || !m.ai)
|
||||
var/mob/camera/aiEye/m = eye
|
||||
if(!m)
|
||||
continue
|
||||
if(m.ai.client)
|
||||
m.ai.client.images -= t.obscured
|
||||
var/client/client = m.GetViewerClient()
|
||||
if(client)
|
||||
client.images -= t.obscured
|
||||
|
||||
for(var/turf in visRemoved)
|
||||
var/turf/t = turf
|
||||
@@ -116,32 +118,32 @@
|
||||
|
||||
obscured += t.obscured
|
||||
for(var/eye in seenby)
|
||||
var/mob/aiEye/m = eye
|
||||
if(!m || !m.ai)
|
||||
var/mob/camera/aiEye/m = eye
|
||||
if(!m)
|
||||
seenby -= m
|
||||
continue
|
||||
if(m.ai.client)
|
||||
m.ai.client.images += t.obscured
|
||||
var/client/client = m.GetViewerClient()
|
||||
if(client)
|
||||
client.images += t.obscured
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
|
||||
/datum/camerachunk/New(loc, x, y, z)
|
||||
|
||||
// 0xf = 15
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
|
||||
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
|
||||
for(var/obj/machinery/camera/c in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
|
||||
if(c.can_use())
|
||||
cameras += c
|
||||
|
||||
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
|
||||
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
|
||||
turfs[t] = t
|
||||
for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
|
||||
turfs[t] = t
|
||||
|
||||
for(var/camera in cameras)
|
||||
var/obj/machinery/camera/c = camera
|
||||
@@ -152,6 +154,9 @@
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
visibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
|
||||
@@ -3,57 +3,27 @@
|
||||
// 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/aiEye
|
||||
/mob/camera/aiEye
|
||||
name = "Inactive AI Eye"
|
||||
icon = 'icons/mob/AI.dmi'
|
||||
|
||||
icon = 'icons/mob/AI.dmi' //Allows ghosts to see what the AI is looking at.
|
||||
icon_state = "eye"
|
||||
alpha = 127
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
density = 0
|
||||
status_flags = GODMODE // You can't damage it.
|
||||
mouse_opacity = 0
|
||||
see_in_dark = 7
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
var/ghostimage = null
|
||||
|
||||
/mob/aiEye/New()
|
||||
ghostimage = image(src.icon,src,src.icon_state)
|
||||
ghost_darkness_images |= ghostimage //so ghosts can see the blob cursor when they disable darkness
|
||||
updateallghostimages()
|
||||
..()
|
||||
|
||||
/mob/aiEye/Destroy()
|
||||
if (ghostimage)
|
||||
ghost_darkness_images -= ghostimage
|
||||
qdel(ghostimage)
|
||||
ghostimage = null;
|
||||
updateallghostimages()
|
||||
ai = null
|
||||
return ..()
|
||||
|
||||
// Movement code. Returns 0 to stop air movement from moving it.
|
||||
/mob/aiEye/Move()
|
||||
return 0
|
||||
|
||||
// Hide popout menu verbs
|
||||
/mob/aiEye/examinate(atom/A as mob|obj|turf in view())
|
||||
set popup_menu = 0
|
||||
set src = usr.contents
|
||||
return 0
|
||||
var/relay_speech = FALSE
|
||||
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
/mob/aiEye/setLoc(var/T, var/cancel_tracking = 1)
|
||||
|
||||
/mob/camera/aiEye/setLoc(T)
|
||||
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
|
||||
if(cancel_tracking)
|
||||
ai.ai_cancel_tracking()
|
||||
|
||||
T = get_turf(T)
|
||||
loc = T
|
||||
cameranet.visibility(src)
|
||||
@@ -63,40 +33,27 @@
|
||||
if(ai.holo)
|
||||
ai.holo.move_hologram()
|
||||
|
||||
/mob/aiEye/proc/getLoc()
|
||||
|
||||
if(ai)
|
||||
if(!isturf(ai.loc) || !ai.client)
|
||||
return
|
||||
return ai.eyeobj.loc
|
||||
|
||||
/mob/aiEye/experience_pressure_difference()
|
||||
/mob/camera/aiEye/Move()
|
||||
return 0
|
||||
|
||||
// AI MOVEMENT
|
||||
/mob/camera/aiEye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
// The AI's "eye". Described on the top of the page.
|
||||
|
||||
/mob/living/silicon/ai
|
||||
var/mob/aiEye/eyeobj = new()
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
var/acceleration = 1
|
||||
var/obj/machinery/hologram/holopad/holo = null
|
||||
|
||||
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
|
||||
/mob/living/silicon/ai/New()
|
||||
..()
|
||||
eyeobj.ai = src
|
||||
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
|
||||
spawn(5)
|
||||
eyeobj.loc = src.loc
|
||||
/mob/camera/aiEye/Destroy()
|
||||
ai = null
|
||||
return ..()
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(istype(usr, /mob/living/silicon/ai))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
if(AI.eyeobj && AI.client.eye == AI.eyeobj)
|
||||
AI.eyeobj.setLoc(src)
|
||||
AI.cameraFollow = null
|
||||
if (isturf(src.loc) || isturf(src))
|
||||
AI.eyeobj.setLoc(src)
|
||||
|
||||
// AI MOVEMENT
|
||||
|
||||
// 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.
|
||||
@@ -120,38 +77,42 @@
|
||||
else
|
||||
user.sprint = initial
|
||||
|
||||
if(!user.tracking)
|
||||
user.cameraFollow = null
|
||||
|
||||
//user.unset_machine() //Uncomment this if it causes problems.
|
||||
//user.lightNearbyCamera()
|
||||
|
||||
if (user.camera_light_on)
|
||||
user.light_cameras()
|
||||
|
||||
// Return to the Core.
|
||||
|
||||
/mob/living/silicon/ai/proc/core()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Core"
|
||||
|
||||
view_core()
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(!src.eyeobj)
|
||||
if(src.eyeobj && src.loc)
|
||||
src.eyeobj.loc = src.loc
|
||||
else
|
||||
src << "ERROR: Eyeobj not found. Creating new eye..."
|
||||
src.eyeobj = new(loc)
|
||||
src.eyeobj = new(src.loc)
|
||||
src.eyeobj.ai = src
|
||||
src.rename_character(null, real_name)
|
||||
src.eyeobj.name = "[src.name] (AI Eye)" // Give it a name
|
||||
|
||||
if(client && client.eye)
|
||||
client.eye = src
|
||||
for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
|
||||
c.remove(eyeobj)
|
||||
src.eyeobj.setLoc(src)
|
||||
eyeobj.setLoc(loc)
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == 2)
|
||||
return //won't work if dead
|
||||
acceleration = !acceleration
|
||||
usr << "Camera acceleration has been toggled [acceleration ? "on" : "off"]."
|
||||
|
||||
@@ -108,7 +108,7 @@ proc/isembryo(A)
|
||||
return 1
|
||||
|
||||
/proc/isAIEye(A)
|
||||
if(istype(A, /mob/aiEye))
|
||||
if(istype(A, /mob/camera/aiEye))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -379,7 +379,7 @@ proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 fo
|
||||
|
||||
var/atom/oldeye=M.client.eye
|
||||
var/aiEyeFlag = 0
|
||||
if(istype(oldeye, /mob/aiEye))
|
||||
if(istype(oldeye, /mob/camera/aiEye))
|
||||
aiEyeFlag = 1
|
||||
|
||||
var/x
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
set desc = "Delete image"
|
||||
set src in usr
|
||||
|
||||
deletepicture()
|
||||
deletepicture(src)
|
||||
|
||||
/obj/item/device/camera/siliconcam/robot_camera/verb/take_image()
|
||||
set category ="Robot Commands"
|
||||
|
||||
Reference in New Issue
Block a user