mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-04 22:52:03 +00:00
pAI gets a better PDA that can actually receive messages from people. They can also instantly reply like everybody else now. Got rid of old pAI messaging code. pAI can toggle their receiver/signaller and their ringer. AI Stuff You can show the AI the notes on your PDA by holding it up to a camera. When you show up a paper/pda to the camera the AI can now click on your name to go to you, if you're near a camera. The AI's "track with camera" list was adjusted so that it is sorted by humans and then by other mobs. In short, the huge list of monkeys will be below the human master race. Made the AI's PDA name look nicer. When showing a piece of paper/your pda to a camera... people who are Unknown will not have a link; which would allow the AI to track them. Radio/Telecomms Stuff Made the" common server" and the "preset right receiver" listen for frequencies 144.1 to 148.9. This will allow people to use different frequencies to talk to eachother without bothering the common channel. It will also allow Revs and Cultists to work with each other; everything is still logged though so it still has risks. Increased the maximum frequency limit for handheld radios and intercoms. It will give you the option to just use station bounced radios on a higher frequency so that anyone with a headset can't simply tune in. All-In-One Grinder Created an All-In-One Grinder that is suppose to replace the blender, juicer and reagent grinder altogether. Meaning any department that has a juicer, blender and grinder will instead get this. It will help people be more independent from Chemistry by recycling food and plants. The All-In-One grinder can grind and juice. Grinding food that isn't part of a recipe will transfer the reagents of the food into the beaker. Juicing only works with certain foods. I've updated the UI a bit, it will now tell you what's in the beaker and I made it look nicer. Map I removed all blenders and juicers on the station and replaced them with the All-In-One grinder! Misc. Added myself to the admin.txt list. git-svn-id: http://tgstation13.googlecode.com/svn/trunk@4053 316c924e-a436-60f5-8080-3fe189b3f50e
396 lines
12 KiB
Plaintext
396 lines
12 KiB
Plaintext
|
|
// 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"
|
|
|
|
if(usr.stat == 2)
|
|
usr << "You can't track with camera because you are dead!"
|
|
return
|
|
|
|
attack_ai(src)
|
|
|
|
/mob/living/silicon/ai/proc/ai_camera_track()
|
|
set category = "AI Commands"
|
|
set name = "Track With Camera"
|
|
if(usr.stat == 2)
|
|
usr << "You can't track with camera because you are dead!"
|
|
return
|
|
|
|
var/list/names = list()
|
|
var/list/namecounts = list()
|
|
var/list/humans = list()
|
|
var/list/others = list()
|
|
for(var/mob/living/M in world)
|
|
//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
|
|
continue
|
|
if(M == usr)
|
|
continue
|
|
if(M.digitalcamo)
|
|
continue
|
|
if(M.loc.z == 2) // Don't detect mobs on Centcom
|
|
continue
|
|
|
|
var/name = M.name
|
|
if (name in names)
|
|
namecounts[name]++
|
|
name = text("[] ([])", name, namecounts[name])
|
|
else
|
|
names.Add(name)
|
|
namecounts[name] = 1
|
|
if(human)
|
|
humans[name] = M
|
|
else
|
|
others[name] = M
|
|
|
|
var/list/targets = sortList(humans) + sortList(others)
|
|
var/target_name = input(usr, "Which creature should you track?") as null|anything in targets
|
|
|
|
if (!target_name)
|
|
usr:cameraFollow = null
|
|
return
|
|
|
|
var/mob/target = (isnull(humans[target_name]) ? others[target_name] : humans[target_name])
|
|
ai_actual_track(target)
|
|
|
|
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target as mob)
|
|
if(!istype(target)) return
|
|
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
|
|
|
|
spawn (0)
|
|
while (U.cameraFollow == target)
|
|
if (U.cameraFollow == null)
|
|
return
|
|
else if (istype(target, /mob/living/carbon/human))
|
|
if(istype(target:wear_id, /obj/item/weapon/card/id/syndicate))
|
|
U << "Follow camera mode terminated."
|
|
U.cameraFollow = null
|
|
return
|
|
if(istype(target:head, /obj/item/clothing/head/helmet/space/space_ninja)&&!target:head:canremove)
|
|
U << "Follow camera mode terminated."
|
|
U.cameraFollow = null
|
|
return
|
|
if(target.digitalcamo)
|
|
U << "Follow camera mode terminated."
|
|
U.cameraFollow = null
|
|
return
|
|
|
|
else if(istype(target.loc,/obj/effect/dummy))
|
|
U << "Follow camera mode ended."
|
|
U.cameraFollow = null
|
|
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)
|
|
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.current = C
|
|
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 world)
|
|
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.current = closest
|
|
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
|
|
|
|
sleep(10)
|
|
|
|
/proc/camera_sort(list/L)
|
|
var/obj/machinery/camera/a
|
|
var/obj/machinery/camera/b
|
|
|
|
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
|
|
|
|
|
|
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
|
|
if (user != src)
|
|
return
|
|
|
|
if (stat == 2)
|
|
return
|
|
|
|
user.machine = src
|
|
|
|
var/list/L = list()
|
|
for (var/obj/machinery/camera/C in world)
|
|
L.Add(C)
|
|
|
|
camera_sort(L)
|
|
|
|
var/list/D = 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
|
|
|
|
var/t = input(user, "Which camera should you change to?") as null|anything in D
|
|
|
|
if (!t || t == "Cancel")
|
|
switchCamera(null)
|
|
return 0
|
|
|
|
var/obj/machinery/camera/C = D[t]
|
|
|
|
switchCamera(C)
|
|
|
|
return
|
|
|
|
/obj/machinery/camera/emp_act(severity)
|
|
if(prob(100/(hardened + severity)))
|
|
icon_state = "cameraemp"
|
|
network = null //Not the best way but it will do. I think.
|
|
spawn(900)
|
|
network = initial(network)
|
|
icon_state = initial(icon_state)
|
|
for(var/mob/living/silicon/ai/O in world)
|
|
if (O.current == src)
|
|
O.cancel_camera()
|
|
O << "Your connection to the camera has been lost."
|
|
for(var/mob/O in world)
|
|
if (istype(O.machine, /obj/machinery/computer/security))
|
|
var/obj/machinery/computer/security/S = O.machine
|
|
if (S.current == src)
|
|
O.machine = null
|
|
S.current = null
|
|
O.reset_view(null)
|
|
O << "The screen bursts into static."
|
|
..()
|
|
|
|
/obj/machinery/camera/emp_proof/emp_act(severity)
|
|
return
|
|
|
|
/obj/machinery/camera/ex_act(severity)
|
|
if(src.invuln)
|
|
return
|
|
else
|
|
..(severity)
|
|
return
|
|
|
|
/obj/machinery/camera/blob_act()
|
|
return
|
|
|
|
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
|
|
if (!istype(user))
|
|
return
|
|
if (src.network != user.network || !(src.status))
|
|
return
|
|
user.current = src
|
|
user.reset_view(src)
|
|
|
|
/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob)
|
|
if(!istype(user))
|
|
return
|
|
status = 0
|
|
for(var/mob/O in viewers(user, null))
|
|
O.show_message("<span class='warning'>\The [user] slashes at [src]!</span>", 1)
|
|
playsound(src.loc, 'slash.ogg', 100, 1)
|
|
icon_state = "camera1"
|
|
add_hiddenprint(user)
|
|
deactivate(user,0)
|
|
|
|
/obj/machinery/camera/attackby(W as obj, user as mob)
|
|
if (istype(W, /obj/item/weapon/wirecutters))
|
|
deactivate(user)
|
|
else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
|
|
var/mob/living/U = user
|
|
var/obj/item/weapon/paper/X = null
|
|
var/obj/item/device/pda/P = null
|
|
|
|
var/itemname = ""
|
|
var/info = ""
|
|
if(istype(W, /obj/item/weapon/paper))
|
|
X = W
|
|
itemname = X.name
|
|
info = X.info
|
|
else
|
|
P = W
|
|
itemname = P.name
|
|
info = P.note
|
|
U << "You hold \a [itemname] up to the camera ..."
|
|
for(var/mob/living/silicon/ai/O in world)
|
|
//if (O.current == src)
|
|
if(U.name == "Unknown") O << "<b>[U]</b> holds \a [itemname] up to one of your cameras ..."
|
|
else O << "<b><a href='byond://?src=\ref[O];track2=\ref[O];track=\ref[U]'>[U]</a></b> holds \a [itemname] up to one of your cameras ..."
|
|
O << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", itemname, info), text("window=[]", itemname))
|
|
for(var/mob/O in world)
|
|
if (istype(O.machine, /obj/machinery/computer/security))
|
|
var/obj/machinery/computer/security/S = O.machine
|
|
if (S.current == 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/weapon/wrench)) //Adding dismantlable cameras to go with the constructable ones. --NEO
|
|
if(src.status)
|
|
user << "\red You can't dismantle a camera while it is active."
|
|
else
|
|
user << "\blue Dismantling camera..."
|
|
if(do_after(user, 20))
|
|
var/obj/item/weapon/grenade/chem_grenade/case = new /obj/item/weapon/grenade/chem_grenade(src.loc)
|
|
case.name = "Camera Assembly"
|
|
case.icon = 'monitors.dmi'
|
|
//JESUS WHAT THE FUCK EVERYTHING TO DO WITH CAMERAS IS TERRIBLE FUCK
|
|
case.icon_state = "cameracase"
|
|
case.path = 2
|
|
case.state = 5
|
|
case.circuit = new /obj/item/device/multitool
|
|
if (istype(src, /obj/machinery/camera/motion))
|
|
case.motion = 1
|
|
del(src)
|
|
else if (istype(W, /obj/item/weapon/camera_bug))
|
|
if (!src.status)
|
|
user << "\blue Camera non-functional"
|
|
return
|
|
if (src.bugged)
|
|
user << "\blue Camera bug removed."
|
|
src.bugged = 0
|
|
else
|
|
user << "\blue Camera bugged."
|
|
src.bugged = 1
|
|
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.
|
|
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
|
|
spark_system.set_up(5, 0, loc)
|
|
spark_system.start()
|
|
playsound(loc, 'blade1.ogg', 50, 1)
|
|
playsound(loc, "sparks", 50, 1)
|
|
|
|
var/obj/item/weapon/grenade/chem_grenade/case = new /obj/item/weapon/grenade/chem_grenade(loc)
|
|
case.name = "Camera Assembly"
|
|
case.icon = 'monitors.dmi'
|
|
case.icon_state = "cameracase"
|
|
case.path = 2
|
|
case.state = 5
|
|
case.circuit = new /obj/item/device/multitool
|
|
if (istype(src, /obj/machinery/camera/motion))
|
|
case.motion = 1
|
|
|
|
for(var/mob/O in viewers(user, 3))
|
|
O.show_message(text("\blue The camera has been sliced apart by [] with an energy blade!", user), 1, text("\red You hear metal being sliced and sparks flying."), 2)
|
|
del(src)
|
|
else
|
|
..()
|
|
return
|
|
|
|
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
|
|
if(choice==1)
|
|
status = !( src.status )
|
|
if (!(src.status))
|
|
for(var/mob/O in viewers(user, null))
|
|
O.show_message(text("\red [] has deactivated []!", user, src), 1)
|
|
playsound(src.loc, 'Wirecutter.ogg', 100, 1)
|
|
icon_state = "camera1"
|
|
add_hiddenprint(user)
|
|
else
|
|
for(var/mob/O in viewers(user, null))
|
|
O.show_message(text("\red [] has reactivated []!", user, src), 1)
|
|
playsound(src.loc, 'Wirecutter.ogg', 100, 1)
|
|
icon_state = "camera"
|
|
add_hiddenprint(user)
|
|
// 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 world)
|
|
if (O.current == src)
|
|
O.cancel_camera()
|
|
O << "Your connection to the camera has been lost."
|
|
for(var/mob/O in world)
|
|
if (istype(O.machine, /obj/machinery/computer/security))
|
|
var/obj/machinery/computer/security/S = O.machine
|
|
if (S.current == src)
|
|
O.machine = null
|
|
S.current = null
|
|
O.reset_view(null)
|
|
O << "The screen bursts into static."
|
|
|
|
//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(M))
|
|
if(C.status) // check if camera disabled
|
|
return C
|
|
break
|
|
|
|
return null
|