-Ported/continued AI Freelook. AIs can now look around like a ghost with the exception that they cannot see what cameras cannot see. Meaning if you're in maintenance, and there's no cameras near you, the AI will not know what you are doing. This also means there's no X-Ray vision cameras anymore. I've added documentation to freelook.dm which explains how the system works, if anyone is interested in adding anything. More information here: http://nanotrasen.com/phpBB3/viewtopic.php?f=7&t=9675

-I've added some cameras to rooms that should have cameras but were previously depending on other camera's using their X-Ray vision in order to see into a room.

-AIs have a multitool in their contents that they can use to interact with the telecommunication machines.

-Added "Follow" for observers. Works the same as AI tracking without checking if they can track.

-Added a range to how far Cyborgs can interact with machines. This is to stop Cyborgs from interacting with machines through cameras, which could be used to easily disable the AI.

git-svn-id: http://tgstation13.googlecode.com/svn/trunk@4531 316c924e-a436-60f5-8080-3fe189b3f50e
This commit is contained in:
giacomand@gmail.com
2012-08-25 05:34:33 +00:00
parent 34b1d3de38
commit 683662f3b6
26 changed files with 9165 additions and 6470 deletions
+61 -120
View File
@@ -1,39 +1,3 @@
var/global/list/obj/machinery/camera/Cameras = list()
/obj/machinery/camera/New()
Cameras += src
..()
/obj/machinery/camera/Del()
Cameras -= src
..()
// Double clicking turfs to move to nearest camera
/turf/proc/move_camera_by_click()
if (usr.stat)
return ..()
if (world.time <= usr:lastDblClick+2)
return ..()
//try to find the closest working camera in the same area, switch to it
var/area/A = get_area(src)
var/best_dist = INFINITY //infinity
var/best_cam = null
for(var/obj/machinery/camera/C in A)
if(usr:network != C.network) continue
if(!C.status) continue // ignore disabled cameras
var/dist = get_dist(src, C)
if(dist < best_dist)
best_dist = dist
best_cam = C
if(!best_cam)
return ..()
usr:lastDblClick = world.time
usr:switchCamera(best_cam)
/mob/living/silicon/ai/proc/ai_camera_list()
set category = "AI Commands"
set name = "Show Camera List"
@@ -55,26 +19,33 @@ var/global/list/obj/machinery/camera/Cameras = list()
var/list/namecounts = list()
var/list/humans = list()
var/list/others = list()
for(var/mob/living/M in mob_list)
//Cameras can't track people wearing an agent card or a ninja hood.
var/human = 0
if(istype(M, /mob/living/carbon/human))
human = 1
if(istype(M:wear_id, /obj/item/weapon/card/id/syndicate))
continue
if(istype(M:head, /obj/item/clothing/head/helmet/space/space_ninja)&&!M:head:canremove)
continue
if(!istype(M.loc, /turf)) //in a closet or something, AI can't see him anyways
continue
if(istype(M.loc.loc, /area/wizard_station))
continue
if(M.invisibility)//cloaked
// Easy checks first.
// Don't detect mobs on Centcom. Since the wizard den is on Centcomm, we only need this.
if(M.loc.z == 2)
continue
if(M == usr)
continue
if(M.invisibility)//cloaked
continue
if(M.digitalcamo)
continue
if(M.loc.z == 2) // Don't detect mobs on Centcom
// 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 agent card or a ninja hood.
if(istype(H.wear_id, /obj/item/weapon/card/id/syndicate))
continue
if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja))
var/obj/item/clothing/head/helmet/space/space_ninja/hood = H.head
if(!hood.canremove)
continue
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
if(!cameranet.checkCameraVis(M))
continue
var/name = M.name
@@ -104,9 +75,10 @@ var/global/list/obj/machinery/camera/Cameras = list()
var/mob/living/silicon/ai/U = usr
U.cameraFollow = target
U << text("Now tracking [] on camera.", target.name)
if (U.machine == null)
U.machine = U
//U << text("Now tracking [] on camera.", target.name)
//if (U.machine == null)
// U.machine = U
U << "Now tracking [target.name] on camera."
spawn (0)
while (U.cameraFollow == target)
@@ -117,7 +89,7 @@ var/global/list/obj/machinery/camera/Cameras = list()
U << "Follow camera mode terminated."
U.cameraFollow = null
return
if(istype(target:head, /obj/item/clothing/head/helmet/space/space_ninja)&&!target:head:canremove)
if(istype(target:head, /obj/item/clothing/head/helmet/space/space_ninja) && !target:head:canremove)
U << "Follow camera mode terminated."
U.cameraFollow = null
return
@@ -132,47 +104,14 @@ var/global/list/obj/machinery/camera/Cameras = list()
return
else if (!target || !istype(target.loc, /turf)) //in a closet
U << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)."
sleep(40) //because we're sleeping another second after this (a few lines down)
sleep(30) //because we're sleeping another second after this (a few lines down)
continue
else if(!cameranet.checkCameraVis(target))
U << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)."
sleep(30) //because we're sleeping another second after this (a few lines down)
continue
var/obj/machinery/camera/C = U.current
if ((C && istype(C, /obj/machinery/camera)) || C==null)
if(isrobot(target))
var/mob/living/silicon/robot/R = target
C = R.camera
U.reset_view(C)
else
var/closestDist = -1
if (C!=null)
if (C.status)
closestDist = get_dist(C, target)
//U << text("Dist = [] for camera []", closestDist, C.name)
var/zmatched = 0
if (closestDist > 7 || closestDist == -1)
//check other cameras
var/obj/machinery/camera/closest = C
for(var/obj/machinery/camera/C2 in Cameras)
if (C2.network == src.network)
if (C2.z == target.z)
zmatched = 1
if (C2.status)
var/dist = get_dist(C2, target)
if ((dist < closestDist) || (closestDist == -1))
closestDist = dist
closest = C2
//U << text("Closest camera dist = [], for camera []", closestDist, closest.area.name)
if (closest != C)
U.reset_view(closest)
//use_power(50)
if (zmatched == 0)
U << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)."
sleep(40) //because we're sleeping another second after this (a few lines down)
else
U << "Follow camera mode ended."
U.cameraFollow = null
U.eyeobj.setLoc(get_turf(target))
sleep(10)
/proc/camera_sort(list/L)
@@ -191,7 +130,6 @@ var/global/list/obj/machinery/camera/Cameras = list()
L.Swap(j, j + 1)
return L
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
if (user != src)
return
@@ -199,13 +137,8 @@ var/global/list/obj/machinery/camera/Cameras = list()
if (stat == 2)
return
// If they cancel then just put them back to their old camera
var/obj/machinery/camera/tempC = src.current
user.machine = src
switchCamera(null)
var/list/L = list()
for (var/obj/machinery/camera/C in Cameras)
for (var/obj/machinery/camera/C in cameranet.cameras)
L.Add(C)
camera_sort(L)
@@ -214,19 +147,15 @@ var/global/list/obj/machinery/camera/Cameras = list()
D["Cancel"] = "Cancel"
for (var/obj/machinery/camera/C in L)
if (C.network == src.network)
D[text("[][]", C.c_tag, (C.status ? null : " (Deactivated)"))] = C
D[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C
var/t = input(user, "Which camera should you change to?") as null|anything in D
if (!t || t == "Cancel")
if(tempC && tempC.status)
switchCamera(tempC)
else
switchCamera(null)
return 0
var/obj/machinery/camera/C = D[t]
switchCamera(C)
src.eyeobj.setLoc(C)
return
@@ -234,13 +163,15 @@ var/global/list/obj/machinery/camera/Cameras = list()
if(prob(100/(hardened + severity)))
icon_state = "cameraemp"
network = null //Not the best way but it will do. I think.
cameranet.removeCamera(src)
stat |= EMPED
sd_SetLuminosity(0)
spawn(900)
network = initial(network)
icon_state = initial(icon_state)
for(var/mob/living/silicon/ai/O in mob_list)
if (O.current == src)
O.cancel_camera()
O << "Your connection to the camera has been lost."
stat &= ~EMPED
if(can_use())
cameranet.addCamera(src)
for(var/mob/O in mob_list)
if (istype(O.machine, /obj/machinery/computer/security))
var/obj/machinery/computer/security/S = O.machine
@@ -266,9 +197,9 @@ var/global/list/obj/machinery/camera/Cameras = list()
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
if (!istype(user))
return
if (src.network != user.network || !(src.status))
if (!src.can_use())
return
user.reset_view(src)
user.eyeobj.setLoc(get_turf(src))
/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob)
if(!istype(user))
@@ -329,7 +260,7 @@ var/global/list/obj/machinery/camera/Cameras = list()
case.motion = 1
del(src)
else if (istype(W, /obj/item/weapon/camera_bug))
if (!src.status)
if (!src.can_use())
user << "\blue Camera non-functional"
return
if (src.bugged)
@@ -381,10 +312,6 @@ var/global/list/obj/machinery/camera/Cameras = list()
// now disconnect anyone using the camera
//Apparently, this will disconnect anyone even if the camera was re-activated.
//I guess that doesn't matter since they can't use it anyway?
for(var/mob/living/silicon/ai/O in player_list)
if (O.current == src)
O.cancel_camera()
O << "Your connection to the camera has been lost."
for(var/mob/O in player_list)
if (istype(O.machine, /obj/machinery/computer/security))
var/obj/machinery/computer/security/S = O.machine
@@ -393,6 +320,13 @@ var/global/list/obj/machinery/camera/Cameras = list()
O.reset_view(null)
O << "The screen bursts into static."
/obj/machinery/camera/proc/can_use()
if(!status)
return 0
if(stat & EMPED)
return 0
return 1
/atom/proc/auto_turn()
//Automatically turns based on nearby walls.
var/turf/simulated/wall/T = null
@@ -414,10 +348,17 @@ var/global/list/obj/machinery/camera/Cameras = list()
//Return a working camera that can see a given mob
//or null if none
/proc/seen_by_camera(var/mob/M)
for(var/obj/machinery/camera/C in oview(4, M))
if(C.can_use()) // check if camera disabled
return C
break
return null
for(var/obj/machinery/camera/C in oview(M))
if(C.status) // check if camera disabled
/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
break
return null
return null
+14 -7
View File
@@ -30,10 +30,11 @@
attack_hand(var/mob/user as mob)
if(stat & (NOPOWER|BROKEN)) return
user.machine = src
if(!isAI(user))
user.machine = src
var/list/L = list()
for (var/obj/machinery/camera/C in Cameras)
for (var/obj/machinery/camera/C in cameranet.cameras)
L.Add(C)
camera_sort(L)
@@ -56,14 +57,20 @@
return 0
if(C)
if ((get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) || !( C.status )) && (!istype(user, /mob/living/silicon/ai)))
if(!C.status)
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
return 0
else
src.current = C
use_power(50)
spawn( 5 )
if(isAI(user))
var/mob/living/silicon/ai/A = user
A.eyeobj.setLoc(get_turf(C))
A.client.eye = A.eyeobj
else
src.current = C
use_power(50)
spawn(5)
attack_hand(user)
return
+8 -6
View File
@@ -31,9 +31,8 @@ Possible to do for anyone motivated enough:
/*There are pretty much only three ways to interact here.
I don't need to check for client since they're clicking on an object.
This may change in the future but for now will suffice.*/
if(user.client.eye!=src)//Set client eye on the object if it's not already.
user.current = src
user.reset_view(src)
if(user.eyeobj.loc != src.loc)//Set client eye on the object if it's not already.
user.eyeobj.setLoc(get_turf(src))
else if(!hologram)//If there is no hologram, possibly make one.
activate_holo(user)
else if(master==user)//If there is a hologram, remove it. But only if the user is the master. Otherwise do nothing.
@@ -41,7 +40,7 @@ Possible to do for anyone motivated enough:
return
/obj/machinery/hologram/holopad/proc/activate_holo(mob/living/silicon/ai/user)
if(!(stat & NOPOWER)&&user.client.eye==src)//If the projector has power and client eye is on it.
if(!(stat & NOPOWER) && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it.
if(!hologram)//If there is not already a hologram.
create_holo(user)//Create one.
for(var/mob/M in viewers())
@@ -76,6 +75,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
hologram.name = "AI hologram"//If someone decides to right click.
sd_SetLuminosity(1)//To make the pad glowy.
icon_state = "holopad1"
A.current = src
master = A//AI is the master.
use_power = 2//Active power usage.
return 1
@@ -83,6 +83,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/hologram/holopad/proc/clear_holo()
hologram.sd_SetLuminosity(0)//Clear lighting.
del(hologram)//Get rid of hologram.
if(master.current == src)
master.current = null
master = null//Null the master, since no-one is using it now.
sd_SetLuminosity(0)//Clear lighting for the parent.
icon_state = "holopad0"
@@ -91,8 +93,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/hologram/holopad/process()
if(hologram)//If there is a hologram.
if(master&&!master.stat&&master.client&&master.client.eye==src)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
if( !(get_dist(src,hologram.loc)>3||stat & NOPOWER) )//If the hologram is not out of bounds and the machine has power.
if(master && !master.stat && master.client && master.eyeobj.loc == src.loc)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
if(!(stat & NOPOWER))//If the machine has power.
return 1
clear_holo()//If not, we want to get rid of the hologram.
return 1
+7 -1
View File
@@ -184,7 +184,13 @@ Class Procs:
return 0
/obj/machinery/attack_ai(mob/user as mob)
return src.attack_hand(user)
if(isrobot(user))
// For some reason attack_robot doesn't work
// This is to stop robots from using cameras to remotely control machines.
if(user.client && user.client.eye == user)
return src.attack_hand(user)
else
return src.attack_hand(user)
/obj/machinery/attack_paw(mob/user as mob)
return src.attack_hand(user)
+1881
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
/mob/living/silicon/ai/proc/ai_statuschange()
set category = "AI Commands"
set name = "AI Status"
if(usr.stat == 2)
usr <<"You cannot change your emotional status because you are dead!"
return
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer")
var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
for (var/obj/machinery/ai_status_display/AISD in world) //change status
spawn( 0 )
AISD.emotion = emote
for (var/obj/machinery/status_display/SD in world) //if Friend Computer, change ALL displays
if(emote=="Friend Computer")
spawn(0)
SD.friendc = 1
else
spawn(0)
SD.friendc = 0
return