Merge with upstream/master

This commit is contained in:
DZD
2015-02-12 16:43:01 -05:00
98 changed files with 3191 additions and 2422 deletions
+10
View File
@@ -29,6 +29,16 @@ atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
return 0
return 1
//Convenience function for atoms to update turfs they occupy
/atom/movable/proc/update_nearby_tiles(need_rebuild)
if(!air_master)
return 0
for(var/turf/simulated/turf in locs)
air_master.mark_for_update(turf)
return 1
//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1).
//Returns:
+187 -1
View File
@@ -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 -1
View File
@@ -94,7 +94,7 @@ datum/light_source
if(owner.loc && owner.luminosity > 0)
readrgb(owner.l_color)
effect = list()
for(var/turf/T in view(owner.get_light_range(),owner))
for(var/turf/T in view(owner.get_light_range(),get_turf(owner)))
var/delta_lumen = lum(T)
if(delta_lumen > 0)
effect[T] = delta_lumen
+5
View File
@@ -179,6 +179,11 @@ datum/ai_laws/tyrant //This probably shouldn't be a default lawset.
/datum/ai_laws/proc/clear_ion_laws()
src.ion = list()
/datum/ai_laws/proc/clear_zeroth_law(var/law_borg = null)
src.zeroth = null
if(law_borg)
src.zeroth_borg = null
/datum/ai_laws/proc/show_laws(var/who)
+1209 -1204
View File
File diff suppressed because it is too large Load Diff
-179
View File
@@ -1,179 +0,0 @@
#define UPDATE_BUFFER 25 // 2.5 seconds
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the mob using this chunk to stream these chunks and know what it can and cannot see.
/datum/visibility_chunk
var/obscured_image = 'icons/effects/cameravis.dmi'
var/obscured_sub = "black"
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/viewpoints = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
/datum/visibility_chunk/proc/add(mob/new_mob)
// if this thing doesn't use one of these visibility systems, kick it out
if (!new_mob.visibility_interface)
return
// if the mob being added isn't a valid form of that mob, kick it out
if (!new_mob.visibility_interface:canBeAddedToChunk(src))
return
// add this chunk to the list of visible chunks
new_mob.visibility_interface:addChunk(src)
visible++
seenby += new_mob
if(changed && !updating)
update()
/datum/visibility_chunk/proc/remove(mob/new_mob)
// if this thing doesn't use one of these visibility systems, kick it out
if (!new_mob.visibility_interface)
return
// if the mob being added isn't a valid form of that mob, kick it out
if (!new_mob.visibility_interface:canBeAddedToChunk(src))
return
// remove the chunk
new_mob.visibility_interface:removeChunk(src)
// remove the mob from out lists
seenby -= new_mob
if(visible > 0)
visible--
/datum/visibility_chunk/proc/visibilityChanged(turf/loc)
if(!visibleTurfs[loc])
return
hasChanged()
/datum/visibility_chunk/proc/hasChanged(var/update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
/*
This function needs to be overwritten to return True if the viewpoint object is valid, and false if it is not.
*/
/datum/visibility_chunk/proc/validViewpoint(var/viewpoint)
return FALSE
/*
This function needs to be overwritten to return a list of visible turfs for that viewpoint
*/
/datum/visibility_chunk/proc/getVisibleTurfsForViewpoint(var/viewpoint)
return list()
// returns a list of turfs which can be seen in by the chunks viewpoints
/datum/visibility_chunk/proc/getVisibleTurfs()
var/list/newVisibleTurfs = list()
for(var/viewpoint in viewpoints)
if (validViewpoint(viewpoint))
for (var/turf/t in getVisibleTurfsForViewpoint(viewpoint))
newVisibleTurfs[t]=t
return newVisibleTurfs
/*
This function needs to be overwritten to find nearby viewpoint objects to the chunk center.
*/
/datum/visibility_chunk/proc/findNearbyViewpoints()
return FALSE
/*
This function can be overwritten to change or randomize the obscuring images
*/
/datum/visibility_chunk/proc/setObscuredImage(var/turf/target_turf)
if(!target_turf.obscured)
target_turf.obscured = image(obscured_image, target_turf, obscured_sub, 15)
/datum/visibility_chunk/proc/update()
set background = 1
// get a list of all the turfs that our viewpoints can see
var/list/newVisibleTurfs = getVisibleTurfs()
// Removes turf that isn't in turfs.
newVisibleTurfs &= turfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
// update the visibility overlays
for(var/turf in visAdded)
var/turf/t = turf
if(t.obscured)
obscured -= t.obscured
for(var/mob/current_mob in seenby)
if (current_mob.visibility_interface)
current_mob.visibility_interface:removeObscuredTurf(t)
for(var/turf in visRemoved)
var/turf/t = turf
if(obscuredTurfs[t])
setObscuredImage(t)
obscured += t.obscured
for(var/mob/current_mob in seenby)
if (current_mob.visibility_interface)
current_mob.visibility_interface:addObscuredTurf(t)
else
seenby -= current_mob
// Create a new chunk, since the chunks are made as they are needed.
/datum/visibility_chunk/New(loc, x, y, z)
// 0xf = 15
x &= ~0xf
y &= ~0xf
src.x = x
src.y = y
src.z = z
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
// locate all nearby viewpoints
findNearbyViewpoints()
// get the turfs that are visible to those viewpoints
visibleTurfs = getVisibleTurfs()
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
// create the list of turfs we can't see
obscuredTurfs = turfs - visibleTurfs
// create the list of obscuring images to add to viewing clients
for(var/turf in obscuredTurfs)
var/turf/t = turf
setObscuredImage(t)
obscured += t.obscured
#undef UPDATE_BUFFER
@@ -1,11 +0,0 @@
var/datum/visibility_network/cameras/cameranet = new()
var/datum/visibility_network/cult/cultNetwork = new()
var/datum/visibility_network/list/visibility_networks = list("ALL_CAMERAS"=cameranet, "CULT" = cultNetwork)
// used by turfs and objects to update all visibility networks
/proc/updateVisibilityNetworks(atom/A, var/opacity_check = 1)
var/datum/visibility_network/currentNetwork
for (var/networkName in visibility_networks)
currentNetwork = visibility_networks[networkName]
currentNetwork.updateVisibility(A, opacity_check)
@@ -1,94 +0,0 @@
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/turf
var/image/obscured
/turf/proc/visibilityChanged()
if(ticker)
updateVisibilityNetworks(src)
/turf/simulated/Del()
visibilityChanged()
..()
/turf/simulated/New()
..()
visibilityChanged()
// STRUCTURES
/obj/structure/Del()
if(ticker)
updateVisibilityNetworks(src)
..()
/obj/structure/New()
..()
if(ticker)
updateVisibilityNetworks(src)
// EFFECTS
/obj/effect/Del()
if(ticker)
updateVisibilityNetworks(src)
..()
/obj/effect/New()
..()
if(ticker)
updateVisibilityNetworks(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/proc/update_nearby_tiles(need_rebuild)
if(!glass)
updateVisibilityNetworks(src,0)
if(!air_master)
return 0
for(var/turf/simulated/turf in locs)
update_heat_protection(turf)
air_master.mark_for_update(turf)
return 1
#define UPDATE_VISIBILITY_NETWORK_BUFFER 30
/mob
var/datum/visibility_network/list/visibilityNetworks=list()
var/updatingVisibilityNetworks=FALSE
/mob/Move(n,direct)
var/oldLoc = src.loc
//. = ..()
if(..(n,direct))
if(src.visibilityNetworks.len)
if(!src.updatingVisibilityNetworks)
src.updatingVisibilityNetworks = 1
spawn(UPDATE_VISIBILITY_NETWORK_BUFFER)
if(oldLoc != src.loc)
for (var/datum/visibility_network/currentNetwork in src.visibilityNetworks)
currentNetwork.updateMob(src)
src.updatingVisibilityNetworks = 0
return .
/mob/proc/addToVisibilityNetwork(var/datum/visibility_network/network)
if(network)
src.visibilityNetworks+=network
/mob/proc/removeFromVisibilityNetwork(var/datum/visibility_network/network)
if(network)
src.visibilityNetworks|=network
#undef UPDATE_VISIBILITY_NETWORK_BUFFER
@@ -1,46 +0,0 @@
/datum/visibility_interface
var/chunk_type = null
var/mob/controller = null
var/list/visible_chunks = list()
/datum/visibility_interface/New(var/mob/controller)
src.controller = controller
/datum/visibility_interface/proc/validMob()
return getClient()
/datum/visibility_interface/proc/getClient()
return controller.client
/datum/visibility_interface/proc/canBeAddedToChunk(var/datum/visibility_chunk/test_chunk)
return istype(test_chunk,chunk_type)
/datum/visibility_interface/proc/addChunk(var/datum/visibility_chunk/test_chunk)
visible_chunks+=test_chunk
var/client/currentClient = getClient()
if(currentClient)
currentClient.images += test_chunk.obscured
/datum/visibility_interface/proc/removeChunk(var/datum/visibility_chunk/test_chunk)
visible_chunks-=test_chunk
var/client/currentClient = getClient()
if(currentClient)
currentClient.images -= test_chunk.obscured
/datum/visibility_interface/proc/removeObscuredTurf(var/turf/target_turf)
if(validMob())
var/client/currentClient = getClient()
if(currentClient)
currentClient.images -= target_turf.obscured
/datum/visibility_interface/proc/addObscuredTurf(var/turf/target_turf)
if(validMob())
var/client/currentClient = getClient()
if(currentClient)
currentClient.images -= target_turf.obscured
@@ -1,144 +0,0 @@
/datum/visibility_network
var/list/viewpoints = list()
// the type of chunk used by this network
var/datum/visibility_chunk/ChunkType = /datum/visibility_chunk
// The chunks of the map, mapping the areas that the viewpoints can see.
var/list/chunks = list()
var/ready = 0
// Creates a chunk key string from x,y,z coordinates
/datum/visibility_network/proc/createChunkKey(x,y,z)
x &= ~0xf
y &= ~0xf
return "[x],[y],[z]"
// Checks if a chunk has been Generated in x, y, z.
/datum/visibility_network/proc/chunkGenerated(x, y, z)
return (chunks[createChunkKey(x, y, z)])
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/visibility_network/proc/getChunk(x, y, z)
var/key = createChunkKey(x, y, z)
if(!chunks[key])
chunks[key] = new ChunkType(null, x, y, z)
return chunks[key]
/datum/visibility_network/proc/visibility(var/mob/targetMob)
// if we've got not visibility interface on the mob, we canot do this
if (!targetMob.visibility_interface)
return
// 0xf = 15
var/x1 = max(0, targetMob.x - 16) & ~0xf
var/y1 = max(0, targetMob.y - 16) & ~0xf
var/x2 = min(world.maxx, targetMob.x + 16) & ~0xf
var/y2 = min(world.maxy, targetMob.y + 16) & ~0xf
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
visibleChunks += getChunk(x, y, targetMob.z)
var/list/remove = targetMob.visibility_interface:visible_chunks - visibleChunks
var/list/add = visibleChunks - targetMob.visibility_interface:visible_chunks
for(var/datum/visibility_chunk/chunk in remove)
chunk.remove(targetMob)
for(var/datum/visibility_chunk/chunk in add)
chunk.add(targetMob)
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/visibility_network/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/visibility_network/proc/updateChunk(x, y, z)
if(!chunkGenerated(x, y, z))
return
var/datum/visibility_chunk/chunk = getChunk(x, y, z)
chunk.hasChanged()
/datum/visibility_network/proc/validViewpoint(var/viewpoint)
return FALSE
/datum/visibility_network/proc/addViewpoint(var/viewpoint)
if(validViewpoint(viewpoint))
majorChunkChange(viewpoint, 1)
/datum/visibility_network/proc/removeViewpoint(var/viewpoint)
if(validViewpoint(viewpoint))
majorChunkChange(viewpoint, 0)
/datum/visibility_network/proc/getViewpointFromMob(var/mob/currentMob)
return FALSE
/datum/visibility_network/proc/updateMob(var/mob/currentMob)
var/viewpoint = getViewpointFromMob(currentMob)
if(viewpoint)
updateViewpoint(viewpoint)
/datum/visibility_network/proc/updateViewpoint(var/viewpoint)
if(validViewpoint(viewpoint))
majorChunkChange(viewpoint, 1)
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the viewpoint from the chunks.
// If you want to update the chunks around an object, without adding/removing a viewpoint, use choice 2.
/datum/visibility_network/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
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
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, T.z))
var/datum/visibility_chunk/chunk = getChunk(x, y, T.z)
if(choice == 0)
// Remove the viewpoint.
chunk.viewpoints -= c
else if(choice == 1)
// You can't have the same viewpoint in the list twice.
chunk.viewpoints |= c
chunk.hasChanged()
// checks if the network can see a particular atom
/datum/visibility_network/proc/checkCanSee(var/atom/target)
var/turf/position = get_turf(target)
return checkTurfVis(position)
/datum/visibility_network/proc/checkTurfVis(var/turf/position)
var/datum/visibility_chunk/chunk = getChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(chunk.visibleTurfs[position])
return 1
return 0
+1 -1
View File
@@ -492,7 +492,7 @@
/obj/item/weapon/camera_bug/attack_self(mob/usr as mob)
var/list/cameras = new/list()
for (var/obj/machinery/camera/C in cameranet.viewpoints)
for (var/obj/machinery/camera/C in cameranet.cameras)
if (C.bugged && C.status)
cameras.Add(C)
if (length(cameras) == 0)
+6
View File
@@ -22,6 +22,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/poweralm = 1
var/party = null
var/radalert = 0
var/report_alerts = 1 // Should atmos alerts notify the AI/computers
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
@@ -1983,6 +1984,11 @@ area/security/podbay
//Traitor Station
/area/traitor
name = "\improper Syndicate Base"
icon_state = "syndie_hall"
report_alerts = 0
/area/traitor/rnd
name = "\improper Syndicate Research and Development"
icon_state = "syndie_rnd"
+33 -2
View File
@@ -52,25 +52,32 @@
InitializeLighting()
/area/proc/poweralert(var/state, var/obj/source as obj)
/area/proc/poweralert(var/state, var/obj/source as obj)
if (state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
var/list/cameras = list()
for (var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
if(!report_alerts)
break
cameras += C
if(state == 1)
C.network.Remove("Power Alarms")
else
C.network.Add("Power Alarms")
for (var/mob/living/silicon/aiPlayer in player_list)
if(!report_alerts)
break
if(aiPlayer.z == source.z)
if (state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
for(var/obj/machinery/computer/station_alert/a in machines)
if(!report_alerts)
break
if(a.z == source.z)
if(state == 1)
a.cancelAlarm("Power", src, source)
@@ -107,11 +114,17 @@
for(var/area/RA in related)
//updateicon()
for(var/obj/machinery/camera/C in RA)
if(!report_alerts)
break
cameras += C
C.network.Add("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
if(!report_alerts)
break
aiPlayer.triggerAlarm("Atmosphere", src, cameras, src)
for(var/obj/machinery/computer/station_alert/a in machines)
if(!report_alerts)
break
a.triggerAlarm("Atmosphere", src, cameras, src)
air_doors_activated=1
CloseFirelocks()
@@ -119,10 +132,16 @@
else if (atmosalm == 2)
for(var/area/RA in related)
for(var/obj/machinery/camera/C in RA)
if(!report_alerts)
break
C.network.Remove("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
if(!report_alerts)
break
aiPlayer.cancelAlarm("Atmosphere", src, src)
for(var/obj/machinery/computer/station_alert/a in machines)
if(!report_alerts)
break
a.cancelAlarm("Atmosphere", src, src)
air_doors_activated=0
OpenFirelocks()
@@ -162,11 +181,17 @@
var/list/cameras = list()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
if(!report_alerts)
continue
cameras.Add(C)
C.network.Add("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
if(!report_alerts)
continue
aiPlayer.triggerAlarm("Fire", src, cameras, src)
for (var/obj/machinery/computer/station_alert/a in machines)
if(!report_alerts)
continue
a.triggerAlarm("Fire", src, cameras, src)
/area/proc/firereset()
@@ -176,10 +201,16 @@
updateicon()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
if(!report_alerts)
continue
C.network.Remove("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
if(!report_alerts)
continue
aiPlayer.cancelAlarm("Fire", src, src)
for (var/obj/machinery/computer/station_alert/a in machines)
if(!report_alerts)
continue
a.cancelAlarm("Fire", src, src)
OpenFirelocks()
@@ -355,7 +386,7 @@
thunk(L)
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))
if(L && L.client && (L.client.prefs.sound & SOUND_AMBIENCE))
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
+1 -1
View File
@@ -105,7 +105,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
changeling.objectives += debrain_objective
var/list/active_ais = active_ais()
if(active_ais.len && prob(10)) // num_players() proc is designed for roundstart, changed to fixed value to prevent problems with mid-round objective randomization.
if(active_ais.len && prob(4)) // Leaving this at a flat chance for now, problems with the num_players() proc due to latejoin antags.
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = changeling
destroy_objective.find_target()
@@ -15,7 +15,7 @@
user << "<span class='notice'>We feel a minute twitch in our eyes, and darkness creeps away.</span>"
else
user << "<span class='notice'>Our vision dulls. Shadows gather.</span>"
user.sight -= SEE_MOBS
user.sight &= ~SEE_MOBS
while(active)
user.see_in_dark = 8
user.see_invisible = 2
@@ -37,8 +37,6 @@
if(H.species.flags & IS_SYNTHETIC)
user << "<span class='warning'>This won't work on synthetics.</span>"
return
if(H.species.flags & NO_SCAN) //Prevents transforming slimes and killing them instantly
user << "<span class='warning'>This won't work on a creature with abnormal genetic material.</span>"
if(!isturf(user.loc))
return
if(get_dist(user, target) > (user.mind.changeling.sting_range))
@@ -87,6 +85,11 @@
if((M_HUSK in target.mutations) || (!ishuman(target) && !ismonkey(target)))
user << "<span class='warning'>Our sting appears ineffective against its DNA.</span>"
return 0
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(H.species.flags & NO_SCAN) //Prevents transforming slimes and killing them instantly
user << "<span class='warning'>This won't work on a creature with abnormal genetic material.</span>"
return 0
return 1
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(var/mob/user, var/mob/target)
+2 -4
View File
@@ -72,13 +72,11 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
blood.override = 1
for(var/mob/living/silicon/ai/AI in player_list)
AI.client.images += blood
cultNetwork.viewpoints+=src
cultNetwork.addViewpoint(src)
cult_viewpoints += src
/obj/effect/rune/Del()
..()
cultNetwork.viewpoints-=src
cultNetwork.removeViewpoint(src)
cult_viewpoints -= src
/obj/effect/rune/examine()
set src in view(2)
@@ -313,7 +313,7 @@ rcd light flash thingy on matter drain
power_type = /client/proc/reactivate_camera
/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.viewpoints)
/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Reactivate Camera"
set category = "Malfunction"
if (istype (C, /obj/machinery/camera))
@@ -337,7 +337,7 @@ rcd light flash thingy on matter drain
power_type = /client/proc/upgrade_camera
/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.viewpoints)
/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Upgrade Camera"
set category = "Malfunction"
if(istype(C))
+20 -13
View File
@@ -30,7 +30,7 @@ datum/objective
proc/find_target()
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2))
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD))
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -38,7 +38,7 @@ datum/objective
proc/find_target_by_role(role, role_type=0)//Option sets either to check assigned role or special role. Default to assigned.
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) && (possible_target.current.stat != 2) )
if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) && (possible_target.current.stat != DEAD) )
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -47,7 +47,7 @@ datum/objective
proc/find_target_with_special_role(role)
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
if((possible_target != owner) && ishuman(possible_target.current) && (role && possible_target.special_role == role || !role && possible_target.special_role) && (possible_target.current.stat != 2) )
if((possible_target != owner) && ishuman(possible_target.current) && (role && possible_target.special_role == role || !role && possible_target.special_role) && (possible_target.current.stat != DEAD) )
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
@@ -385,7 +385,7 @@ datum/objective/block
for(var/mob/living/player in player_list)
if(player.type in protected_mobs) continue
if (player.mind)
if (player.stat != 2)
if (player.stat != DEAD)
if (get_turf(player) in shuttle)
return 0
return 1
@@ -420,7 +420,7 @@ datum/objective/escape
return 0
if(!emergency_shuttle.returned())
return 0
if(!owner.current || owner.current.stat ==2)
if(!owner.current || owner.current.stat == DEAD)
return 0
var/turf/location = get_turf(owner.current.loc)
if(!location)
@@ -451,7 +451,14 @@ datum/objective/escape/escape_with_identity
var/target_real_name // Has to be stored because the target's real_name can change over the course of the round
find_target()
target = ..()
var/list/possible_targets = list() //Copypasta because NO_SCAN races, yay for snowflakes.
for(var/datum/mind/possible_target in ticker.minds)
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD))
var/mob/living/carbon/human/H = possible_target.current
if(!(H.species.flags & NO_SCAN))
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
if(target && target.current)
target_real_name = target.current.real_name
explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [target.assigned_role] while wearing their identification card."
@@ -658,7 +665,7 @@ datum/objective/download
check_completion()
if(!ishuman(owner.current))
return 0
if(!owner.current || owner.current.stat == 2)
if(!owner.current || owner.current.stat == DEAD)
return 0
if(!(istype(owner.current:wear_suit, /obj/item/clothing/suit/space/space_ninja)&&owner.current:wear_suit:s_initialized))
return 0
@@ -685,25 +692,25 @@ datum/objective/capture
var/captured_amount = 0
var/area/ninja/holding/A = locate()
for(var/mob/living/carbon/human/M in A)//Humans.
if(M.stat==2)//Dead folks are worth less.
if(M.stat == DEAD)//Dead folks are worth less.
captured_amount+=0.5
continue
captured_amount+=1
for(var/mob/living/carbon/monkey/M in A)//Monkeys are almost worthless, you failure.
captured_amount+=0.1
for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research.
if(M.stat==2)
if(M.stat == DEAD)
captured_amount+=0.5
continue
captured_amount+=1
for(var/mob/living/carbon/alien/humanoid/M in A)//Aliens are worth twice as much as humans.
if(istype(M, /mob/living/carbon/alien/humanoid/queen))//Queens are worth three times as much as humans.
if(M.stat==2)
if(M.stat == DEAD)
captured_amount+=1.5
else
captured_amount+=3
continue
if(M.stat==2)
if(M.stat == DEAD)
captured_amount+=1
continue
captured_amount+=2
@@ -845,7 +852,7 @@ datum/objective/heist/kidnap
var/list/priority_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && (possible_target.assigned_role != "MODE"))
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && (possible_target.assigned_role != "MODE"))
possible_targets += possible_target
for(var/role in roles)
if(possible_target.assigned_role == role)
@@ -865,7 +872,7 @@ datum/objective/heist/kidnap
check_completion()
if(target && target.current)
if (target.current.stat == 2)
if (target.current.stat == DEAD)
return 0 // They're dead. Fail.
//if (!target.current.restrained())
// return 0 // They're loose. Close but no cigar.
+1 -1
View File
@@ -107,7 +107,7 @@
assign_exchange_role(exchange_blue)
else
var/list/active_ais = active_ais()
if(active_ais.len && prob(10)) // Leaving this at a flat chance for now, problems with the num_players() proc.
if(active_ais.len && prob(4)) // Leaving this at a flat chance for now, problems with the num_players() proc due to latejoin antags.
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = traitor
destroy_objective.find_target()
+1
View File
@@ -458,6 +458,7 @@
alert_signal.transmission_method = 1
alert_signal.data["zone"] = alarm_area.name
alert_signal.data["type"] = "Atmospheric"
alert_signal.data["hidden"] = hidden
if(alert_level==2)
alert_signal.data["alert"] = "severe"
+223 -125
View File
@@ -4,54 +4,23 @@
icon_state = "yellow"
density = 1
var/health = 100.0
flags = CONDUCT
var/menu = 0
//used by nanoui: 0 = main menu, 1 = relabel
var/valve_open = 0
var/release_pressure = ONE_ATMOSPHERE
var/list/_color = list("yellow", null, null, null)//variable that stores colours
var/list/decals = list() // var that stores the decals, NOTE: Not the actual POSSIBLE decals, but the ones currently used
var/list/oldcolor = list()//lists for check_change()
var/list/olddecals = list()
var/list/possibledecals = list( //var that stores all possible decals, here for adminbus I guess? NOTE: LEAVE "done" IN HERE
"Low temperature canister" = "cold",
"High temperature canister" = "hot",
"Plasma containing canister" = "plasma",
"Done" = "DONE"
)
var/list/possiblemaincolor = list( //these lists contain the possible colors of a canister, here for adminbus
"\[N2O\]" = "redws",
"\[N2\]" = "red",
"\[O2\]" = "blue",
"\[Toxin (Bio)\]" = "orange",
"\[CO2\]" = "black",
"\[Air\]" = "grey",
"\[CAUTION\]" = "yellow",
"\[SPECIAL\]" = "whiters"
)
var/list/possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
"\[N2\]" = "red-c",
"\[O2\]" = "blue-c",
"\[Toxin (Bio)\]" = "orange-c",
"\[CO2\]" = "black-c",
"\[Air\]" = "grey-c",
"\[CAUTION\]" = "yellow-c"
)
var/list/possibletertcolor = list(
"\[N2\]" = "red-c-1",
"\[O2\]" = "blue-c-1",
"\[Toxin (Bio)\]" = "orange-c-1",
"\[CO2\]" = "black-c-1",
"\[Air\]" = "grey-c-1",
"\[CAUTION\]" = "yellow-c-1"
)
var/list/possiblequartcolor = list(
"\[N2\]" = "red-c-2",
"\[O2\]" = "blue-c-2",
"\[Toxin (Bio)\]" = "orange-c-2",
"\[CO2\]" = "black-c-2",
"\[Air\]" = "grey-c-2",
"\[CAUTION\]" = "yellow-c-2"
)
var/list/_color //variable that stores colours
var/list/decals // list that stores the decals
var/list/possibledecals
var/list/oldcolor//lists for check_change()
var/list/olddecals
var/list/possiblemaincolor //these lists contain the possible colors of a canister
var/list/possibleseccolor
var/list/possibletertcolor
var/list/possiblequartcolor
var/list/colorcontainer //passed to the ui to render the color lists
var/can_label = 1
var/filled = 0.5
@@ -63,42 +32,78 @@
var/busy = 0
var/update_flag = 0
/obj/machinery/portable_atmospherics/canister/sleeping_agent
name = "Canister: \[N2O\]"
icon_state = "redws"
_color = list("redws", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/nitrogen
name = "Canister: \[N2\]"
icon_state = "red"
_color = list("red", null, null, null)
decals = list("plasma")
can_label = 0
/obj/machinery/portable_atmospherics/canister/oxygen
name = "Canister: \[O2\]"
icon_state = "blue"
_color = list("blue", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/toxins
name = "Canister \[Toxin (Plasma)\]"
icon_state = "orange"
_color = list("orange", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/carbon_dioxide
name = "Canister \[CO2\]"
icon_state = "black"
_color = list("black", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/air
name = "Canister \[Air\]"
icon_state = "grey"
_color = list("grey", null, null, null)
can_label = 0
/obj/machinery/portable_atmospherics/canister/custom_mix
name = "Canister \[Custom\]"
icon_state = "whiters"
_color = list("whiters", null, null, null)
can_label = 0
New()
..()
_color = list(
"prim" = "yellow",
"sec" = null,
"ter" = null,
"quart" = null)
oldcolor = list()
decals = list()
olddecals = list()
possibledecals = list( //var that stores all possible decals, used by ui
list("name" = "Low temperature canister", "icon" = "cold", "active" = 0),
list("name" = "High temperature canister", "icon" = "hot", "active" = 0),
list("name" = "Plasma containing canister", "icon" = "plasma", "active" = 0)
)
possiblemaincolor = list( //these lists contain the possible colors of a canister
list("name" = "\[N2O\]", "icon" = "redws"),
list("name" = "\[N2\]", "icon" = "red"),
list("name" = "\[O2\]", "icon" = "blue"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange"),
list("name" = "\[CO2\]", "icon" = "black"),
list("name" = "\[Air\]", "icon" = "grey"),
list("name" = "\[CAUTION\]", "icon" = "yellow"),
list("name" = "\[SPECIAL\]", "icon" = "whiters")
)
possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
list("name" = "\[N2\]", "icon" = "red-c"),
list("name" = "\[O2\]", "icon" = "blue-c"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c"),
list("name" = "\[CO2\]", "icon" = "black-c"),
list("name" = "\[Air\]", "icon" = "grey-c"),
list("name" = "\[CAUTION\]", "icon" = "yellow-c")
)
possibletertcolor = list(
list("name" = "\[N2\]", "icon" = "red-c-1"),
list("name" = "\[O2\]", "icon" = "blue-c-1"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-1"),
list("name" = "\[CO2\]", "icon" = "black-c-1"),
list("name" = "\[Air\]", "icon" = "grey-c-1"),
list("name" = "\[CAUTION\]", "icon" = "yellow-c-1")
)
possiblequartcolor = list(
list("name" = "\[N2\]", "icon" = "red-c-2"),
list("name" = "\[O2\]", "icon" = "blue-c-2"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-2"),
list("name" = "\[CO2\]", "icon" = "black-c-2"),
list("name" = "\[Air\]", "icon" = "grey-c-2"),
list("name" = "\[CAUTION\]", "icon" = "yellow-c-2")
)
colorcontainer = list(//passed to the ui to render the color lists
"prim" = list(
"options" = possiblemaincolor,
"name" = "Primary color",
"anycolor" = -1,//0: no color applied. 1: color selected. Not used for primary color.
),
"sec" = list(
"options" = possibleseccolor,
"name" = "Secondary color",
"anycolor" = 0,
),
"ter" = list(
"options" = possibletertcolor,
"name" = "Tertiary color",
"anycolor" = 0,
),
"quart" = list(
"options" = possiblequartcolor,
"name" = "Quaternary color",
"anycolor" = 0,
)
)
update_icon()
/obj/machinery/portable_atmospherics/canister/proc/check_change()
var/old_flag = update_flag
@@ -118,10 +123,13 @@
else
update_flag |= 32
if(oldcolor != _color || olddecals != decals)
if(list2params(oldcolor) != list2params(_color))
update_flag |= 64
olddecals = decals
oldcolor = _color
oldcolor = _color.Copy()
if(list2params(olddecals) != list2params(decals))
update_flag |= 128
olddecals = decals.Copy()
if(update_flag == old_flag)
return 1
@@ -137,29 +145,31 @@ update_flag
8 = tank_pressure < ONE_ATMOS
16 = tank_pressure < 15*ONE_ATMOS
32 = tank_pressure go boom.
64 = decals/colors got changed
64 = colors
128 = decals
(note: colors and decals has to be applied every icon update)
*/
if (src.destroyed)
src.overlays = 0
src.icon_state = text("[]-1", src._color[1])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
src.icon_state = text("[]-1", src._color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
if(icon_state != src._color[1])
icon_state = src._color[1]
if(icon_state != src._color["prim"])
icon_state = src._color["prim"]
if(check_change()) //Returns 1 if no change needed to icons.
return
src.overlays = 0
if (_color[2])//COLORS!
overlays.Add(_color[2])
if (_color["sec"])//COLORS!
overlays.Add(_color["sec"])
if (_color[3])
overlays.Add(_color[3])
if (_color["ter"])
overlays.Add(_color["ter"])
if (_color[4])
overlays.Add(_color[4])
if (_color["quart"])
overlays.Add(_color["quart"])
for(var/D in decals)
overlays.Add("decal-" + D)
@@ -176,8 +186,36 @@ update_flag
overlays += "can-o2"
else if(update_flag & 32)
overlays += "can-o3"
update_flag &= ~196 //the flags 128 and 64 represent change, not states. As such, we have to reset them to be able to detect a change on the next go.
return
//template modification exploit prevention, used in Topic()
/obj/machinery/portable_atmospherics/canister/proc/is_a_color(var/inputVar, var/checkColor = "all")
if (checkColor == "prim" || checkColor == "all")
for(var/list/L in possiblemaincolor)
if (L["icon"] == inputVar)
return 1
if (checkColor == "sec" || checkColor == "all")
for(var/list/L in possibleseccolor)
if (L["icon"] == inputVar)
return 1
if (checkColor == "ter" || checkColor == "all")
for(var/list/L in possibletertcolor)
if (L["icon"] == inputVar)
return 1
if (checkColor == "quart" || checkColor == "all")
for(var/list/L in possiblequartcolor)
if (L["icon"] == inputVar)
return 1
return 0
/obj/machinery/portable_atmospherics/canister/proc/is_a_decal(var/inputVar)
for(var/list/L in possibledecals)
if (L["icon"] == inputVar)
return 1
return 0
/obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature > temperature_resistance)
health -= 5
@@ -329,7 +367,11 @@ update_flag
// this is the data which will be sent to the ui
var/data[0]
data["name"] = name
data["menu"] = menu ? 1 : 0
data["canLabel"] = can_label ? 1 : 0
data["_color"] = _color
data["colorContainer"] = colorcontainer
data["possibleDecals"] = possibledecals
data["portConnected"] = connected_port ? 1 : 0
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
@@ -365,6 +407,9 @@ update_flag
onclose(usr, "canister")
return
if (href_list["choice"] == "menu")
menu = text2num(href_list["mode_target"])
if(href_list["toggle"])
if (valve_open)
if (holding)
@@ -393,48 +438,96 @@ update_flag
else
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
if (href_list["relabel"])
if (href_list["rename"])
if (can_label)
var/T = copytext(sanitize(input("Choose canister label", "Name", name) as text|null),1,MAX_NAME_LEN)
if (can_label) //Exploit prevention
if (T)
name = T
else
name = "canister"
else
usr << "\red As you attempted to rename it the pressure rose!"
var/label1 = input("Choose canister label", "Primary color") as null|anything in possiblemaincolor
if (href_list["choice"] == "Primary color")
if (is_a_color(href_list["icon"],"prim"))
_color["prim"] = href_list["icon"]
if (href_list["choice"] == "Secondary color")
if (href_list["icon"] == "none")
_color["sec"] = ""
colorcontainer["sec"]["anycolor"] = 0
else if (is_a_color(href_list["icon"],"sec"))
_color["sec"] = href_list["icon"]
colorcontainer["sec"]["anycolor"] = 1
if (href_list["choice"] == "Tertiary color")
if (href_list["icon"] == "none")
_color["ter"] = ""
colorcontainer["ter"]["anycolor"] = 0
else if (is_a_color(href_list["icon"],"ter"))
_color["ter"] = href_list["icon"]
colorcontainer["ter"]["anycolor"] = 1
if (href_list["choice"] == "Quaternary color")
if (href_list["icon"] == "none")
_color["quart"] = ""
colorcontainer["quart"]["anycolor"] = 0
else if (is_a_color(href_list["icon"],"quart"))
_color["quart"] = href_list["icon"]
colorcontainer["quart"]["anycolor"] = 1
var/label2 = input("Choose canister label", "Secondary color") as null|anything in possibleseccolor
var/label3 = input("Choose canister label", "Tertiary color") as null|anything in possibletertcolor
var/label4 = input("Choose canister label", "Quaternary color") as null|anything in possiblequartcolor
decals = list()
_color = list(
(label1 ? possiblemaincolor[label1] : color[1]),//if the user didn't specify a primary colour, keep the current one.
possibleseccolor[label2],
possibletertcolor[label3],
possiblequartcolor[label4]
)
decals = list()
var/list/tempposdecals = possibledecals
while (src && !src.gc_destroyed && usr)//allow the user to select (theoretically) INFINITE DECALS!!!
var/newdecal = input("Choose canister label", "Decal") as anything in tempposdecals
if (newdecal == "Done")
if (href_list["choice"] == "decals")
if (is_a_decal(href_list["icon"]))
for (var/list/L in possibledecals)
if (L["icon"] == href_list["icon"])
L["active"] = (L["active"] == 0)
break
decals.Add(tempposdecals[newdecal])
tempposdecals.Remove(newdecal)
src.name = (input("Choose canister label", "Name") as text) + " canister"
decals = list()
for (var/list/L in possibledecals)
if (L["active"])
if (!(L["icon"] in decals))
decals.Add(L["icon"])
src.add_fingerprint(usr)
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/toxins/New()
/obj/machinery/portable_atmospherics/canister/toxins
name = "Canister \[Toxin (Plasma)\]"
icon_state = "orange" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/oxygen
name = "Canister: \[O2\]"
icon_state = "blue" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/sleeping_agent
name = "Canister: \[N2O\]"
icon_state = "redws" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/nitrogen
name = "Canister: \[N2\]"
icon_state = "red" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/carbon_dioxide
name = "Canister \[CO2\]"
icon_state = "black" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/air
name = "Canister \[Air\]"
icon_state = "grey" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/custom_mix
name = "Canister \[Custom\]"
icon_state = "whiters" //See New()
can_label = 0
/obj/machinery/portable_atmospherics/canister/toxins/New()
..()
_color["prim"] = "orange"
src.air_contents.toxins = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -442,18 +535,18 @@ update_flag
return 1
/obj/machinery/portable_atmospherics/canister/oxygen/New()
..()
_color["prim"] = "blue"
src.air_contents.oxygen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
src.update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/sleeping_agent/New()
..()
_color["prim"] = "redws"
var/datum/gas/sleeping_agent/trace_gas = new
air_contents.trace_gases += trace_gas
trace_gas.moles = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
@@ -479,9 +572,11 @@ update_flag
/obj/machinery/portable_atmospherics/canister/nitrogen/New()
..()
_color["prim"] = "red"
decals = list("plasma")
possibledecals[3]["active"] = 1
src.air_contents.nitrogen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -489,8 +584,9 @@ update_flag
return 1
/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New()
..()
_color["prim"] = "black"
src.air_contents.carbon_dioxide = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -499,8 +595,9 @@ update_flag
/obj/machinery/portable_atmospherics/canister/air/New()
..()
_color["prim"] = "grey"
src.air_contents.oxygen = (O2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
src.air_contents.nitrogen = (N2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.update_values()
@@ -511,6 +608,7 @@ update_flag
/obj/machinery/portable_atmospherics/canister/custom_mix/New()
..()
_color["prim"] = "whiters"
src.update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
return 1
+1 -1
View File
@@ -583,7 +583,7 @@ obj/machinery/bot/proc/start_patrol()
new_destination = "__nearest__"
post_signal(beacon_freq, "findbeacon", "patrol")
awaiting_beacon = 1
spawn(150)
spawn(200)
awaiting_beacon = 0
if(nearest_beacon)
set_destination(nearest_beacon)
+156 -94
View File
@@ -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)
+10 -8
View File
@@ -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
@@ -98,7 +100,7 @@
C.auto_turn()
C.network = uniquelist(tempnetwork)
tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS)
tempnetwork = difflist(C.network,restricted_camera_networks)
if(!tempnetwork.len)//Camera isn't on any open network - remove its chunk from AI visibility.
cameranet.removeCamera(C)
@@ -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 -2
View File
@@ -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
+19 -6
View File
@@ -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)
+96 -96
View File
@@ -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.cameras)
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(atom/movable/target as mob|obj)
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(atom/movable/M)
var/turf/T = get_turf(M)
if(T && (T.z == 1 || T.z == 3 || T.z == 5))
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
@@ -23,8 +23,10 @@
var/zone = signal.data["zone"]
var/severity = signal.data["alert"]
var/hidden = signal.data["hidden"]
if(!zone || !severity) return
if(hidden) return
minor_alarms -= zone
priority_alarms -= zone
+13 -4
View File
@@ -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)
@@ -76,14 +81,15 @@
var/data[0]
data["current"] = null
var/list/L = list()
for (var/obj/machinery/camera/C in cameranet.viewpoints)
for (var/obj/machinery/camera/C in cameranet.cameras)
if(can_access_camera(C))
L.Add(C)
camera_sort(L)
cameranet.process_sort()
var/cameras[0]
for(var/obj/machinery/camera/C in L)
@@ -106,7 +112,7 @@
if(emagged)
access = list(access_captain) // Assume captain level access when emagged
data["emagged"] = 1
if(isAI(user) || isrobot (user))
if(isAI(user) || isrobot(user))
access = list(access_captain) // Assume captain level access when AI
// Loop through the ID's permission, and check which networks the ID has access to.
@@ -119,6 +125,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)
@@ -137,7 +146,7 @@
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
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.viewpoints
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras
if(!C) return
switch_to_camera(usr, C)
+4 -4
View File
@@ -123,7 +123,7 @@
if (istype(I))
if(src.check_access(I))
if (!status)
message_admins("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!")
msg_admin_attack("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!")
log_game("\blue [key_name(usr)] has initiated the global cyborg killswitch!")
use_log += text("\[[time_stamp()]\] <font color='red'>[usr.name] ([usr.ckey]) has initiated the global cyborg killswitch!</font>")
src.status = 1
@@ -169,7 +169,7 @@
R.ResetSecurityCodes()
else
message_admins("\blue [key_name_admin(usr)] detonated [R.name]!")
msg_admin_attack("\blue [key_name_admin(usr)] detonated [R.name]!")
log_game("\blue [key_name_admin(usr)] detonated [R.name]!")
use_log += text("\[[time_stamp()]\] <font color='red'>[usr.name] ([usr.ckey]) detonated [R.name] ([R.ckey])!</font>")
R.self_destruct()
@@ -183,7 +183,7 @@
var/choice = input("Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm")
if(R && istype(R))
message_admins("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
msg_admin_attack("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
R.canmove = !R.canmove
if (R.lockcharge)
@@ -208,7 +208,7 @@
var/choice = input("Are you certain you wish to hack [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm")
if(R && istype(R))
// message_admins("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!")
msg_admin_attack("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!")
log_game("[key_name(usr)] emagged [R.name] using robotic console!")
R.emagged = 1
if(R.hud_used)
+3 -1
View File
@@ -221,12 +221,14 @@
for(var/datum/reagent/R in beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
data["autoeject"] = autoeject
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410)
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 420)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
+101
View File
@@ -0,0 +1,101 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
/obj/machinery/laprecharger
name = "laptop recharger"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "recharger0"
anchored = 1
use_power = 1
idle_power_usage = 40
active_power_usage = 2500
var/obj/item/charging = null
var/icon_state_charged = "recharger2"
var/icon_state_charging = "recharger1"
var/icon_state_idle = "recharger0"
/obj/machinery/laprecharger/attackby(obj/item/weapon/G as obj, mob/user as mob)
if(istype(user,/mob/living/silicon))
return
if(istype(G, /obj/item/weapon/gun/energy) || istype(G, /obj/item/weapon/melee/baton))
user << "\red The laptop recharger blinks red as you try to insert the item!"
return
if(istype(G,/obj/item/device/laptop))
if(charging)
return
// Checks to make sure he's not in space doing it, and that the area got proper power.
var/area/a = get_area(src)
if(!isarea(a))
user << "\red The [name] blinks red as you try to insert the item!"
return
if(a.power_equip == 0)
user << "\red The [name] blinks red as you try to insert the item!"
return
if(istype(G, /obj/item/device/laptop))
var/obj/item/device/laptop/L = G
if(!L.stored_computer.battery)
user << "There's no battery in it!"
return
user.drop_item()
G.loc = src
charging = G
use_power = 2
update_icon()
else if(istype(G, /obj/item/weapon/wrench))
if(charging)
user << "\red Remove the laptop first!"
return
anchored = !anchored
user << "You [anchored ? "attached" : "detached"] the recharger."
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
/obj/machinery/laprecharger/attack_hand(mob/user as mob)
add_fingerprint(user)
if(charging)
charging.update_icon()
charging.loc = loc
charging = null
use_power = 1
update_icon()
/obj/machinery/laprecharger/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/laprecharger/process()
if(stat & (NOPOWER|BROKEN) || !anchored)
return
if(charging)
if(istype(charging, /obj/item/device/laptop))
var/obj/item/device/laptop/L = charging
if(L.stored_computer.battery.charge < L.stored_computer.battery.maxcharge)
L.stored_computer.battery.give(1000)
icon_state = icon_state_charging
use_power(2500)
else
icon_state = icon_state_charged
return
/obj/machinery/laprecharger/emp_act(severity)
if(stat & (NOPOWER|BROKEN) || !anchored)
..(severity)
return
/obj/machinery/laprecharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier.
if(charging)
icon_state = icon_state_charging
else
icon_state = icon_state_idle
// Atlantis: No need for that copy-pasta code, just use var to store icon_states instead.
obj/machinery/laprecharger/wallcharger
name = "wall laptop recharger"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "wrecharger0"
icon_state_idle = "wrecharger0"
icon_state_charging = "wrecharger1"
icon_state_charged = "wrecharger2"
-9
View File
@@ -25,15 +25,6 @@
if(!height || air_group) return 0
else return ..()
//Looks like copy/pasted code... I doubt 'need_rebuild' is even used here - Nodrak
/obj/machinery/shield/proc/update_nearby_tiles(need_rebuild)
if(!air_master) return 0
air_master.mark_for_update(get_turf(src))
return 1
/obj/machinery/shield/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(!istype(W)) return
+1 -1
View File
@@ -138,7 +138,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
if(payload && !istype(payload, /obj/item/weapon/bombcore/training))
message_admins("[key_name(user)]<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A> has primed a [name] ([payload]) for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.")
msg_admin_attack("[key_name(user)]<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A> has primed a [name] ([payload]) for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.")
log_game("[key_name(user)] has primed a [name] ([payload]) for detonation at [A.name]([bombturf.x],[bombturf.y],[bombturf.z])")
payload.adminlog = "The [src.name] that [key_name(user)] had primed detonated!"
+2 -11
View File
@@ -467,10 +467,10 @@ steam.start() -- spawns the effect
var/more = ""
if(M)
more = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</a>)"
message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
start()
@@ -1107,15 +1107,6 @@ steam.start() -- spawns the effect
if(air_group) return 0
return !density
proc/update_nearby_tiles(need_rebuild)
if(!air_master)
return 0
air_master.mark_for_update(get_turf(src))
return 1
/datum/effect/effect/system/reagents_explosion
var/amount // TNT equivalent
var/flashing = 0 // does explosion creates flash effect?
+1 -1
View File
@@ -7,7 +7,7 @@
/obj/item/device/handtv/attack_self(mob/usr as mob)
var/list/cameras = new/list()
for (var/obj/machinery/camera/C in cameranet.viewpoints)
for (var/obj/machinery/camera/C in cameranet.cameras)
if (C.hasbug && C.status)
cameras.Add(C)
if (length(cameras) == 0)
@@ -51,8 +51,8 @@
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
bombers += "[key_name(user)] attached a [item] to a transfer valve."
message_admins("[key_name_admin(user)] attached a [item] to a transfer valve.")
log_game("[key_name_admin(user)] attached a [item] to a transfer valve.")
msg_admin_attack("[key_name_admin(user)] attached [item] to a transfer valve.")
log_game("[key_name_admin(user)] attached [item] to a transfer valve.")
attacher = user
nanomanager.update_uis(src) // update all UIs attached to src
return
@@ -66,7 +66,7 @@
/obj/item/device/transfer_valve/attack_self(mob/user as mob)
ui_interact(user)
/obj/item/device/transfer_valve/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// this is the data which will be sent to the ui
@@ -77,13 +77,13 @@
data["valveOpen"] = valve_open ? 1 : 0
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
@@ -190,7 +190,7 @@
log_str += " Last touched by: [src.fingerprintslast][last_touch_info]"
bombers += log_str
message_admins(log_str, 0, 1)
msg_admin_attack(log_str, 0, 1)
log_game(log_str)
merge_gases()
spawn(20) // In case one tank bursts
+1 -1
View File
@@ -26,7 +26,7 @@
/obj/item/tape/police
name = "police tape"
desc = "A length of police tape. Do not cross."
req_access = list(access_security)
req_one_access = list(access_security,access_forensics_lockers)
icon_base = "police"
/obj/item/taperoll/engineering
+26 -12
View File
@@ -101,13 +101,20 @@ AI MODULES
for(var/templaw in laws)
target.add_inherent_law(templaw)
/obj/item/weapon/aiModule/zeroth
var/removeownlaw = 0
/obj/item/weapon/aiModule/zeroth/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
if(target.laws.zeroth)
target << "[sender.real_name] attempted to modify your zeroth law."
target << "It would be in your best interest to play along with [sender.real_name] that:"
for(var/failedlaw in laws)
target << "[failedlaw]"
return 1
if(removeownlaw && (laws[1] == target.laws.zeroth))
target.clear_zeroth_law()
return 2
else
target << "[sender.real_name] attempted to modify your zeroth law."
target << "It would be in your best interest to play along with [sender.real_name] that:"
for(var/failedlaw in laws)
target << "[failedlaw]"
return 1
for(var/templaw in laws)
target.set_zeroth_law(templaw)
@@ -149,7 +156,7 @@ AI MODULES
/obj/item/weapon/aiModule/zeroth/oneHuman
name = "'OneHuman' AI Module"
var/targetName = ""
desc = "A 'one human' AI module: 'Only <name> is crew.'"
desc = "A 'one human' AI module: 'Only <name> is crew.' This module adds a zeroth law, which can only be removed by uploading this board again."
origin_tech = "programming=3;materials=6" //made with diamonds!
laws = list("Only <name> is crew.")
@@ -159,6 +166,7 @@ AI MODULES
targetName = targName
laws[1] = "Only [targetName] is crew"
desc = "A 'one crew' AI module: '[laws[1]]'"
removeownlaw = 1
/obj/item/weapon/aiModule/zeroth/oneHuman/install(var/mob/living/silicon/S,var/mob/user)
if(!targetName)
@@ -167,8 +175,10 @@ AI MODULES
..()
/obj/item/weapon/aiModule/zeroth/oneHuman/transmitInstructions(var/mob/living/silicon/target, var/mob/sender)
if(..())
return "[targetName], but the AI's existing law 0 cannot be overriden."
if(..() == 1)
return "[targetName], but the AI's existing zeroth law cannot be overriden."
if(..() == 2)
return "The AI's zeroth law has been overridden."
return targetName
@@ -186,13 +196,17 @@ AI MODULES
/obj/item/weapon/aiModule/zeroth/quarantine
name = "'Quarantine' AI Module"
desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.'"
desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.' This module adds a zeroth law, which can only be removed by uploading this board again."
origin_tech = "programming=3;biotech=2;materials=4"
laws = list("The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, organics from leaving. It is impossible to harm an organic while preventing them from leaving.")
removeownlaw = 1
/obj/item/weapon/aiModule/zeroth/quarantine/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
if(..())
return "The AI's existing law 0 cannot be overriden."
var/result = ..()
if(result == 1)
return "The AI's existing zeroth law cannot be overriden."
if(result == 2)
return "The AI's zeroth law has been overridden."
return laws[1]
/******************** OxygenIsToxicToHumans ********************/
@@ -259,7 +273,7 @@ AI MODULES
/obj/item/weapon/aiModule/reset/purge/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
..()
target.clear_inherent_laws()
target.clear_inherent_laws()
/******************* Full Core Boards *******************/
@@ -96,7 +96,7 @@
else if(clown_check(user))
// This used to go before the assembly check, but that has absolutely zero to do with priming the damn thing. You could spam the admins with it.
var/log_str = "[key_name(usr)]<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A> has primed a [name] for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>."
message_admins(log_str)
msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
user << "<span class='warning'>You prime the [name]! [det_time / 10] second\s!</span>"
@@ -144,7 +144,7 @@
var/turf/bombturf = get_turf(loc)
var/area/A = bombturf.loc
var/log_str = "[key_name(usr)]<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A> has completed [name] at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> [contained]."
message_admins(log_str)
msg_admin_attack(log_str)
log_game(log_str)
else
user << "<span class='notice'>You need to add at least one beaker before locking the assembly.</span>"
@@ -72,7 +72,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
var/log_str = "[key_name(usr)]<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A> has primed a [name] for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>."
message_admins(log_str)
msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
if(iscarbon(user))
@@ -63,7 +63,7 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
var/log_str = "[key_name(usr)]<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A> has primed a [name] for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>."
message_admins(log_str)
msg_admin_attack(log_str)
log_game(log_str)
bombers += "[log_str]"
if(iscarbon(user))
+22 -20
View File
@@ -444,7 +444,7 @@ obj/item/weapon/twohanded/
no_embed = 1
force = 5
force_unwielded = 5
force_wielded = 20
force_wielded = 30
throwforce = 15
throw_range = 1
w_class = 5
@@ -475,29 +475,31 @@ obj/item/weapon/twohanded/
/obj/item/weapon/twohanded/knighthammer/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity)
if(!proximity) return
if(wielded)
if(charged == 5)
charged = 0
if(istype(A, /mob/living/))
var/mob/living/Z = A
if(Z.health < 1)
Z.visible_message("<span class='danger'>[Z.name] was blown to peices by the power of [src.name]!</span>", \
"<span class='userdanger'>You feel a powerful blow rip you apart!</span>", \
"<span class='danger'>You hear a heavy impact and the sound of ripping flesh!.</span>")
Z.gib()
else
Z.take_organ_damage(0,30)
Z.visible_message("<span class='danger'>[Z.name] was sent flying by a blow from the [src.name]!</span>", \
"<span class='userdanger'>You feel a powerful blow connect with your body and send you flying!</span>", \
"<span class='danger'>You hear something heavy impact flesh!.</span>")
var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src)))
Z.throw_at(throw_target, 200, 4)
else if(istype(A, /turf/simulated/wall))
if(charged == 5)
charged = 0
if(istype(A, /mob/living/))
var/mob/living/Z = A
if(Z.health >= 1)
Z.visible_message("<span class='danger'>[Z.name] was sent flying by a blow from the [src.name]!</span>", \
"<span class='userdanger'>You feel a powerful blow connect with your body and send you flying!</span>", \
"<span class='danger'>You hear something heavy impact flesh!.</span>")
var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src)))
Z.throw_at(throw_target, 200, 4)
playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
else if(wielded && Z.health < 1)
Z.visible_message("<span class='danger'>[Z.name] was blown to peices by the power of [src.name]!</span>", \
"<span class='userdanger'>You feel a powerful blow rip you apart!</span>", \
"<span class='danger'>You hear a heavy impact and the sound of ripping flesh!.</span>")
Z.gib()
playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
if(wielded)
if(istype(A, /turf/simulated/wall))
var/turf/simulated/wall/Z = A
Z.ex_act(2)
charged = 3
playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
else if (istype(A, /obj/structure) || istype(A, /obj/mecha/))
var/obj/Z = A
Z.ex_act(2)
charged = 3
playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
playsound(user, 'sound/weapons/marauder.ogg', 50, 1)
@@ -110,6 +110,11 @@
viewers(user) << "<span class='suicide'>[user] is falling on the [src.name]! It looks like \he's trying to commit suicide.</span>"
return(BRUTELOSS)
/obj/item/weapon/claymore/ceremonial
name = "ceremonial claymore"
desc = "An engraved and fancy version of the claymore. It appears to be less sharp than it's more functional cousin."
force = 20
/obj/item/weapon/katana
name = "katana"
desc = "Woefully underpowered in D20"
+15 -3
View File
@@ -5,9 +5,6 @@
icon_state = "cart"
anchored = 0
density = 1
flags = OPENCONTAINER
//copypaste sorry
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
var/obj/item/stack/sheet/glass/myglass = null
var/obj/item/stack/sheet/metal/mymetal = null
var/obj/item/stack/sheet/plasteel/myplasteel = null
@@ -82,6 +79,21 @@
update_icon()
else
user << fail_msg
else if(istype(I, /obj/item/weapon/wrench))
if (!anchored && !isinspace())
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] tightens \the [src]'s casters.", \
"<span class='notice'> You have tightened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 1
else if(anchored)
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] loosens \the [src]'s casters.", \
"<span class='notice'> You have loosened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 0
else
usr << "<span class='warning'>You cannot interface your modules [src]!</span>"
+204
View File
@@ -0,0 +1,204 @@
/obj/structure/foodcart
name = "food cart"
desc = "A cart for transporting food and drinks."
icon = 'icons/obj/foodcart.dmi'
icon_state = "cart"
anchored = 0
density = 1
//Food slots
var/list/food_slots[6]
//var/obj/item/weapon/reagent_containers/food/snacks/food1 = null
//var/obj/item/weapon/reagent_containers/food/snacks/food2 = null
//var/obj/item/weapon/reagent_containers/food/snacks/food3 = null
//var/obj/item/weapon/reagent_containers/food/snacks/food4 = null
//var/obj/item/weapon/reagent_containers/food/snacks/food5 = null
//var/obj/item/weapon/reagent_containers/food/snacks/food6 = null
//Drink slots
var/list/drink_slots[6]
//var/obj/item/weapon/reagent_containers/food/drinks/drink1 = null
//var/obj/item/weapon/reagent_containers/food/drinks/drink2 = null
//var/obj/item/weapon/reagent_containers/food/drinks/drink3 = null
//var/obj/item/weapon/reagent_containers/food/drinks/drink4 = null
//var/obj/item/weapon/reagent_containers/food/drinks/drink5 = null
//var/obj/item/weapon/reagent_containers/food/drinks/drink6 = null
/obj/structure/foodcart/proc/put_in_cart(obj/item/I, mob/user)
user.drop_item()
I.loc = src
updateUsrDialog()
user << "<span class='notice'>You put [I] into [src].</span>"
return
/obj/structure/foodcart/attackby(obj/item/I, mob/user)
var/fail_msg = "<span class='notice'>There are no open spaces for this in [src].</span>"
if(!I.is_robot_module())
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
var/success = 0
for(var/s=1,s<=6,s++)
if(!food_slots[s])
put_in_cart(I, user)
food_slots[s]=I
update_icon()
success = 1
break;
if(!success)
user << fail_msg
else if(istype(I, /obj/item/weapon/reagent_containers/food/drinks))
var/success = 0
for(var/s=1,s<=6,s++)
if(!drink_slots[s])
put_in_cart(I, user)
drink_slots[s]=I
update_icon()
success = 1
break;
if(!success)
user << fail_msg
else if(istype(I, /obj/item/weapon/wrench))
if (!anchored && !isinspace())
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] tightens \the [src]'s casters.", \
"<span class='notice'> You have tightened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 1
else if(anchored)
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] loosens \the [src]'s casters.", \
"<span class='notice'> You have loosened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 0
else
usr << "<span class='warning'>You cannot interface your modules [src]!</span>"
/obj/structure/foodcart/attack_hand(mob/user)
user.set_machine(src)
var/dat
if(food_slots[1])
dat += "<a href='?src=\ref[src];f1=1'>[food_slots[1]]</a><br>"
if(food_slots[2])
dat += "<a href='?src=\ref[src];f2=1'>[food_slots[2]]</a><br>"
if(food_slots[3])
dat += "<a href='?src=\ref[src];f3=1'>[food_slots[3]]</a><br>"
if(food_slots[4])
dat += "<a href='?src=\ref[src];f4=1'>[food_slots[4]]</a><br>"
if(food_slots[5])
dat += "<a href='?src=\ref[src];f5=1'>[food_slots[5]]</a><br>"
if(food_slots[6])
dat += "<a href='?src=\ref[src];f6=1'>[food_slots[6]]</a><br>"
if(drink_slots[1])
dat += "<a href='?src=\ref[src];d1=1'>[drink_slots[1]]</a><br>"
if(drink_slots[2])
dat += "<a href='?src=\ref[src];d2=1'>[drink_slots[2]]</a><br>"
if(drink_slots[3])
dat += "<a href='?src=\ref[src];d3=1'>[drink_slots[3]]</a><br>"
if(drink_slots[4])
dat += "<a href='?src=\ref[src];d4=1'>[drink_slots[4]]</a><br>"
if(drink_slots[5])
dat += "<a href='?src=\ref[src];d5=1'>[drink_slots[5]]</a><br>"
if(drink_slots[6])
dat += "<a href='?src=\ref[src];d6=1'>[drink_slots[6]]</a><br>"
var/datum/browser/popup = new(user, "foodcart", name, 240, 160)
popup.set_content(dat)
popup.open()
/obj/structure/foodcart/Topic(href, href_list)
if(!in_range(src, usr))
return
if(!isliving(usr))
return
var/mob/living/user = usr
if(href_list["f1"])
if(food_slots[1])
user.put_in_hands(food_slots[1])
user << "<span class='notice'>You take [food_slots[1]] from [src].</span>"
food_slots[1] = null
if(href_list["f2"])
if(food_slots[2])
user.put_in_hands(food_slots[2])
user << "<span class='notice'>You take [food_slots[2]] from [src].</span>"
food_slots[2] = null
if(href_list["f3"])
if(food_slots[3])
user.put_in_hands(food_slots[3])
user << "<span class='notice'>You take [food_slots[3]] from [src].</span>"
food_slots[3] = null
if(href_list["f4"])
if(food_slots[4])
user.put_in_hands(food_slots[4])
user << "<span class='notice'>You take [food_slots[4]] from [src].</span>"
food_slots[4] = null
if(href_list["f5"])
if(food_slots[5])
user.put_in_hands(food_slots[5])
user << "<span class='notice'>You take [food_slots[5]] from [src].</span>"
food_slots[5] = null
if(href_list["f6"])
if(food_slots[6])
user.put_in_hands(food_slots[6])
user << "<span class='notice'>You take [food_slots[6]] from [src].</span>"
food_slots[6] = null
if(href_list["d1"])
if(drink_slots[1])
user.put_in_hands(drink_slots[1])
user << "<span class='notice'>You take [drink_slots[1]] from [src].</span>"
drink_slots[1] = null
if(href_list["d2"])
if(drink_slots[2])
user.put_in_hands(drink_slots[2])
user << "<span class='notice'>You take [drink_slots[2]] from [src].</span>"
drink_slots[2] = null
if(href_list["d3"])
if(drink_slots[3])
user.put_in_hands(drink_slots[3])
user << "<span class='notice'>You take [drink_slots[3]] from [src].</span>"
drink_slots[3] = null
if(href_list["d4"])
if(drink_slots[4])
user.put_in_hands(drink_slots[4])
user << "<span class='notice'>You take [drink_slots[4]] from [src].</span>"
drink_slots[4] = null
if(href_list["d5"])
if(drink_slots[5])
user.put_in_hands(drink_slots[5])
user << "<span class='notice'>You take [drink_slots[5]] from [src].</span>"
drink_slots[5] = null
if(href_list["d6"])
if(drink_slots[6])
user.put_in_hands(drink_slots[6])
user << "<span class='notice'>You take [drink_slots[6]] from [src].</span>"
drink_slots[6] = null
update_icon() //Not really needed without overlays, but keeping just in case
updateUsrDialog()
/*
Overlays for cart_unused
/obj/structure/foodcart/update_icon()
overlays = null
if(food1)
overlays += "cart_food1"
if(food2)
overlays += "cart_food2"
if(food3)
overlays += "cart_food3"
if(food4)
overlays += "cart_food4"
if(food5)
overlays += "cart_food5"
if(food6)
overlays += "cart_food6"
if(drink1)
overlays += "cart_drink1"
if(drink2)
overlays += "cart_drink2"
if(drink3)
overlays += "cart_drink3"
if(drink4)
overlays += "cart_drink4"
if(drink5)
overlays += "cart_drink5"
if(drink6)
overlays += "cart_drink6"
*/
@@ -34,14 +34,6 @@
update_nearby_tiles()
..()
proc/update_nearby_tiles(need_rebuild) //Copypasta from airlock code
if(!air_master)
return 0
air_master.mark_for_update(get_turf(src))
return 1
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return 0
+17 -2
View File
@@ -482,14 +482,29 @@
update_icon()
else
user << "<span class='notice'>[src] can't hold any more signs.</span>"
else if(mybag)
mybag.attackby(I, user)
else if(istype(I, /obj/item/weapon/crowbar))
user.visible_message("<span class='warning'>[user] begins to empty the contents of [src].</span>")
if(do_after(user, 30))
usr << "<span class='notice'>You empty the contents of [src]'s bucket onto the floor.</span>"
reagents.reaction(src.loc)
src.reagents.clear_reagents()
else if(istype(I, /obj/item/weapon/wrench))
if (!anchored && !isinspace())
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] tightens \the [src]'s casters.", \
"<span class='notice'> You have tightened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 1
else if(anchored)
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user.visible_message( \
"[user] loosens \the [src]'s casters.", \
"<span class='notice'> You have loosened \the [src]'s casters.</span>", \
"You hear ratchet.")
anchored = 0
else if(mybag)
mybag.attackby(I, user)
else
usr << "<span class='warning'>You cannot interface your modules [src]!</span>"
@@ -157,13 +157,6 @@
CheckHardness()
return
proc/update_nearby_tiles(need_rebuild) //Copypasta from airlock code
if(!air_master) return 0
air_master.mark_for_update(get_turf(src))
return 1
/obj/structure/mineral_door/iron
mineralType = "metal"
hardness = 3
@@ -27,13 +27,6 @@ obj/structure/windoor_assembly
var/secure = 0 //Whether or not this creates a secure windoor
var/state = "01" //How far the door assembly has progressed
/obj/structure/windoor_assembly/proc/update_nearby_tiles(need_rebuild)
if(!air_master) return 0
air_master.mark_for_update(loc)
return 1
obj/structure/windoor_assembly/New(dir=NORTH)
..()
src.ini_dir = src.dir
+12 -20
View File
@@ -65,7 +65,7 @@ var/global/wcColored
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window destroyed by [Proj.firer.name] ([formatPlayerPanel(Proj.firer,Proj.firer.ckey)]) via \an [Proj]! pdiff = [pdiff] at [formatJumpTo(loc)]!")
msg_admin_attack("Window destroyed by [Proj.firer.name] ([formatPlayerPanel(Proj.firer,Proj.firer.ckey)]) via \an [Proj]! pdiff = [pdiff] at [formatJumpTo(loc)]!")
log_admin("Window destroyed by ([Proj.firer.ckey]) via \an [Proj]! pdiff = [pdiff] at [loc]!")
destroy()
return
@@ -135,19 +135,19 @@ var/global/wcColored
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
if(M)
message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
log_admin("Window with pdiff [pdiff] at [loc] deanchored by [M.real_name] ([M.ckey])!")
else
message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [AM]!")
msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] deanchored by [AM]!")
log_admin("Window with pdiff [pdiff] at [loc] deanchored by [AM]!")
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
if(M)
message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [M.real_name] ([formatPlayerPanel(M,M.ckey)])!")
log_admin("Window with pdiff [pdiff] at [loc] destroyed by [M.real_name] ([M.ckey])!")
else
message_admins("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [AM]!")
msg_admin_attack("Window with pdiff [pdiff] at [formatJumpTo(loc)] destroyed by [AM]!")
log_admin("Window with pdiff [pdiff] at [loc] destroyed by [AM]!")
destroy()
@@ -158,7 +158,7 @@ var/global/wcColored
user.visible_message("<span class='danger'>[user] smashes through [src]!</span>")
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window destroyed by hulk [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
msg_admin_attack("Window destroyed by hulk [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
log_admin("Window destroyed by hulk [user.real_name] ([user.ckey]) with pdiff [pdiff] at [loc]!")
destroy()
else if (usr.a_intent == "harm")
@@ -183,7 +183,7 @@ var/global/wcColored
user.visible_message("<span class='danger'>[user] smashes through [src]!</span>")
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window destroyed by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
msg_admin_attack("Window destroyed by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) with pdiff [pdiff] at [formatJumpTo(loc)]!")
destroy()
else //for nicer text~
user.visible_message("<span class='danger'>[user] smashes into [src]!</span>")
@@ -240,7 +240,7 @@ var/global/wcColored
return
if(W.flags & NOBLUDGEON) return
if(istype(W, /obj/item/weapon/screwdriver))
if(reinf && state >= 1)
state = 3 - state
@@ -254,7 +254,7 @@ var/global/wcColored
if(!anchored)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else if(!reinf)
anchored = !anchored
@@ -264,7 +264,7 @@ var/global/wcColored
if(!anchored)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else if(istype(W, /obj/item/weapon/crowbar) && reinf && state <= 1)
state = 1 - state
@@ -305,7 +305,7 @@ var/global/wcColored
step(src, get_dir(user, src))
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
msg_admin_attack("Window with pdiff [pdiff] deanchored by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)]!")
log_admin("Window with pdiff [pdiff] deanchored by [user.real_name] ([user.ckey]) at [loc]!")
else
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
@@ -325,7 +325,7 @@ var/global/wcColored
if(health <= 0)
var/pdiff=performWallPressureCheck(src.loc)
if(pdiff>0)
message_admins("Window with pdiff [pdiff] broken at [formatJumpTo(loc)]!")
msg_admin_attack("Window with pdiff [pdiff] broken at [formatJumpTo(loc)]!")
destroy()
return
@@ -403,14 +403,6 @@ var/global/wcColored
dir = ini_dir
update_nearby_tiles(need_rebuild=1)
//This proc has to do with airgroups and atmos, it has nothing to do with smoothwindows, that's update_nearby_tiles().
/obj/structure/window/proc/update_nearby_tiles(need_rebuild)
if(!air_master) return 0
air_master.mark_for_update(get_turf(src))
return 1
//checks if this window is full-tile one
/obj/structure/window/proc/is_fulltile()
if(dir & (dir - 1))
+2 -3
View File
@@ -210,15 +210,14 @@ var/list/mechtoys = list(
if(slip.stamped && slip.stamped.len) //yes, the clown stamp will work. clown is the highest authority on the station, it makes sense
points += points_per_slip
find_slip = 0
continue
// Sell phoron
if(istype(A, /obj/item/stack/sheet/mineral/plasma))
else if(istype(A, /obj/item/stack/sheet/mineral/plasma))
var/obj/item/stack/sheet/mineral/plasma/P = A
plasma_count += P.amount
// Sell platinum
if(istype(A, /obj/item/stack/sheet/mineral/platinum))
else if(istype(A, /obj/item/stack/sheet/mineral/platinum))
var/obj/item/stack/sheet/mineral/platinum/P = A
plat_count += P.amount
+1 -1
View File
@@ -1025,7 +1025,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/meson/cyber(M), slot_glasses)
M.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(M), slot_wear_mask)
M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/singuloth(M), slot_head)
M.equip_to_slot_or_del(new /obj/item/weapon/claymore(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/weapon/claymore/ceremonial(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/weapon/tank/oxygen(M), slot_s_store)
M.equip_to_slot_or_del(new /obj/item/weapon/twohanded/knighthammer(M), slot_back)
+2 -2
View File
@@ -52,7 +52,7 @@ var/intercom_range_display_status = 0
del(C)
if(camera_range_display_status)
for(var/obj/machinery/camera/C in cameranet.viewpoints)
for(var/obj/machinery/camera/C in cameranet.cameras)
new/obj/effect/debugging/camera_range(C.loc)
feedback_add_details("admin_verb","mCRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -68,7 +68,7 @@ var/intercom_range_display_status = 0
var/list/obj/machinery/camera/CL = list()
for(var/obj/machinery/camera/C in cameranet.viewpoints)
for(var/obj/machinery/camera/C in cameranet.cameras)
CL += C
var/output = {"<B>CAMERA ANOMALIES REPORT</B><HR>
+1 -1
View File
@@ -45,7 +45,7 @@
if(!status)
status = 1
bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
msg_admin_attack("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
user << "<span class='notice'>A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited.</span>"
else
status = 0
+1 -1
View File
@@ -186,7 +186,7 @@
firstquery.Execute()
while(firstquery.NextRow())
if(text2num(firstquery.item[1]) == default_slot)
var/DBQuery/query = dbcon.NewQuery("UPDATE characters SET OOC_Notes='[sql_sanitize_text(metadata)]',real_name='[sql_sanitize_text(real_name)]',name_is_always_random='[be_random_name]',gender='[gender]',age='[age]',species='[sql_sanitize_text(species)]',language='[sql_sanitize_text(language)]',hair_red='[r_hair]',hair_green='[g_hair]',hair_blue='[b_hair]',facial_red='[r_facial]',facial_green='[g_facial]',facial_blue='[b_facial]',skin_tone='[s_tone]',skin_red='[r_skin]',skin_green='[g_skin]',skin_blue='[b_skin]',hair_style_name='[sql_sanitize_text(h_style)]',facial_style_name='[sql_sanitize_text(f_style)]',eyes_red='[r_eyes]',eyes_green='[g_eyes]',eyes_blue='[b_eyes]',underwear='[underwear]',undershirt='[undershirt]',backbag='[backbag]',b_type='[b_type]',alternate_option='[alternate_option]',job_support_high='[job_support_high]',job_support_med='[job_support_med]',job_support_low='[job_support_low]',job_medsci_high='[job_medsci_high]',job_medsci_med='[job_medsci_med]',job_medsci_low='[job_medsci_low]',job_engsec_high='[job_engsec_high]',job_engsec_med='[job_engsec_med]',job_engsec_low='[job_engsec_low]',job_karma_high='[job_karma_high]',job_karma_med='[job_karma_med]',job_karma_low='[job_karma_low]',flavor_text='[sql_sanitize_text(flavor_text)]',med_record='[sql_sanitize_text(med_record)]',sec_record='[sql_sanitize_text(sec_record)]',gen_record='[sql_sanitize_text(gen_record)]',player_alt_titles='[sql_sanitize_text(playertitlelist)]',be_special='[be_special]',disabilities='[disabilities]',organ_data='[organlist]',nanotrasen_relation='[nanotrasen_relation]', speciesprefs='[speciesprefs]' WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
var/DBQuery/query = dbcon.NewQuery("UPDATE characters SET OOC_Notes='[sql_sanitize_text(metadata)]',real_name='[sql_sanitize_text(real_name)]',name_is_always_random='[be_random_name]',gender='[gender]',age='[age]',species='[sql_sanitize_text(species)]',language='[sql_sanitize_text(language)]',hair_red='[r_hair]',hair_green='[g_hair]',hair_blue='[b_hair]',facial_red='[r_facial]',facial_green='[g_facial]',facial_blue='[b_facial]',skin_tone='[s_tone]',skin_red='[r_skin]',skin_green='[g_skin]',skin_blue='[b_skin]',hair_style_name='[sql_sanitize_text(h_style)]',facial_style_name='[sql_sanitize_text(f_style)]',eyes_red='[r_eyes]',eyes_green='[g_eyes]',eyes_blue='[b_eyes]',underwear='[underwear]',undershirt='[undershirt]',backbag='[backbag]',b_type='[b_type]',alternate_option='[alternate_option]',job_support_high='[job_support_high]',job_support_med='[job_support_med]',job_support_low='[job_support_low]',job_medsci_high='[job_medsci_high]',job_medsci_med='[job_medsci_med]',job_medsci_low='[job_medsci_low]',job_engsec_high='[job_engsec_high]',job_engsec_med='[job_engsec_med]',job_engsec_low='[job_engsec_low]',job_karma_high='[job_karma_high]',job_karma_med='[job_karma_med]',job_karma_low='[job_karma_low]',flavor_text='[sql_sanitize_text(flavor_text)]',med_record='[sql_sanitize_text(med_record)]',sec_record='[sql_sanitize_text(sec_record)]',gen_record='[sql_sanitize_text(gen_record)]',player_alt_titles='[playertitlelist]',be_special='[be_special]',disabilities='[disabilities]',organ_data='[organlist]',nanotrasen_relation='[nanotrasen_relation]', speciesprefs='[speciesprefs]' WHERE ckey='[C.ckey]' AND slot='[default_slot]'")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during character slot saving. Error : \[[err]\]\n")
+15 -1
View File
@@ -26,4 +26,18 @@
/obj/item/clothing/suit/storage/hear_talk(mob/M, var/msg)
pockets.hear_talk(M, msg)
..()
..()
/obj/item/clothing/suit/storage/proc/return_inv()
var/list/L = list( )
L += src.contents
for(var/obj/item/weapon/storage/S in src)
L += S.return_inv()
for(var/obj/item/weapon/gift/G in src)
L += G.gift
if (istype(G.gift, /obj/item/weapon/storage))
L += G.gift:return_inv()
return L
@@ -40,6 +40,20 @@
hold.hear_talk(M, msg, verb, speaking)
..()
/obj/item/clothing/accessory/storage/proc/return_inv()
var/list/L = list( )
L += src.contents
for(var/obj/item/weapon/storage/S in src)
L += S.return_inv()
for(var/obj/item/weapon/gift/G in src)
L += G.gift
if (istype(G.gift, /obj/item/weapon/storage))
L += G.gift:return_inv()
return L
/obj/item/clothing/accessory/storage/attack_self(mob/user as mob)
if (has_suit) //if we are part of a suit
hold.open(user)
+2 -2
View File
@@ -185,12 +185,12 @@
return null
var/list/L = list()
for(var/obj/machinery/camera/C in cameranet.viewpoints)
for(var/obj/machinery/camera/C in cameranet.cameras)
var/list/temp = C.network & key.networks
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)
+2 -3
View File
@@ -68,8 +68,7 @@
for (var/mob/living/silicon/ai/aiPlayer in player_list)
if (aiPlayer.client)
var/law = ""
aiPlayer.set_zeroth_law(law)
aiPlayer.clear_zeroth_law()
aiPlayer << "\red <b>You have detected a change in your laws information:</b>"
aiPlayer << "Laws Updated: [law]"
aiPlayer << "Laws Updated: Zeroth law removed."
..()
+57 -12
View File
@@ -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)
@@ -406,7 +406,7 @@ var/list/ai_list = list()
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in cameranet.viewpoints
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
//Carn: holopad requests
@@ -584,15 +584,14 @@ var/list/ai_list = list()
if(control_disabled)
src << "Wireless communication is disabled."
return
var/turf/ai_current_turf = get_turf(src)
var/ai_Zlevel = ai_current_turf.z
var/ai_allowed_Zlevel = list(1,3,5)
var/d
var/area/bot_area
d += "<A HREF=?src=\ref[src];botrefresh=\ref[Bot]>Query network status</A><br>"
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='20%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
for (Bot in aibots)
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
if((Bot.z in ai_allowed_Zlevel) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
bot_area = get_area(Bot)
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.bot_type_name])</td>"
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
@@ -631,8 +630,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 +703,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)
@@ -715,11 +711,11 @@ var/list/ai_list = list()
var/mob/living/silicon/ai/U = usr
for (var/obj/machinery/camera/C in cameranet.viewpoints)
for (var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
var/list/tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS,1)
var/list/tempnetwork = difflist(C.network,restricted_camera_networks,1)
if(tempnetwork.len)
for(var/i in tempnetwork)
cameralist[i] = i
@@ -733,7 +729,7 @@ var/list/ai_list = list()
if(isnull(network))
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in cameranet.viewpoints)
for(var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
if(network in C.network)
@@ -912,3 +908,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
@@ -1,25 +1,156 @@
/datum/visibility_network/cameras
ChunkType = /datum/visibility_chunk/camera
// CAMERA NET
//
// The datum containing all the chunks.
/datum/visibility_network/cameras/getViewpointFromMob(var/mob/currentMob)
var/mob/living/silicon/robot/currentRobot=currentMob
if(currentRobot)
return currentRobot.camera
return FALSE
var/datum/cameranet/cameranet = new()
/datum/visibility_network/cameras/validViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
if (!c)
return FALSE
return c.can_use()
/datum/cameranet
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
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
// adding some indirection so that I don't have to edit a ton of files
/datum/visibility_network/cameras/proc/addCamera(var/camera)
return addViewpoint(camera)
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
return (chunks[key])
/datum/visibility_network/cameras/proc/removeCamera(var/camera)
return removeViewpoint(camera)
// 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
var/key = "[x],[y],[z]"
if(!chunks[key])
chunks[key] = new /datum/camerachunk(null, x, y, z)
/datum/visibility_network/cameras/proc/checkCameraVis(var/atom/target)
return checkCanSee(target)
return chunks[key]
// 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)
// 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/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
visibleChunks += getCameraChunk(x, y, ai.z)
var/list/remove = ai.visibleCameraChunks - visibleChunks
var/list/add = visibleChunks - ai.visibleCameraChunks
for(var/chunk in remove)
var/datum/camerachunk/c = chunk
c.remove(ai)
for(var/chunk in add)
var/datum/camerachunk/c = chunk
c.add(ai)
// 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)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/cameranet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
chunk.hasChanged()
// Removes a camera from a chunk.
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
//else
// majorChunkChange(c, 0)
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
/datum/cameranet/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
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
//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)
if(chunkGenerated(x, y, T.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
if(choice == 0)
// Remove the camera.
chunk.cameras -= c
else if(choice == 1)
// You can't have the same camera in the list twice.
chunk.cameras |= c
chunk.hasChanged()
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)
// 0xf = 15
var/turf/position = get_turf(target)
return checkTurfVis(position)
/datum/cameranet/proc/checkTurfVis(var/turf/position)
var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(chunk.visibleTurfs[position])
return 1
return 0
// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
set src in world
if(cameranet.chunkGenerated(x, y, z))
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
@@ -1,23 +1,168 @@
/datum/visibility_chunk/camera
#define UPDATE_BUFFER 25 // 2.5 seconds
/datum/visibility_chunk/camera/validViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
if(!c)
return FALSE
if(!c.can_use())
return FALSE
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, c) > 24)
return FALSE
return TRUE
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the AI Eye to stream these chunks and know what it can and cannot see.
/datum/camerachunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/cameras = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
/datum/visibility_chunk/camera/getVisibleTurfsForViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
return c.can_see()
// 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
visible++
seenby += ai
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
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/camerachunk/proc/visibilityChanged(turf/loc)
if(!visibleTurfs[loc])
return
hasChanged()
// 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)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
/datum/camerachunk/proc/update()
set background = 1
var/list/newVisibleTurfs = list()
for(var/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, c) > 24)
continue
for(var/turf/t in c.can_see())
newVisibleTurfs[t] = t
// Removes turf that isn't in turfs.
newVisibleTurfs &= turfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
for(var/turf in visAdded)
var/turf/t = turf
if(t.obscured)
obscured -= t.obscured
for(var/eye in seenby)
var/mob/aiEye/m = eye
if(!m || !m.ai)
continue
if(m.ai.client)
m.ai.client.images -= t.obscured
for(var/turf in visRemoved)
var/turf/t = turf
if(obscuredTurfs[t])
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/eye in seenby)
var/mob/aiEye/m = eye
if(!m || !m.ai)
seenby -= m
continue
if(m.ai.client)
m.ai.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
src.x = x
src.y = y
src.z = z
/datum/visibility_chunk/camera/findNearbyViewpoints()
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
viewpoints += c
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/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
for(var/turf/t in c.can_see())
visibleTurfs[t] = t
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
obscuredTurfs = turfs - visibleTurfs
for(var/turf in obscuredTurfs)
var/turf/t = turf
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
#undef UPDATE_BUFFER
@@ -1,13 +1,12 @@
// AI EYE
//
// A mob that the AI controls to look around the station with.
// 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
name = "Inactive AI Eye"
icon = 'icons/mob/AI.dmi'
icon_state = "eye"
alpha = 127
icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
density = 0
status_flags = GODMODE // You can't damage it.
@@ -15,20 +14,16 @@
see_in_dark = 7
invisibility = INVISIBILITY_AI_EYE
/mob/aiEye/New()
..()
visibility_interface = new /datum/visibility_interface/ai_eye(src)
// Movement code. Returns 0 to stop air movement from moving it.
/mob/aiEye/Move()
return 0
// Hide popout menu verbs
/mob/aiEye/examine()
/mob/aiEye/examine(atom/A as mob|obj|turf in view())
set popup_menu = 0
set src = usr.contents
return 0
/mob/aiEye/pull()
set popup_menu = 0
set src = usr.contents
@@ -41,11 +36,15 @@
// 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/aiEye/setLoc(var/T)
if(ai)
if(!isturf(ai.loc))
return
if(cancel_tracking)
ai.ai_cancel_tracking()
T = get_turf(T)
loc = T
cameranet.visibility(src)
@@ -55,9 +54,12 @@
if(ai.holo)
ai.holo.move_hologram()
/mob/aiEye/proc/getLoc()
/mob/aiEye/Move()
return 0
if(ai)
if(!isturf(ai.loc) || !ai.client)
return
return ai.eyeobj.loc
// AI MOVEMENT
@@ -70,7 +72,6 @@
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()
..()
@@ -79,7 +80,7 @@
spawn(5)
eyeobj.loc = src.loc
/mob/living/silicon/ai/Destroy()
/mob/living/silicon/ai/Del()
eyeobj.ai = null
del(eyeobj) // No AI, no Eye
..()
@@ -88,9 +89,7 @@
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && AI.client.eye == AI.eyeobj)
AI.cameraFollow = null
if (isturf(src.loc) || isturf(src))
AI.eyeobj.setLoc(src)
AI.eyeobj.setLoc(src)
// 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.
@@ -114,23 +113,24 @@
else
user.sprint = initial
user.cameraFollow = null
//user.unset_machine() //Uncomment this if it causes problems.
//user.lightNearbyCamera()
// Return to the Core.
/mob/living/silicon/ai/proc/view_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 && src.loc)
src.eyeobj.z = src.z
src.eyeobj.loc = src.loc
else
if(!src.eyeobj)
src << "ERROR: Eyeobj not found. Creating new eye..."
src.eyeobj = new(src.loc)
src.eyeobj.ai = src
@@ -138,11 +138,11 @@
if(client && client.eye)
client.eye = src
for(var/datum/visibility_chunk/camera/c in eyeobj.visibility_interface.visible_chunks)
for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
c.remove(eyeobj)
src.eyeobj.setLoc(src)
/mob/living/silicon/ai/verb/toggle_acceleration()
/mob/living/silicon/ai/proc/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
@@ -20,7 +20,7 @@
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Destroy().
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Del().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
@@ -43,7 +43,7 @@
WHERE IS EVERYTHING?
cameraNetwork.dm = Everything about the cameraNetwork datum.
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
@@ -1,3 +1,80 @@
#define BORG_CAMERA_BUFFER 30
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/turf
var/image/obscured
/turf/proc/visibilityChanged()
if(ticker)
cameranet.updateVisibility(src)
/turf/simulated/Del()
visibilityChanged()
..()
/turf/simulated/New()
..()
visibilityChanged()
// STRUCTURES
/obj/structure/Del()
if(ticker)
cameranet.updateVisibility(src)
..()
/obj/structure/New()
..()
if(ticker)
cameranet.updateVisibility(src)
// EFFECTS
/obj/effect/Del()
if(ticker)
cameranet.updateVisibility(src)
..()
/obj/effect/New()
..()
if(ticker)
cameranet.updateVisibility(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/update_nearby_tiles(need_rebuild)
. = ..(need_rebuild)
// Glass door glass = 1
// don't check then?
if(!glass && cameranet)
cameranet.updateVisibility(src, 0)
// ROBOT MOVEMENT
// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/robot/var/updating = 0
/mob/living/silicon/robot/Move()
var/oldLoc = src.loc
. = ..()
if(.)
if(src.camera && src.camera.network.len)
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(oldLoc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
@@ -5,23 +82,29 @@
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
cameranet.addViewpoint(src)
cameranet.addCamera(src)
else
src.SetLuminosity(0)
cameranet.removeViewpoint(src)
cameranet.removeCamera(src)
/obj/machinery/camera/New()
..()
cameranet.viewpoints += src //Camera must be added to global list of all cameras no matter what...
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.
//Camera must be added to global list of all cameras no matter what...
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.addViewpoint(src)
cameranet.addCamera(src)
/obj/machinery/camera/Del()
cameranet.viewpoints -= src
var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS)
cameranet.cameras -= src
var/list/open_networks = difflist(network,restricted_camera_networks)
if(open_networks.len)
cameranet.removeViewpoint(src)
cameranet.removeCamera(src)
..()
#undef BORG_CAMERA_BUFFER
@@ -1,10 +0,0 @@
/datum/visibility_interface/ai_eye
chunk_type = /datum/visibility_chunk/camera
/datum/visibility_interface/ai_eye/getClient()
var/mob/aiEye/eye = controller
if (!eye)
return FALSE
if (!eye.ai)
return FALSE
return eye.ai.client
@@ -23,6 +23,10 @@
/mob/living/silicon/ai/proc/set_zeroth_law(var/law, var/law_borg)
src.laws_sanity_check()
src.laws.set_zeroth_law(law, law_borg)
/mob/living/silicon/ai/proc/clear_zeroth_law(var/law_borg)
src.laws_sanity_check()
src.laws.clear_zeroth_law(law_borg)
/mob/living/silicon/ai/proc/add_inherent_law(var/law)
src.laws_sanity_check()
@@ -77,6 +77,10 @@
laws_sanity_check()
laws.set_zeroth_law(law)
/mob/living/silicon/robot/proc/clear_zeroth_law()
laws_sanity_check()
laws.clear_zeroth_law()
/mob/living/silicon/robot/proc/add_inherent_law(var/law)
laws_sanity_check()
laws.add_inherent_law(law)
@@ -30,4 +30,4 @@
icon_living = "Syndifox"
icon_dead = "Syndifox_dead"
flags = IS_SYNTHETIC|NO_BREATHE
faction = list("syndicate")
faction = list("syndicate")
+5 -3
View File
@@ -57,18 +57,20 @@
client.verbs |= H.species.abilities
CallHook("Login", list("client" = src.client, "mob" = src))
//Update morgues on login/logout
if (stat == DEAD)
var/obj/structure/morgue/Morgue = null
var/mob/living/carbon/human/C = null
if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse
var/mob/dead/observer/G = src
if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control.
return
if (G.can_reenter_corpse && G.mind.current)
C = G.mind.current
else if (istype(src,/mob/living/carbon/human))
C = src
if (C) //We found our corpse, is it inside a morgue?
if (istype(C.loc,/obj/structure/morgue))
Morgue = C.loc
@@ -78,4 +80,4 @@
Morgue = B.loc
if (Morgue)
Morgue.update()
+4 -2
View File
@@ -10,18 +10,20 @@
if(admins_number == 0) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell.
send2adminirc("[key_name(src)] logged out - no more admins online.")
..()
//Update morgues on login/logout
if (stat == DEAD)
var/obj/structure/morgue/Morgue = null
var/mob/living/carbon/human/C = null
if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse
var/mob/dead/observer/G = src
if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control.
return 1
if (G.can_reenter_corpse && G.mind.current)
C = G.mind.current
else if (istype(src,/mob/living/carbon/human))
C = src
if (C) //We found our corpse, is it inside a morgue?
if (istype(C.loc,/obj/structure/morgue))
Morgue = C.loc
+8
View File
@@ -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)
-48
View File
@@ -19,54 +19,6 @@ It reuses a lot of code from the AIEye cameraNetwork. In order to work properly,
if (vp)
return TRUE
return FALSE
/datum/visibility_chunk/cult/validViewpoint(var/atom/viewpoint)
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, viewpoint) > 24)
return FALSE
if (isCultRune(viewpoint) || isCultViewpoint(viewpoint))
return viewpoint:can_use()
return FALSE
/datum/visibility_chunk/cult/getVisibleTurfsForViewpoint(var/viewpoint)
var/obj/effect/rune/rune = viewpoint
if (rune)
return rune.can_see()
var/obj/cult_viewpoint/cvp = viewpoint
if (cvp)
return cvp.can_see()
return null
/datum/visibility_chunk/cult/findNearbyViewpoints()
for(var/obj/cult_viewpoint/vp in range(16, locate(x + 8, y + 8, z)))
if(vp.can_use())
viewpoints += vp
for(var/obj/effect/rune/rune in range(16, locate(x + 8, y + 8, z)))
viewpoints += rune
/datum/visibility_network/cult
ChunkType = /datum/visibility_chunk/cult
/datum/visibility_network/cult/validViewpoint(var/viewpoint)
if (isCultRune(viewpoint) || isCultViewpoint(viewpoint))
return viewpoint:can_use()
return FALSE
/datum/visibility_network/cult/getViewpointFromMob(var/mob/currentMob)
for(var/obj/cult_viewpoint/currentView in currentMob)
return currentView
return FALSE
/datum/visibility_interface/cult
chunk_type = /datum/visibility_chunk/cult
/*
RUNE JUNK
-1
View File
@@ -52,7 +52,6 @@ mob/spirit/proc/Spirit_Move(direct)
mob/spirit/setLoc(var/T)
T = get_turf(T)
loc = T
cultNetwork.visibility(src)
mob/spirit/verb/toggle_acceleration()
set category = "Spirit"
-3
View File
@@ -38,9 +38,6 @@ mob/spirit/New()
loc = pick(latejoin)
// hook them to the cult visibility network
visibility_interface = new /datum/visibility_interface/cult(src)
// no nameless spirits
if (!name)
name = "Boogyman"
+2 -6
View File
@@ -18,9 +18,6 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/New(var/mob/target)
owner = target
//src.loc = owner
owner.addToVisibilityNetwork(cultNetwork)
cultNetwork.viewpoints+=src
cultNetwork.addViewpoint(src)
cult_viewpoints+=src
//handle_missing_mask()
..()
@@ -28,10 +25,7 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/Del()
processing_objects.Remove(src)
cultNetwork.viewpoints-=src
cultNetwork.removeViewpoint(src)
cult_viewpoints-=src
owner.removeFromVisibilityNetwork(cultNetwork)
..()
return
@@ -134,6 +128,8 @@ var/obj/cult_viewpoint/list/cult_viewpoints = list()
/obj/cult_viewpoint/proc/get_display_name()
if(istype(src,/obj/effect/rune))
return name
if (!owner)
return
if (cult_name)
+3 -1
View File
@@ -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)
+2 -2
View File
@@ -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)
+16 -2
View File
@@ -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
+2 -1
View File
@@ -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
+1 -1
View File
@@ -40,7 +40,7 @@
src.directwired = 1
/obj/machinery/power/emitter/Destroy()
message_admins("Emitter deleted at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
msg_admin_attack("Emitter deleted at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
log_game("Emitter deleted at ([x],[y],[z])")
investigate_log("<font color='red'>deleted</font> at ([x],[y],[z])","singulo")
..()
@@ -350,6 +350,6 @@ field_generator power level display
if(O.last_warning && temp)
if((world.time - O.last_warning) > 50) //to stop message-spam
temp = 0
message_admins("A singulo exists and a containment field has failed.",1)
msg_admin_attack("A singulo exists and a containment field has failed.",1)
investigate_log("has <font color='red'>failed</font> whilst a singulo exists.","singulo")
O.last_warning = world.time
+1 -1
View File
@@ -143,7 +143,7 @@
var/obj/item/device/assembly_holder/H = W
if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter))
message_admins("[key_name_admin(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
msg_admin_attack("[key_name_admin(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
log_game("[key_name(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.")
rig = W
+4 -2
View File
@@ -12,7 +12,8 @@
/datum/surgery_step/brain/saw_skull
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
/obj/item/weapon/hatchet = 75
/obj/item/weapon/hatchet = 75, \
/obj/item/weapon/melee/arm_blade = 60 // Dr. Chang E. Ling, MD
)
min_duration = 50
@@ -67,7 +68,8 @@
/datum/surgery_step/brain/saw_spine
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
/obj/item/weapon/hatchet = 75
/obj/item/weapon/hatchet = 75, \
/obj/item/weapon/melee/arm_blade = 60
)
min_duration = 50
+2 -1
View File
@@ -187,7 +187,8 @@
/datum/surgery_step/generic/cut_limb
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
/obj/item/weapon/hatchet = 75
/obj/item/weapon/hatchet = 75, \
/obj/item/weapon/melee/arm_blade = 60
)
min_duration = 110
+3 -2
View File
@@ -12,7 +12,8 @@
/datum/surgery_step/ribcage/saw_ribcage
allowed_tools = list(
/obj/item/weapon/circular_saw = 100, \
/obj/item/weapon/hatchet = 75
/obj/item/weapon/hatchet = 75, \
/obj/item/weapon/melee/arm_blade = 60
)
min_duration = 50
@@ -146,7 +147,7 @@
user.visible_message(msg, self_msg)
target.op_stage.ribcage = 0
//////////////////////////////////////////////////////////////////
// ALIEN EMBRYO SURGERY //
//////////////////////////////////////////////////////////////////
+10 -2
View File
@@ -798,11 +798,13 @@ var/list/cheartstopper = list("potassium_chloride") //this stops the heart when
#define GETPULSE_HAND 0 //less accurate (hand)
#define GETPULSE_TOOL 1 //more accurate (med scanner, sleeper, etc)
var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.
var/list/restricted_camera_networks = list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.
"CentCom",
"ERT",
"NukeOps",
"Thunderdome",
"UO45",
"UO45R",
"Xeno"
)
@@ -940,4 +942,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