mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 13:37:58 +01:00
Camera code update, fix runtime
This commit is contained in:
+187
-1
@@ -396,4 +396,190 @@ proc/listclearnulls(list/list)
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
return R
|
||||
|
||||
|
||||
/proc/dd_sortedObjectList(var/list/L, var/cache=list())
|
||||
if(L.len < 2)
|
||||
return L
|
||||
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
||||
return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list
|
||||
|
||||
/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache)
|
||||
var/Li=1
|
||||
var/Ri=1
|
||||
var/list/result = new()
|
||||
while(Li <= L.len && Ri <= R.len)
|
||||
var/LLi = L[Li]
|
||||
var/RRi = R[Ri]
|
||||
var/LLiV = cache[LLi]
|
||||
var/RRiV = cache[RRi]
|
||||
if(!LLiV)
|
||||
LLiV = LLi:dd_SortValue()
|
||||
cache[LLi] = LLiV
|
||||
if(!RRiV)
|
||||
RRiV = RRi:dd_SortValue()
|
||||
cache[RRi] = RRiV
|
||||
if(LLiV < RRiV)
|
||||
result += L[Li++]
|
||||
else
|
||||
result += R[Ri++]
|
||||
|
||||
if(Li <= L.len)
|
||||
return (result + L.Copy(Li, 0))
|
||||
return (result + R.Copy(Ri, 0))
|
||||
|
||||
// Insert an object into a sorted list, preserving sortedness
|
||||
/proc/dd_insertObjectList(var/list/L, var/O)
|
||||
var/min = 1
|
||||
var/max = L.len
|
||||
var/Oval = O:dd_SortValue()
|
||||
|
||||
while(1)
|
||||
var/mid = min+round((max-min)/2)
|
||||
|
||||
if(mid == max)
|
||||
L.Insert(mid, O)
|
||||
return
|
||||
|
||||
var/Lmid = L[mid]
|
||||
var/midval = Lmid:dd_SortValue()
|
||||
if(Oval == midval)
|
||||
L.Insert(mid, O)
|
||||
return
|
||||
else if(Oval < midval)
|
||||
max = mid
|
||||
else
|
||||
min = mid+1
|
||||
|
||||
/*
|
||||
proc/dd_sortedObjectList(list/incoming)
|
||||
/*
|
||||
Use binary search to order by dd_SortValue().
|
||||
This works by going to the half-point of the list, seeing if the node in
|
||||
question is higher or lower cost, then going halfway up or down the list
|
||||
and checking again. This is a very fast way to sort an item into a list.
|
||||
*/
|
||||
var/list/sorted_list = new()
|
||||
var/low_index
|
||||
var/high_index
|
||||
var/insert_index
|
||||
var/midway_calc
|
||||
var/current_index
|
||||
var/current_item
|
||||
var/current_item_value
|
||||
var/current_sort_object_value
|
||||
var/list/list_bottom
|
||||
|
||||
var/current_sort_object
|
||||
for (current_sort_object in incoming)
|
||||
low_index = 1
|
||||
high_index = sorted_list.len
|
||||
while (low_index <= high_index)
|
||||
// Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
|
||||
midway_calc = (low_index + high_index) / 2
|
||||
current_index = round(midway_calc)
|
||||
if (midway_calc > current_index)
|
||||
current_index++
|
||||
current_item = sorted_list[current_index]
|
||||
|
||||
current_item_value = current_item:dd_SortValue()
|
||||
current_sort_object_value = current_sort_object:dd_SortValue()
|
||||
if (current_sort_object_value < current_item_value)
|
||||
high_index = current_index - 1
|
||||
else if (current_sort_object_value > current_item_value)
|
||||
low_index = current_index + 1
|
||||
else
|
||||
// current_sort_object == current_item
|
||||
low_index = current_index
|
||||
break
|
||||
|
||||
// Insert before low_index.
|
||||
insert_index = low_index
|
||||
|
||||
// Special case adding to end of list.
|
||||
if (insert_index > sorted_list.len)
|
||||
sorted_list += current_sort_object
|
||||
continue
|
||||
|
||||
// Because BYOND lists don't support insert, have to do it by:
|
||||
// 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
|
||||
list_bottom = sorted_list.Copy(insert_index)
|
||||
sorted_list.Cut(insert_index)
|
||||
sorted_list += current_sort_object
|
||||
sorted_list += list_bottom
|
||||
return sorted_list
|
||||
*/
|
||||
|
||||
proc/dd_sortedtextlist(list/incoming, case_sensitive = 0)
|
||||
// Returns a new list with the text values sorted.
|
||||
// Use binary search to order by sortValue.
|
||||
// This works by going to the half-point of the list, seeing if the node in question is higher or lower cost,
|
||||
// then going halfway up or down the list and checking again.
|
||||
// This is a very fast way to sort an item into a list.
|
||||
var/list/sorted_text = new()
|
||||
var/low_index
|
||||
var/high_index
|
||||
var/insert_index
|
||||
var/midway_calc
|
||||
var/current_index
|
||||
var/current_item
|
||||
var/list/list_bottom
|
||||
var/sort_result
|
||||
|
||||
var/current_sort_text
|
||||
for (current_sort_text in incoming)
|
||||
low_index = 1
|
||||
high_index = sorted_text.len
|
||||
while (low_index <= high_index)
|
||||
// Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
|
||||
midway_calc = (low_index + high_index) / 2
|
||||
current_index = round(midway_calc)
|
||||
if (midway_calc > current_index)
|
||||
current_index++
|
||||
current_item = sorted_text[current_index]
|
||||
|
||||
if (case_sensitive)
|
||||
sort_result = sorttextEx(current_sort_text, current_item)
|
||||
else
|
||||
sort_result = sorttext(current_sort_text, current_item)
|
||||
|
||||
switch(sort_result)
|
||||
if (1)
|
||||
high_index = current_index - 1 // current_sort_text < current_item
|
||||
if (-1)
|
||||
low_index = current_index + 1 // current_sort_text > current_item
|
||||
if (0)
|
||||
low_index = current_index // current_sort_text == current_item
|
||||
break
|
||||
|
||||
// Insert before low_index.
|
||||
insert_index = low_index
|
||||
|
||||
// Special case adding to end of list.
|
||||
if (insert_index > sorted_text.len)
|
||||
sorted_text += current_sort_text
|
||||
continue
|
||||
|
||||
// Because BYOND lists don't support insert, have to do it by:
|
||||
// 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
|
||||
list_bottom = sorted_text.Copy(insert_index)
|
||||
sorted_text.Cut(insert_index)
|
||||
sorted_text += current_sort_text
|
||||
sorted_text += list_bottom
|
||||
return sorted_text
|
||||
|
||||
|
||||
proc/dd_sortedTextList(list/incoming)
|
||||
var/case_sensitive = 1
|
||||
return dd_sortedtextlist(incoming, case_sensitive)
|
||||
|
||||
|
||||
datum/proc/dd_SortValue()
|
||||
return "[src]"
|
||||
|
||||
/obj/machinery/dd_SortValue()
|
||||
return "[sanitize(name)]"
|
||||
|
||||
/obj/machinery/camera/dd_SortValue()
|
||||
return "[c_tag]"
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/visibility_network
|
||||
var/list/viewpoints = list()
|
||||
|
||||
var/cameras_unsorted = 1
|
||||
// the type of chunk used by this network
|
||||
var/datum/visibility_chunk/ChunkType = /datum/visibility_chunk
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
var/list/chunks = list()
|
||||
|
||||
var/ready = 0
|
||||
|
||||
|
||||
/datum/visibility_network/proc/process_sort()
|
||||
if(cameras_unsorted)
|
||||
viewpoints = dd_sortedObjectList(viewpoints)
|
||||
cameras_unsorted = 0
|
||||
|
||||
|
||||
// Creates a chunk key string from x,y,z coordinates
|
||||
|
||||
@@ -8,17 +8,20 @@
|
||||
active_power_usage = 10
|
||||
layer = 5
|
||||
|
||||
var/datum/wires/camera/wires = null // Wires datum
|
||||
var/list/network = list("SS13")
|
||||
var/c_tag = null
|
||||
var/c_tag_order = 999
|
||||
var/status = 1.0
|
||||
var/status = 1
|
||||
anchored = 1.0
|
||||
var/invuln = null
|
||||
panel_open = 0 // 0 = Closed / 1 = Open
|
||||
var/indestructible = 0
|
||||
var/bugged = 0
|
||||
var/obj/item/weapon/camera_assembly/assembly = null
|
||||
var/watcherslist = list()
|
||||
var/obj/item/device/camera_bug/hasbug = null
|
||||
|
||||
var/toughness = 5 //sorta fragile
|
||||
|
||||
// WIRES
|
||||
var/datum/wires/camera/wires = null // Wires datum
|
||||
|
||||
//OTHER
|
||||
|
||||
@@ -28,15 +31,18 @@
|
||||
var/light_disabled = 0
|
||||
var/alarm_on = 0
|
||||
var/busy = 0
|
||||
var/indestructible = 0 // If set, prevents aliens from destroying it
|
||||
|
||||
var/obj/item/device/camera_bug/hasbug = null
|
||||
|
||||
/obj/machinery/camera/New()
|
||||
wires = new(src)
|
||||
|
||||
assembly = new(src)
|
||||
assembly.state = 4
|
||||
|
||||
invalidateCameraCache()
|
||||
|
||||
/* // Use this to look for cameras that have the same c_tag.
|
||||
for(var/obj/machinery/camera/C in cameranet.viewpoints)
|
||||
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)
|
||||
world.log << "[src.c_tag] [src.x] [src.y] [src.z] conflicts with [C.c_tag] [C.x] [C.y] [C.z]"
|
||||
@@ -50,51 +56,48 @@
|
||||
ASSERT(src.network.len > 0)
|
||||
..()
|
||||
|
||||
/obj/machinery/camera/Del()
|
||||
if(!alarm_on)
|
||||
triggerCameraAlarm()
|
||||
|
||||
cancelCameraAlarm()
|
||||
..()
|
||||
|
||||
/obj/machinery/camera/emp_act(severity)
|
||||
if(!isEmpProof())
|
||||
if(prob(100/severity))
|
||||
icon_state = "[initial(icon_state)]emp"
|
||||
var/list/previous_network = network
|
||||
network = list()
|
||||
cameranet.removeCamera(src)
|
||||
invalidateCameraCache()
|
||||
stat |= EMPED
|
||||
SetLuminosity(0)
|
||||
kick_viewers()
|
||||
triggerCameraAlarm()
|
||||
update_icon()
|
||||
|
||||
spawn(900)
|
||||
network = previous_network
|
||||
icon_state = initial(icon_state)
|
||||
stat &= ~EMPED
|
||||
cancelCameraAlarm()
|
||||
if(can_use())
|
||||
cameranet.addCamera(src)
|
||||
for(var/mob/O in mob_list)
|
||||
if(O.client && O.client.eye == src)
|
||||
O.unset_machine()
|
||||
O.reset_view(null)
|
||||
O << "The screen bursts into static."
|
||||
update_icon()
|
||||
invalidateCameraCache()
|
||||
..()
|
||||
|
||||
/obj/machinery/camera/bullet_act(var/obj/item/projectile/P)
|
||||
if(P.damage_type == BRUTE || P.damage_type == BURN)
|
||||
take_damage(P.damage)
|
||||
|
||||
/obj/machinery/camera/ex_act(severity)
|
||||
if(src.invuln)
|
||||
if(indestructible)
|
||||
return
|
||||
else
|
||||
..(severity)
|
||||
return
|
||||
|
||||
//camera dies if an explosion touches it!
|
||||
if(severity <= 2 || prob(50))
|
||||
destroy()
|
||||
|
||||
..() //and give it the regular chance of being deleted outright
|
||||
|
||||
|
||||
/obj/machinery/camera/blob_act()
|
||||
del(src)
|
||||
return
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(var/num = 7)
|
||||
src.view_range = num
|
||||
cameranet.updateVisibility(src, 0)
|
||||
|
||||
/obj/machinery/camera/proc/shock(var/mob/living/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
user.electrocute_act(10, src)
|
||||
|
||||
|
||||
/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob)
|
||||
if(!istype(user))
|
||||
return
|
||||
@@ -107,10 +110,22 @@
|
||||
add_hiddenprint(user)
|
||||
deactivate(user,0)
|
||||
|
||||
/obj/machinery/camera/attackby(W as obj, mob/living/user as mob)
|
||||
/obj/machinery/camera/hitby(AM as mob|obj)
|
||||
..()
|
||||
if (istype(AM, /obj))
|
||||
var/obj/O = AM
|
||||
if (O.throwforce >= src.toughness)
|
||||
visible_message("<span class='warning'><B>[src] was hit by [O].</B></span>")
|
||||
take_damage(O.throwforce)
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(var/num = 7)
|
||||
src.view_range = num
|
||||
cameranet.updateVisibility(src, 0)
|
||||
|
||||
/obj/machinery/camera/attackby(obj/W as obj, mob/living/user as mob)
|
||||
invalidateCameraCache()
|
||||
// DECONSTRUCTION
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(isscrewdriver(W))
|
||||
//user << "<span class='notice'>You start to [panel_open ? "close" : "open"] the camera's panel.</span>"
|
||||
//if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown
|
||||
panel_open = !panel_open
|
||||
@@ -118,19 +133,21 @@
|
||||
"<span class='notice'>You screw the camera's panel [panel_open ? "open" : "closed"].</span>")
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
|
||||
else if((istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) && panel_open)
|
||||
wires.Interact(user)
|
||||
else if((iswirecutter(W) || ismultitool(W)) && panel_open)
|
||||
interact(user)
|
||||
|
||||
else if(istype(W, /obj/item/weapon/weldingtool) && wires.CanDeconstruct())
|
||||
else if(iswelder(W) && (wires.CanDeconstruct() || (stat & BROKEN)))
|
||||
if(weld(W, user))
|
||||
if(assembly)
|
||||
if (stat & BROKEN)
|
||||
new /obj/item/stack/cable_coil(src.loc, length=2)
|
||||
else if(assembly)
|
||||
assembly.loc = src.loc
|
||||
assembly.state = 1
|
||||
new /obj/item/stack/cable_coil(src.loc, length=2)
|
||||
del(src)
|
||||
|
||||
|
||||
// OTHER
|
||||
else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
|
||||
else if (can_use() && (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
|
||||
@@ -152,11 +169,12 @@
|
||||
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 player_list)
|
||||
if(O.client && O.client.eye == src)
|
||||
O.unset_machine()
|
||||
O.reset_view(null)
|
||||
O << "[U] holds \a [itemname] up to the camera..."
|
||||
O << browse("<HTML><HEAD><TITLE>[itemname]</TITLE></HEAD><BODY><TT>[info]</TT></BODY></HTML>","window=[itemname]")
|
||||
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/device/camera_bug) && panel_open)
|
||||
if (!src.can_use())
|
||||
user << "\blue Camera non-functional"
|
||||
@@ -165,32 +183,24 @@
|
||||
user << "\blue Camera bugged."
|
||||
user.drop_item(W)
|
||||
hasbug = W
|
||||
contents += W
|
||||
if(prob(15))
|
||||
spawn(30)
|
||||
if(src.can_use() && hasbug)
|
||||
desc += "<br>The power light on the camera is blinking"
|
||||
triggerCameraAlarm()
|
||||
src.bugged = 1
|
||||
else if (iscrowbar(W) && panel_open && src.hasbug)
|
||||
user << "\blue You retrieve \the [hasbug]"
|
||||
user.put_in_hands(hasbug)
|
||||
hasbug = null
|
||||
deactivatebug(user)
|
||||
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, 'sound/weapons/blade1.ogg', 50, 1)
|
||||
playsound(loc, "sparks", 50, 1)
|
||||
visible_message("\blue The camera has been sliced apart by [] with an energy blade!")
|
||||
del(src)
|
||||
else if(istype(W, /obj/item/device/laser_pointer))
|
||||
var/obj/item/device/laser_pointer/L = W
|
||||
L.laser_act(src, user)
|
||||
deactivatebug(user)
|
||||
else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras
|
||||
if (W.force >= src.toughness)
|
||||
visible_message("<span class='warning'><b>[src] has been [pick(W.attack_verb)] with [W] by [user]!</b></span>")
|
||||
if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items?
|
||||
var/obj/item/I = W
|
||||
if (I.hitsound)
|
||||
playsound(loc, I.hitsound, 50, 1, -1)
|
||||
take_damage(W.force)
|
||||
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/machinery/camera/proc/deactivatebug(user as mob)
|
||||
for(var/mob/O in player_list)
|
||||
if(istype(O.machine, /obj/item/device/handtv))
|
||||
@@ -201,50 +211,91 @@
|
||||
O << "The screen bursts into static."
|
||||
|
||||
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
|
||||
if(choice==1)
|
||||
status = !( src.status )
|
||||
if(choice != 1)
|
||||
//legacy support, if choice is != 1 then just kick viewers without changing status
|
||||
kick_viewers()
|
||||
else
|
||||
invalidateCameraCache()
|
||||
set_status( !src.status )
|
||||
if (!(src.status))
|
||||
if(user)
|
||||
visible_message("\red [user] has deactivated [src]!")
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
visible_message("\red \The [src] deactivates!")
|
||||
visible_message("\red [user] has deactivated [src]!")
|
||||
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
if(user)
|
||||
visible_message("\red [user] has reactivated [src]!")
|
||||
add_hiddenprint(user)
|
||||
else
|
||||
visible_message("\red \the [src] reactivates!")
|
||||
visible_message("\red [user] has reactivated [src]!")
|
||||
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
icon_state = initial(icon_state)
|
||||
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?
|
||||
|
||||
/obj/machinery/camera/proc/take_damage(var/force, var/message)
|
||||
//prob(25) gives an average of 3-4 hits
|
||||
if (force >= toughness && (force > toughness*4 || prob(25)))
|
||||
destroy()
|
||||
|
||||
//Used when someone breaks a camera
|
||||
/obj/machinery/camera/proc/destroy()
|
||||
invalidateCameraCache()
|
||||
stat |= BROKEN
|
||||
kick_viewers()
|
||||
triggerCameraAlarm()
|
||||
update_icon()
|
||||
|
||||
//sparks
|
||||
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, "sparks", 50, 1)
|
||||
|
||||
/obj/machinery/camera/proc/set_status(var/newstatus)
|
||||
if (status != newstatus)
|
||||
status = newstatus
|
||||
invalidateCameraCache()
|
||||
// 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 couldn't use it anyway?
|
||||
kick_viewers()
|
||||
|
||||
//This might be redundant, because of check_eye()
|
||||
/obj/machinery/camera/proc/kick_viewers()
|
||||
for(var/mob/O in player_list)
|
||||
if(O.client && O.client.eye == src)
|
||||
O.unset_machine()
|
||||
O.reset_view(null)
|
||||
O << "The screen bursts into static."
|
||||
if (istype(O.machine, /obj/machinery/computer/security))
|
||||
var/obj/machinery/computer/security/S = O.machine
|
||||
if (S.current == src)
|
||||
O.unset_machine()
|
||||
O.reset_view(null)
|
||||
O << "The screen bursts into static."
|
||||
|
||||
/obj/machinery/camera/update_icon()
|
||||
if (!status || (stat & BROKEN))
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
else if (stat & EMPED)
|
||||
icon_state = "[initial(icon_state)]emp"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/machinery/camera/proc/triggerCameraAlarm()
|
||||
alarm_on = 1
|
||||
if(!get_area(src))
|
||||
return
|
||||
|
||||
for(var/mob/living/silicon/S in mob_list)
|
||||
S.triggerAlarm("Camera", get_area(src), list(src), src)
|
||||
|
||||
|
||||
/obj/machinery/camera/proc/cancelCameraAlarm()
|
||||
alarm_on = 0
|
||||
if(!get_area(src))
|
||||
return
|
||||
|
||||
for(var/mob/living/silicon/S in mob_list)
|
||||
S.cancelAlarm("Camera", get_area(src), list(src), src)
|
||||
S.cancelAlarm("Camera", get_area(src), src)
|
||||
|
||||
//if false, then the camera is listed as DEACTIVATED and cannot be used
|
||||
/obj/machinery/camera/proc/can_use()
|
||||
if(!status)
|
||||
return 0
|
||||
if(stat & EMPED)
|
||||
if(stat & (EMPED|BROKEN))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -266,13 +317,13 @@
|
||||
//If someone knows a better way to do this, let me know. -Giacom
|
||||
switch(i)
|
||||
if(NORTH)
|
||||
src.dir = SOUTH
|
||||
dir = SOUTH
|
||||
if(SOUTH)
|
||||
src.dir = NORTH
|
||||
dir = NORTH
|
||||
if(WEST)
|
||||
src.dir = EAST
|
||||
dir = EAST
|
||||
if(EAST)
|
||||
src.dir = WEST
|
||||
dir = WEST
|
||||
break
|
||||
|
||||
//Return a working camera that can see a given mob
|
||||
@@ -312,3 +363,14 @@
|
||||
return 1
|
||||
busy = 0
|
||||
return 0
|
||||
|
||||
/obj/machinery/camera/interact(mob/living/user as mob)
|
||||
if(!panel_open || istype(user, /mob/living/silicon/ai))
|
||||
return
|
||||
|
||||
if(stat & BROKEN)
|
||||
user << "<span class='warning'>\The [src] is broken.</span>"
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
wires.Interact(user)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
/obj/item/weapon/camera_assembly
|
||||
name = "camera assembly"
|
||||
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
|
||||
desc = "A pre-fabricated security camera kit, ready to be assembled and mounted to a surface."
|
||||
icon = 'icons/obj/monitors.dmi'
|
||||
icon_state = "cameracase"
|
||||
w_class = 2
|
||||
anchored = 0
|
||||
|
||||
m_amt = 700
|
||||
g_amt = 300
|
||||
|
||||
// Motion, EMP-Proof, X-Ray
|
||||
var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/plasma, /obj/item/weapon/reagent_containers/food/snacks/grown/carrot)
|
||||
var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/osmium, /obj/item/weapon/stock_parts/scanning_module)
|
||||
var/list/upgrades = list()
|
||||
var/state = 0
|
||||
var/busy = 0
|
||||
@@ -59,8 +58,10 @@
|
||||
if(iscoil(W))
|
||||
var/obj/item/stack/cable_coil/C = W
|
||||
if(C.use(2))
|
||||
user << "You add wires to the assembly."
|
||||
user << "<span class='notice'>You add wires to the assembly.</span>"
|
||||
state = 3
|
||||
else
|
||||
user << "<span class='warning'>You need 2 coils of wire to wire the assembly.</span>"
|
||||
return
|
||||
|
||||
else if(iswelder(W))
|
||||
@@ -87,7 +88,8 @@
|
||||
usr << "No network found please hang up and try your call again."
|
||||
return
|
||||
|
||||
var/temptag = "[get_area(src)] ([rand(1, 999)])"
|
||||
var/area/camera_area = get_area(src)
|
||||
var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])"
|
||||
input = strip_html(input(usr, "How would you like to name the camera?", "Set Camera Name", temptag))
|
||||
|
||||
state = 4
|
||||
@@ -124,7 +126,7 @@
|
||||
|
||||
// Upgrades!
|
||||
if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already.
|
||||
user << "You attach the [W] into the assembly inner circuits."
|
||||
user << "You attach \the [W] into the assembly inner circuits."
|
||||
upgrades += W
|
||||
user.drop_item(W)
|
||||
W.loc = src
|
||||
@@ -169,4 +171,4 @@
|
||||
return 0
|
||||
return 1
|
||||
busy = 0
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
/obj/machinery/camera/process()
|
||||
// motion camera event loop
|
||||
if (stat & (EMPED|NOPOWER))
|
||||
return
|
||||
if(!isMotion())
|
||||
. = PROCESS_KILL
|
||||
return
|
||||
@@ -40,16 +42,20 @@
|
||||
cancelAlarm()
|
||||
|
||||
/obj/machinery/camera/proc/cancelAlarm()
|
||||
if (!status || (stat & NOPOWER))
|
||||
return 0
|
||||
if (detectTime == -1)
|
||||
for (var/mob/living/silicon/aiPlayer in player_list)
|
||||
if (status) aiPlayer.cancelAlarm("Motion", src.loc.loc)
|
||||
aiPlayer.cancelAlarm("Motion", get_area(src), src)
|
||||
detectTime = 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/camera/proc/triggerAlarm()
|
||||
if (!status || (stat & NOPOWER))
|
||||
return 0
|
||||
if (!detectTime) return 0
|
||||
for (var/mob/living/silicon/aiPlayer in player_list)
|
||||
if (status) aiPlayer.triggerAlarm("Motion", src.loc.loc, src)
|
||||
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
|
||||
detectTime = -1
|
||||
return 1
|
||||
|
||||
|
||||
@@ -53,12 +53,14 @@
|
||||
// CHECKS
|
||||
|
||||
/obj/machinery/camera/proc/isEmpProof()
|
||||
var/O = locate(/obj/item/stack/sheet/mineral/plasma) in assembly.upgrades
|
||||
var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades
|
||||
return O
|
||||
|
||||
/obj/machinery/camera/proc/isXRay()
|
||||
var/O = locate(/obj/item/weapon/reagent_containers/food/snacks/grown/carrot) in assembly.upgrades
|
||||
return O
|
||||
var/obj/item/weapon/stock_parts/scanning_module/O = locate(/obj/item/weapon/stock_parts/scanning_module) in assembly.upgrades
|
||||
if (O && O.rating >= 2)
|
||||
return O
|
||||
return null
|
||||
|
||||
/obj/machinery/camera/proc/isMotion()
|
||||
var/O = locate(/obj/item/device/assembly/prox_sensor) in assembly.upgrades
|
||||
@@ -67,11 +69,22 @@
|
||||
// UPGRADE PROCS
|
||||
|
||||
/obj/machinery/camera/proc/upgradeEmpProof()
|
||||
assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/plasma(assembly))
|
||||
assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/osmium(assembly))
|
||||
setPowerUsage()
|
||||
|
||||
/obj/machinery/camera/proc/upgradeXRay()
|
||||
assembly.upgrades.Add(new /obj/item/weapon/reagent_containers/food/snacks/grown/carrot(assembly))
|
||||
assembly.upgrades.Add(new /obj/item/weapon/stock_parts/scanning_module/adv(assembly))
|
||||
setPowerUsage()
|
||||
|
||||
// If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list.
|
||||
/obj/machinery/camera/proc/upgradeMotion()
|
||||
assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly))
|
||||
assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly))
|
||||
setPowerUsage()
|
||||
|
||||
/obj/machinery/camera/proc/setPowerUsage()
|
||||
var/mult = 1
|
||||
if (isXRay())
|
||||
mult++
|
||||
if (isMotion())
|
||||
mult++
|
||||
active_power_usage = mult*initial(active_power_usage)
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
/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 == 2)
|
||||
return 1
|
||||
if(T.z > 6)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/proc/get_camera_list()
|
||||
|
||||
if(src.stat == 2)
|
||||
return
|
||||
|
||||
var/list/L = list()
|
||||
for (var/obj/machinery/camera/C in cameranet.viewpoints)
|
||||
L.Add(C)
|
||||
|
||||
camera_sort(L)
|
||||
cameranet.process_sort()
|
||||
|
||||
var/list/T = list()
|
||||
T["Cancel"] = "Cancel"
|
||||
for (var/obj/machinery/camera/C in L)
|
||||
for (var/obj/machinery/camera/C in cameranet.viewpoints)
|
||||
var/list/tempnetwork = C.network&src.network
|
||||
if (tempnetwork.len)
|
||||
T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C
|
||||
@@ -19,20 +28,76 @@
|
||||
track.cameras = T
|
||||
return T
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_camera_list(var/camera in get_camera_list())
|
||||
set category = "AI Commands"
|
||||
set name = "Show Camera List"
|
||||
|
||||
if(src.stat == 2)
|
||||
src << "You can't list the cameras because you are dead!"
|
||||
return
|
||||
|
||||
if (!camera || camera == "Cancel")
|
||||
return 0
|
||||
|
||||
|
||||
var/obj/machinery/camera/C = track.cameras[camera]
|
||||
track = null
|
||||
src.eyeobj.setLoc(C)
|
||||
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_store_location(loc as text)
|
||||
set category = "AI Commands"
|
||||
set name = "Store Camera Location"
|
||||
set desc = "Stores your current camera location by the given name"
|
||||
|
||||
loc = sanitize(copytext(loc, 1, MAX_MESSAGE_LEN))
|
||||
if(!loc)
|
||||
src << "\red Must supply a location name"
|
||||
return
|
||||
|
||||
if(stored_locations.len >= max_locations)
|
||||
src << "\red Cannot store additional locations. Remove one first"
|
||||
return
|
||||
|
||||
if(loc in stored_locations)
|
||||
src << "\red There is already a stored location by this name"
|
||||
return
|
||||
|
||||
var/L = src.eyeobj.getLoc()
|
||||
if (InvalidTurf(get_turf(L)))
|
||||
src << "\red Unable to store this location"
|
||||
return
|
||||
|
||||
stored_locations[loc] = L
|
||||
src << "Location '[loc]' stored"
|
||||
|
||||
/mob/living/silicon/ai/proc/sorted_stored_locations()
|
||||
return sortList(stored_locations)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_goto_location(loc in sorted_stored_locations())
|
||||
set category = "AI Commands"
|
||||
set name = "Goto Camera Location"
|
||||
set desc = "Returns to the selected camera location"
|
||||
|
||||
if (!(loc in stored_locations))
|
||||
src << "\red Location [loc] not found"
|
||||
return
|
||||
|
||||
var/L = stored_locations[loc]
|
||||
src.eyeobj.setLoc(L)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_remove_location(loc in sorted_stored_locations())
|
||||
set category = "AI Commands"
|
||||
set name = "Delete Camera Location"
|
||||
set desc = "Deletes the selected camera location"
|
||||
|
||||
if (!(loc in stored_locations))
|
||||
src << "\red Location [loc] not found"
|
||||
return
|
||||
|
||||
stored_locations.Remove(loc)
|
||||
src << "Location [loc] removed"
|
||||
|
||||
// Used to allow the AI is write in mob names/camera name from the CMD line.
|
||||
/datum/trackable
|
||||
var/list/names = list()
|
||||
@@ -50,12 +115,7 @@
|
||||
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.
|
||||
var/turf/T = get_turf(M)
|
||||
if(!T)
|
||||
continue
|
||||
if(T.z == 2)
|
||||
continue
|
||||
if(T.z > 6)
|
||||
if(InvalidTurf(get_turf(M)))
|
||||
continue
|
||||
if(M == usr)
|
||||
continue
|
||||
@@ -72,10 +132,6 @@
|
||||
//Cameras can't track people wearing an agent card or a ninja hood.
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /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(!near_camera(M))
|
||||
@@ -98,6 +154,10 @@
|
||||
return targets
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_camera_track(var/target_name in trackable_mobs())
|
||||
set category = "AI Commands"
|
||||
set name = "Track With Camera"
|
||||
set desc = "Select who you would like to track."
|
||||
|
||||
if(src.stat == 2)
|
||||
src << "You can't track with camera because you are dead!"
|
||||
return
|
||||
@@ -108,61 +168,18 @@
|
||||
src.track = null
|
||||
ai_actual_track(target)
|
||||
|
||||
/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target as mob)
|
||||
if(!istype(target)) return
|
||||
spawn(0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(H.digitalcamo)
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if (!near_camera(target))
|
||||
src << "Target is not near any active cameras."
|
||||
return
|
||||
var/obj/machinery/door/airlock/tobeopened
|
||||
var/dist = -1
|
||||
for(var/obj/machinery/door/airlock/D in range(3,target))
|
||||
if(!D.density) continue
|
||||
if(dist < 0)
|
||||
dist = get_dist(D, target)
|
||||
//world << dist
|
||||
tobeopened = D
|
||||
else
|
||||
if(dist > get_dist(D, target))
|
||||
dist = get_dist(D, target)
|
||||
//world << dist
|
||||
tobeopened = D
|
||||
//world << "found [tobeopened.name] closer"
|
||||
else
|
||||
//world << "[D.name] not close enough | [get_dist(D, target)] | [dist]"
|
||||
if(tobeopened)
|
||||
switch(alert(src, "Do you want to open \the [tobeopened] for [target]?","Doorknob_v2a.exe","Yes","No"))
|
||||
if("Yes")
|
||||
var/nhref = "src=\ref[tobeopened];aiEnable=7"
|
||||
tobeopened.Topic(nhref, params2list(nhref), tobeopened, 1)
|
||||
src << "\blue You've opened \the [tobeopened] for [target]."
|
||||
if("No")
|
||||
src << "\red You deny the request."
|
||||
else
|
||||
src << "\red You've failed to open an airlock for [target]"
|
||||
/mob/living/silicon/ai/proc/ai_cancel_tracking(var/forced = 0)
|
||||
if(!cameraFollow)
|
||||
return
|
||||
/mob/living/silicon/ai/proc/ai_actual_track(atom/target as mob|obj)
|
||||
|
||||
src << "Follow camera mode [forced ? "terminated" : "ended"]."
|
||||
cameraFollow = null
|
||||
|
||||
/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
|
||||
U << "Now tracking [target.name] on camera."
|
||||
|
||||
spawn (0)
|
||||
@@ -172,30 +189,23 @@
|
||||
if (istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
|
||||
U << "Follow camera mode terminated."
|
||||
U.cameraFollow = null
|
||||
U.ai_cancel_tracking(1)
|
||||
return
|
||||
/* if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
|
||||
U << "Follow camera mode terminated."
|
||||
U.cameraFollow = null
|
||||
return*/
|
||||
if(H.digitalcamo)
|
||||
U << "Follow camera mode terminated."
|
||||
U.cameraFollow = null
|
||||
U.ai_cancel_tracking(1)
|
||||
return
|
||||
|
||||
if(istype(target.loc,/obj/effect/dummy))
|
||||
U << "Follow camera mode ended."
|
||||
U.cameraFollow = null
|
||||
U.ai_cancel_tracking()
|
||||
return
|
||||
|
||||
if (!near_camera(target))
|
||||
if (!trackable(target))
|
||||
U << "Target is not near any active cameras."
|
||||
sleep(100)
|
||||
continue
|
||||
|
||||
if(U.eyeobj)
|
||||
U.eyeobj.setLoc(get_turf(target))
|
||||
U.eyeobj.setLoc(get_turf(target), 0)
|
||||
else
|
||||
view_core()
|
||||
return
|
||||
@@ -212,6 +222,12 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/proc/trackable(var/mob/living/M)
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && (T.z == 1) && hassensorlevel(M, SUIT_SENSOR_TRACKING))
|
||||
return 1
|
||||
|
||||
return near_camera(M)
|
||||
|
||||
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
|
||||
if (!istype(user))
|
||||
@@ -223,19 +239,3 @@
|
||||
|
||||
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
|
||||
ai_camera_list()
|
||||
|
||||
/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
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/proc/invalidateCameraCache()
|
||||
for(var/obj/machinery/computer/security/s in world)
|
||||
s.camera_cache = null
|
||||
|
||||
/obj/machinery/computer/security
|
||||
name = "Camera Monitor"
|
||||
desc = "Used to access the various cameras networks on the station."
|
||||
@@ -12,6 +16,7 @@
|
||||
var/list/tempnets[0]
|
||||
var/list/data[0]
|
||||
var/list/access[0]
|
||||
var/camera_cache = null
|
||||
|
||||
New() // Lists existing networks and their required access. Format: networks[<name>] = list(<access>)
|
||||
networks["SS13"] = list(access_hos,access_captain)
|
||||
@@ -78,29 +83,38 @@
|
||||
|
||||
data["current"] = null
|
||||
|
||||
var/list/L = list()
|
||||
for (var/obj/machinery/camera/C in cameranet.viewpoints)
|
||||
if(can_access_camera(C))
|
||||
L.Add(C)
|
||||
if(isnull(camera_cache))
|
||||
cameranet.process_sort()
|
||||
|
||||
camera_sort(L)
|
||||
var/cameras[0]
|
||||
for(var/obj/machinery/camera/C in cameranet.viewpoints)
|
||||
var/cam[0]
|
||||
cam["name"] = C.c_tag
|
||||
cam["deact"] = !C.can_use()
|
||||
cam["camera"] = "\ref[C]"
|
||||
cam["x"] = C.x
|
||||
cam["y"] = C.y
|
||||
cam["z"] = C.z
|
||||
|
||||
var/cameras[0]
|
||||
for(var/obj/machinery/camera/C in L)
|
||||
var/cam[0]
|
||||
cam["name"] = C.c_tag
|
||||
cam["deact"] = !C.can_use()
|
||||
cam["camera"] = "\ref[C]"
|
||||
cam["x"] = C.x
|
||||
cam["y"] = C.y
|
||||
cam["z"] = C.z
|
||||
cameras[++cameras.len] = cam
|
||||
|
||||
cameras[++cameras.len] = cam
|
||||
if(C == current)
|
||||
data["current"] = cam
|
||||
|
||||
var/list/camera_list = list("cameras" = cameras)
|
||||
camera_cache=list2json(camera_list)
|
||||
|
||||
else
|
||||
if(current)
|
||||
var/cam[0]
|
||||
cam["name"] = current.c_tag
|
||||
cam["deact"] = !current.can_use()
|
||||
cam["camera"] = "\ref[current]"
|
||||
cam["x"] = current.x
|
||||
cam["y"] = current.y
|
||||
cam["z"] = current.z
|
||||
|
||||
if(C == current)
|
||||
data["current"] = cam
|
||||
|
||||
data["cameras"] = cameras
|
||||
|
||||
tempnets.Cut()
|
||||
if(emagged)
|
||||
@@ -119,6 +133,9 @@
|
||||
tempnets.Add(list(list("name" = l, "active" = 0)))
|
||||
break
|
||||
data["networks"] = tempnets
|
||||
|
||||
if(ui)
|
||||
ui.load_cached_data(camera_cache)
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
@@ -128,7 +145,8 @@
|
||||
ui.add_template("mapContent", "sec_camera_map_content.tmpl")
|
||||
// adding a template with the key "mapHeader" replaces the map header content
|
||||
ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
|
||||
|
||||
|
||||
ui.load_cached_data(camera_cache)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
if(temp.len)
|
||||
L.Add(C)
|
||||
|
||||
camera_sort(L)
|
||||
cameranet.process_sort()
|
||||
|
||||
return L
|
||||
verify_machine(var/obj/machinery/camera/C,var/datum/file/camnet_key/key = null)
|
||||
|
||||
@@ -112,7 +112,7 @@ var/list/ai_list = list()
|
||||
if (istype(loc, /turf))
|
||||
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
|
||||
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message)
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location)
|
||||
|
||||
if(!safety)//Only used by AIize() to successfully spawn an AI.
|
||||
if (!B)//If there is no player/brain inside.
|
||||
@@ -127,7 +127,7 @@ var/list/ai_list = list()
|
||||
verbs.Remove(,/mob/living/silicon/ai/proc/ai_call_shuttle,/mob/living/silicon/ai/proc/ai_camera_track, \
|
||||
/mob/living/silicon/ai/proc/ai_camera_list, /mob/living/silicon/ai/proc/ai_network_change, \
|
||||
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud)
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message)
|
||||
laws = new /datum/ai_laws/alienmov
|
||||
else
|
||||
B.brainmob.mind.transfer_to(src)
|
||||
@@ -631,8 +631,6 @@ var/list/ai_list = list()
|
||||
|
||||
/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)
|
||||
|
||||
src.cameraFollow = null
|
||||
|
||||
if (!C || stat == 2) //C.can_use())
|
||||
return 0
|
||||
|
||||
@@ -706,7 +704,6 @@ var/list/ai_list = list()
|
||||
set category = "AI Commands"
|
||||
set name = "Jump To Network"
|
||||
unset_machine()
|
||||
src.cameraFollow = null
|
||||
var/cameralist[0]
|
||||
|
||||
if(usr.stat == 2)
|
||||
@@ -912,3 +909,52 @@ var/list/ai_list = list()
|
||||
src << "Accessing Subspace Transceiver control..."
|
||||
if (src.aiRadio)
|
||||
src.aiRadio.interact(src)
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target as mob)
|
||||
if(!istype(target)) return
|
||||
spawn(0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(istype(H.head, /obj/item/clothing/head/helmet/space/space_ninja) && !H.head.canremove)
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if(H.digitalcamo)
|
||||
src << "Unable to locate an airlock"
|
||||
return
|
||||
if (!near_camera(target))
|
||||
src << "Target is not near any active cameras."
|
||||
return
|
||||
var/obj/machinery/door/airlock/tobeopened
|
||||
var/dist = -1
|
||||
for(var/obj/machinery/door/airlock/D in range(3,target))
|
||||
if(!D.density) continue
|
||||
if(dist < 0)
|
||||
dist = get_dist(D, target)
|
||||
//world << dist
|
||||
tobeopened = D
|
||||
else
|
||||
if(dist > get_dist(D, target))
|
||||
dist = get_dist(D, target)
|
||||
//world << dist
|
||||
tobeopened = D
|
||||
//world << "found [tobeopened.name] closer"
|
||||
else
|
||||
//world << "[D.name] not close enough | [get_dist(D, target)] | [dist]"
|
||||
if(tobeopened)
|
||||
switch(alert(src, "Do you want to open \the [tobeopened] for [target]?","Doorknob_v2a.exe","Yes","No"))
|
||||
if("Yes")
|
||||
var/nhref = "src=\ref[tobeopened];aiEnable=7"
|
||||
tobeopened.Topic(nhref, params2list(nhref), tobeopened, 1)
|
||||
src << "\blue You've opened \the [tobeopened] for [target]."
|
||||
if("No")
|
||||
src << "\red You deny the request."
|
||||
else
|
||||
src << "\red You've failed to open an airlock for [target]"
|
||||
return
|
||||
@@ -54,6 +54,14 @@
|
||||
//Holopad
|
||||
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/Move()
|
||||
|
||||
@@ -12,12 +12,19 @@
|
||||
|
||||
/obj/machinery/camera/New()
|
||||
..()
|
||||
cameranet.viewpoints += src //Camera must be added to global list of all cameras no matter what...
|
||||
//Camera must be added to global list of all cameras no matter what...
|
||||
if(cameranet.cameras_unsorted || !ticker)
|
||||
cameranet.viewpoints += src
|
||||
cameranet.cameras_unsorted = 1
|
||||
else
|
||||
dd_insertObjectList(cameranet.viewpoints, 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.addViewpoint(src)
|
||||
|
||||
/obj/machinery/camera/Del()
|
||||
|
||||
cameranet.viewpoints -= src
|
||||
var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS)
|
||||
if(open_networks.len)
|
||||
|
||||
@@ -161,6 +161,14 @@ proc/hasorgans(A)
|
||||
|
||||
/proc/hsl2rgb(h, s, l)
|
||||
return
|
||||
|
||||
proc/hassensorlevel(A, var/level)
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
return U.sensor_mode >= level
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
/proc/check_zone(zone)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
json_writer
|
||||
proc
|
||||
WriteObject(list/L)
|
||||
WriteObject(list/L, cached_data = null)
|
||||
. = "{"
|
||||
var/i = 1
|
||||
for(var/k in L)
|
||||
@@ -9,6 +9,8 @@ json_writer
|
||||
. += {"\"[k]\":[write(val)]"}
|
||||
if(i++ < L.len)
|
||||
. += ","
|
||||
if(cached_data)
|
||||
. = copytext(., 1, lentext(.)) + ",\"cached\":[cached_data]}"
|
||||
.+= "}"
|
||||
|
||||
write(val)
|
||||
|
||||
@@ -7,6 +7,6 @@ proc
|
||||
var/static/json_reader/_jsonr = new()
|
||||
return _jsonr.ReadObject(_jsonr.ScanJson(json))
|
||||
|
||||
list2json(list/L)
|
||||
list2json(list/L, var/cached_data = null)
|
||||
var/static/json_writer/_jsonw = new()
|
||||
return _jsonw.WriteObject(L)
|
||||
return _jsonw.WriteObject(L, cached_data)
|
||||
|
||||
@@ -58,6 +58,9 @@ nanoui is used to open and update nano browser uis
|
||||
var/is_auto_updating = 0
|
||||
// the current status/visibility of the ui
|
||||
var/status = STATUS_INTERACTIVE
|
||||
|
||||
var/cached_data = null
|
||||
|
||||
|
||||
// Only allow users with a certain user.stat to get updates. Defaults to 0 (concious)
|
||||
var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive
|
||||
@@ -370,7 +373,7 @@ nanoui is used to open and update nano browser uis
|
||||
template_data_json = list2json(templates)
|
||||
|
||||
var/list/send_data = get_send_data(initial_data)
|
||||
var/initial_data_json = list2json(send_data)
|
||||
var/initial_data_json = list2json(send_data, cached_data)
|
||||
|
||||
var/url_parameters_json = list2json(list("src" = "\ref[src]"))
|
||||
|
||||
@@ -450,6 +453,17 @@ nanoui is used to open and update nano browser uis
|
||||
var/params = "\ref[src]"
|
||||
|
||||
winset(user, window_id, "on-close=\"nanoclose [params]\"")
|
||||
|
||||
/**
|
||||
* Appends already processed json txt to the list2json proc when setting initial-data and data pushes
|
||||
* Used for data that is fucking huge like manifests and camera lists that doesn't change often.
|
||||
* And we only want to process them when they change.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/datum/nanoui/proc/load_cached_data(var/data)
|
||||
cached_data = data
|
||||
return
|
||||
|
||||
/**
|
||||
* Push data to an already open UI window
|
||||
@@ -464,7 +478,7 @@ nanoui is used to open and update nano browser uis
|
||||
var/list/send_data = get_send_data(data)
|
||||
|
||||
//user << list2json(data) // used for debugging
|
||||
user << output(list2params(list(list2json(send_data))),"[window_id].browser:receiveUpdateData")
|
||||
user << output(list2params(list(list2json(send_data,cached_data))),"[window_id].browser:receiveUpdateData")
|
||||
|
||||
/**
|
||||
* This Topic() proc is called whenever a user clicks on a link within a Nano UI
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
P.internal_organs = list()
|
||||
P.internal_organs += src
|
||||
H.internal_organs_by_name[name] = src
|
||||
H.internal_organs |= src
|
||||
owner = H
|
||||
return
|
||||
|
||||
@@ -196,7 +197,7 @@
|
||||
src.damage += 0.2 * process_accuracy
|
||||
//Damaged one shares the fun
|
||||
else
|
||||
var/datum/organ/internal/O = pick(owner.internal_organs_by_name)
|
||||
var/datum/organ/internal/O = pick(owner.internal_organs)
|
||||
if(O)
|
||||
O.damage += 0.2 * process_accuracy
|
||||
|
||||
|
||||
+9
-1
@@ -806,6 +806,8 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
|
||||
"ERT",
|
||||
"NukeOps",
|
||||
"Thunderdome",
|
||||
"UO45",
|
||||
"UO45R",
|
||||
"Xeno"
|
||||
)
|
||||
|
||||
@@ -943,4 +945,10 @@ var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
|
||||
#define AUTOLATHE 4 //Uses glass/metal only.
|
||||
#define CRAFTLATHE 8 //Uses fuck if I know. For use eventually.
|
||||
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
|
||||
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
|
||||
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
|
||||
|
||||
// Suit sensor levels
|
||||
#define SUIT_SENSOR_OFF 0
|
||||
#define SUIT_SENSOR_BINARY 1
|
||||
#define SUIT_SENSOR_VITAL 2
|
||||
#define SUIT_SENSOR_TRACKING 3
|
||||
@@ -12,7 +12,7 @@ Used In File(s): \code\game\machinery\computer\camera.dm
|
||||
<div class='itemContent'>None</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{for data.cameras}}
|
||||
{{for data.cached.cameras}}
|
||||
{{if data.current && value.name == data.current.name}}
|
||||
{{:helper.link(value.name, '', {'switchTo' : value.camera}, 'selected')}}
|
||||
{{else value.deact}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Title: Security Camera Console (Map content)
|
||||
Used In File(s): \code\game\machinery\computer\camera.dm
|
||||
-->
|
||||
{{for data.cameras}}
|
||||
{{for data.cached.cameras}}
|
||||
{{if value.z == 1}}
|
||||
<div class="mapIcon mapIcon16" style="left: {{:(value.x)}}px; bottom: {{:(value.y - 1)}}px;">
|
||||
{{if data.current && value.name == data.current.name}}
|
||||
|
||||
Reference in New Issue
Block a user