diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index b7e2e501ce..4978c514b8 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -2,9 +2,7 @@ SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
-CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
CREATE SCHEMA IF NOT EXISTS `tgstation` DEFAULT CHARACTER SET latin1 ;
-USE `mydb` ;
USE `tgstation` ;
-- -----------------------------------------------------
diff --git a/baystation12.dme b/baystation12.dme
index d064eb19f4..8e69350ebe 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -161,11 +161,11 @@
#define FILE_DIR "code/unused/powerarmor"
#define FILE_DIR "code/unused/spacecraft"
#define FILE_DIR "code/WorkInProgress"
+#define FILE_DIR "code/WorkInProgress/AI_Visibility"
#define FILE_DIR "code/WorkInProgress/animusstation"
#define FILE_DIR "code/WorkInProgress/Apples"
#define FILE_DIR "code/WorkInProgress/Cael_Aislinn"
#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/BirdMan"
-#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Jumper"
#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Rust"
#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Supermatter"
#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Tajara"
@@ -616,7 +616,6 @@
#include "code\game\mecha\working\firefighter.dm"
#include "code\game\mecha\working\ripley.dm"
#include "code\game\mecha\working\working.dm"
-#include "code\game\objects\biomass.dm"
#include "code\game\objects\blood.dm"
#include "code\game\objects\bodybag.dm"
#include "code\game\objects\bombspawner.dm"
@@ -1143,10 +1142,15 @@
#include "code\modules\scripting\Scanner\Tokens.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security levels\security levels.dm"
-#include "code\WorkInProgress\AI_Visibility.dm"
#include "code\WorkInProgress\buildmode.dm"
#include "code\WorkInProgress\explosion_particles.dm"
+#include "code\WorkInProgress\AI_Visibility\ai.dm"
+#include "code\WorkInProgress\AI_Visibility\cameranet.dm"
+#include "code\WorkInProgress\AI_Visibility\chunk.dm"
+#include "code\WorkInProgress\AI_Visibility\minimap.dm"
+#include "code\WorkInProgress\AI_Visibility\util.dm"
#include "code\WorkInProgress\animusstation\atm.dm"
+#include "code\WorkInProgress\Cael_Aislinn\power_monitor.dm"
#include "code\WorkInProgress\Cael_Aislinn\BirdMan\bird_transformation.dm"
#include "code\WorkInProgress\Cael_Aislinn\BirdMan\birdman.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\core_field.dm"
diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
index 624a731e3e..0c8c8f4134 100755
--- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
@@ -108,8 +108,8 @@ Filter types:
else
filtered_out = null
-
- filtered_out.update_values()
+ if(filtered_out)
+ filtered_out.update_values()
air2.merge(filtered_out)
air3.merge(removed)
diff --git a/code/FEA/FEA_gas_mixture.dm b/code/FEA/FEA_gas_mixture.dm
index 1819129532..8edefe79d7 100644
--- a/code/FEA/FEA_gas_mixture.dm
+++ b/code/FEA/FEA_gas_mixture.dm
@@ -466,6 +466,8 @@ datum
//Outputs: 0 if the self-check failed (local airgroup breaks?)
// then -1 if sharer-check failed (sharing airgroup breaks?)
// then 1 if both checks pass (share succesful?)
+ if(!istype(sharer))
+ return
var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION
@@ -552,6 +554,10 @@ datum
//Inputs: Air datum to share with
//Outputs: Amount of gas exchanged (Negative if lost air, positive if gained.)
+
+ if(!istype(sharer))
+ return
+
var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION
var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION
diff --git a/code/FEA/FEA_turf_tile.dm b/code/FEA/FEA_turf_tile.dm
index fa4081b8af..38083f52ce 100644
--- a/code/FEA/FEA_turf_tile.dm
+++ b/code/FEA/FEA_turf_tile.dm
@@ -378,25 +378,24 @@ turf
enemy_tile.consider_pressure_difference(connection_difference, direction)
else
air_master.active_singletons -= src //not active if not processing!
+ if(air)
+ air.react()
- air.react()
+ if(active_hotspot)
+ if (!active_hotspot.process(possible_fire_spreads))
+ return 0
- if(active_hotspot)
- if (!active_hotspot.process(possible_fire_spreads))
- return 0
+ if(air.temperature > MINIMUM_TEMPERATURE_START_SUPERCONDUCTION)
+ consider_superconductivity(starting = 1)
- if(air.temperature > MINIMUM_TEMPERATURE_START_SUPERCONDUCTION)
- consider_superconductivity(starting = 1)
+ if(air.check_tile_graphic())
+ update_visuals(air)
- if(air.check_tile_graphic())
- update_visuals(air)
-
- if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
-// reset_delay() //hotspots always process quickly
- hotspot_expose(air.temperature, CELL_VOLUME)
- for(var/atom/movable/item in src)
- item.temperature_expose(air, air.temperature, CELL_VOLUME)
- temperature_expose(air, air.temperature, CELL_VOLUME)
+ if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ hotspot_expose(air.temperature, CELL_VOLUME)
+ for(var/atom/movable/item in src)
+ item.temperature_expose(air, air.temperature, CELL_VOLUME)
+ temperature_expose(air, air.temperature, CELL_VOLUME)
return 1
diff --git a/code/WorkInProgress/AI_Visibility.dm b/code/WorkInProgress/AI_Visibility/_old_AI_Visibility.dm
similarity index 96%
rename from code/WorkInProgress/AI_Visibility.dm
rename to code/WorkInProgress/AI_Visibility/_old_AI_Visibility.dm
index cf3eadb2b3..fb7aab4dd0 100644
--- a/code/WorkInProgress/AI_Visibility.dm
+++ b/code/WorkInProgress/AI_Visibility/_old_AI_Visibility.dm
@@ -1,573 +1,573 @@
-//All credit for this goes to Uristqwerty.
-
-//And some to me! -Mini
-
-
-
-//This file is partly designed around being able to uninclude it to go back to the old ai viewing system completely.
-//(And therefore also be portable to another similar codebase simply by transferring the file and including it after the other AI code files.)
-//There are probably a few parts that don't do that at the moment, but I'll fix them at some point.
-
-
-#define MINIMAP_UPDATE_DELAY 1200
-
-/turf
- var/image/obscured
- var/image/dim
-
-/turf/proc/visibilityChanged()
- cameranet.updateVisibility(src)
-
-/turf/New()
- ..()
- cameranet.updateVisibility(src)
-/*
-/turf/Del()
- ..()
- cameranet.updateVisibility(src)
-*/
-/datum/camerachunk
- var/list/obscuredTurfs = list()
- var/list/visibleTurfs = list()
- var/list/dimTurfs = list()
- var/list/obscured = list()
- var/list/dim = list()
- var/list/cameras = list()
- var/list/turfs = list()
- var/list/seenby = list()
- var/visible = 0
- var/changed = 1
- var/updating = 0
-
- var/x
- var/y
- var/z
-
- var/minimap_updating = 0
-
- var/icon/minimap_icon = new('minimap.dmi', "chunk_base")
- var/obj/minimap_obj/minimap_obj = new()
-
-/obj/minimap_obj/Click(location, control, params)
- if(!istype(usr, /mob/dead) && !istype(usr, /mob/living/silicon/ai) && !(usr.client && usr.client.holder && usr.client.holder.level >= 4))
- return
-
- var/list/par = params2list(params)
- var/screen_loc = par["screen-loc"]
-
- if(findtext(screen_loc, "minimap:") != 1)
- return
-
- screen_loc = copytext(screen_loc, length("minimap:") + 1)
-
- var/x_text = copytext(screen_loc, 1, findtext(screen_loc, ","))
- var/y_text = copytext(screen_loc, findtext(screen_loc, ",") + 1)
-
- var/x = (text2num(copytext(x_text, 1, findtext(x_text, ":"))) - 1) * 16
- x += round((text2num(copytext(x_text, findtext(x_text, ":") + 1)) + 1) / 2)
-
- var/y = (text2num(copytext(y_text, 1, findtext(y_text, ":"))) - 1) * 16
- y += round((text2num(copytext(y_text, findtext(y_text, ":") + 1)) + 1) / 2)
-
- if(istype(usr, /mob/living/silicon/ai))
- var/mob/living/silicon/ai/ai = usr
- ai.freelook()
- ai.eyeobj.loc = locate(max(1, x - 1), max(1, y - 1), ai.eyeobj.z)
- cameranet.visibility(ai.eyeobj)
-
- else
- usr.loc = locate(max(1, x - 1), max(1, y - 1), usr.z)
-
-/mob/dead/verb/Open_Minimap()
- set category = "Ghost"
- winshow(src, "minimapwindow", 1)
- client.screen |= cameranet.minimap
-
- if(cameranet.generating_minimap)
- cameranet.minimap_viewers += src
-
-/mob/living/silicon/ai/verb/Open_Minimap()
- set category = "AI Commands"
- winshow(src, "minimapwindow", 1)
- client.screen |= cameranet.minimap
-
- if(cameranet.generating_minimap)
- cameranet.minimap_viewers += src
-
-/client/proc/Open_Minimap()
- set category = "Admin"
- winshow(src, "minimapwindow", 1)
- screen |= cameranet.minimap
-
- if(cameranet.generating_minimap)
- cameranet.minimap_viewers += src.mob
-
-/datum/camerachunk/proc/update_minimap()
- if(changed && !updating)
- update()
-
- minimap_icon.Blend(rgb(255, 0, 0), ICON_MULTIPLY)
-
- var/list/turfs = visibleTurfs | dimTurfs
-
- for(var/turf/turf in turfs)
- var/x = (turf.x & 0xf) * 2
- var/y = (turf.y & 0xf) * 2
-
- if(turf.density)
- minimap_icon.DrawBox(rgb(100, 100, 100), x + 1, y + 1, x + 2, y + 2)
- continue
-
- else if(istype(turf, /turf/space))
- minimap_icon.DrawBox(rgb(0, 0, 0), x + 1, y + 1, x + 2, y + 2)
-
- else
- minimap_icon.DrawBox(rgb(200, 200, 200), x + 1, y + 1, x + 2, y + 2)
-
- for(var/obj/structure/o in turf)
- if(o.density)
- if(istype(o, /obj/structure/window) && (o.dir == NORTH || o.dir == SOUTH || o.dir == EAST || o.dir == WEST))
- if(o.dir == NORTH)
- minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 2, x + 2, y + 2)
- else if(o.dir == SOUTH)
- minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 2, y + 1)
- else if(o.dir == EAST)
- minimap_icon.DrawBox(rgb(150, 150, 200), x + 3, y + 1, x + 2, y + 2)
- else if(o.dir == WEST)
- minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 1, y + 2)
-
- else
- minimap_icon.DrawBox(rgb(150, 150, 150), x + 1, y + 1, x + 2, y + 2)
- break
-
- for(var/obj/machinery/door/o in turf)
- if(istype(o, /obj/machinery/door/window))
- if(o.dir == NORTH)
- minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 2, x + 2, y + 2)
- else if(o.dir == SOUTH)
- minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 1)
- else if(o.dir == EAST)
- minimap_icon.DrawBox(rgb(100, 150, 100), x + 2, y + 1, x + 2, y + 2)
- else if(o.dir == WEST)
- minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 1, y + 2)
-
- else
- minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 2)
- break
-
- minimap_obj.screen_loc = "minimap:[src.x / 16],[src.y / 16]"
- minimap_obj.icon = minimap_icon
-
-/mob/aiEye
- var/list/visibleCameraChunks = list()
- var/mob/ai = null
- density = 0
-
-/datum/camerachunk/proc/add(mob/aiEye/ai)
- ai.visibleCameraChunks += src
- if(ai.ai.client)
- ai.ai.client.images += obscured
- ai.ai.client.images += dim
- visible++
- seenby += ai
- if(changed && !updating)
- update()
- changed = 0
-
-/datum/camerachunk/proc/remove(mob/aiEye/ai)
- ai.visibleCameraChunks -= src
- if(ai.ai.client)
- ai.ai.client.images -= obscured
- ai.ai.client.images -= dim
- seenby -= ai
- if(visible > 0)
- visible--
-
-/datum/camerachunk/proc/visibilityChanged(turf/loc)
- if(!(loc in visibleTurfs))
- return
-
- hasChanged()
-
-/datum/camerachunk/proc/hasChanged()
- if(visible)
- if(!updating)
- updating = 1
- spawn(10)//Batch large changes, such as many doors opening or closing at once
- update()
- updating = 0
- else
- changed = 1
-
- if(!minimap_updating)
- minimap_updating = 1
-
- spawn(MINIMAP_UPDATE_DELAY)
- if(changed && !updating)
- update()
- changed = 0
-
- update_minimap()
- minimap_updating = 0
-
-/datum/camerachunk/proc/update()
-
- var/list/newDimTurfs = list()
- var/list/newVisibleTurfs = list()
-
- for(var/obj/machinery/camera/c in cameras)
- var/lum = c.luminosity
- c.luminosity = 7
-
- newDimTurfs |= turfs & view(7, c)
- newVisibleTurfs |= turfs & view(6, c)
-
- c.luminosity = lum
-
- var/list/dimAdded = newDimTurfs - dimTurfs
- var/list/dimRemoved = dimTurfs - newDimTurfs
- var/list/visAdded = newVisibleTurfs - visibleTurfs
- var/list/visRemoved = visibleTurfs - newVisibleTurfs
-
- visibleTurfs = newVisibleTurfs
- dimTurfs = newDimTurfs
- obscuredTurfs = turfs - dimTurfs
- dimTurfs -= visibleTurfs
-
- for(var/turf/t in dimRemoved)
- if(t.dim)
- dim -= t.dim
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images -= t.dim
-
- if(!(t in visibleTurfs))
- if(!t.obscured)
- t.obscured = image('cameravis.dmi', t, "black", 15)
-
- obscured += t.obscured
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images += t.obscured
-
- for(var/turf/t in dimAdded)
- if(!(t in visibleTurfs))
- if(!t.dim)
- t.dim = image('cameravis.dmi', t, "dim", 15)
- t.mouse_opacity = 0
-
- dim += t.dim
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images += t.dim
-
- if(t.obscured)
- obscured -= t.obscured
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images -= t.obscured
-
- for(var/turf/t in visAdded)
- if(t.obscured)
- obscured -= t.obscured
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images -= t.obscured
-
- for(var/turf/t in visRemoved)
- if(t in obscuredTurfs)
- if(!t.obscured)
- t.obscured = image('cameravis.dmi', t, "black", 15)
-
- obscured += t.obscured
- for(var/mob/aiEye/m in seenby)
- if(m.ai.client)
- m.ai.client.images += t.obscured
-
-
-/datum/camerachunk/New(loc, x, y, z)
- x &= ~0xf
- y &= ~0xf
-
- src.x = x
- src.y = y
- src.z = z
-
- for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
- if(c.status)
- cameras += c
-
- turfs = block(locate(x, y, z), locate(min(world.maxx, x + 15), min(world.maxy, y + 15), z))
-
- for(var/obj/machinery/camera/c in cameras)
- var/lum = c.luminosity
- c.luminosity = 7
-
- dimTurfs |= turfs & view(7, c)
- visibleTurfs |= turfs & view(6, c)
-
- c.luminosity = lum
-
- obscuredTurfs = turfs - dimTurfs
- dimTurfs -= visibleTurfs
-
- for(var/turf/t in obscuredTurfs)
- if(!t.obscured)
- t.obscured = image('cameravis.dmi', t, "black", 15)
-
- obscured += t.obscured
-
- for(var/turf/t in dimTurfs)
- if(!(t in visibleTurfs))
- if(!t.dim)
- t.dim = image('cameravis.dmi', t, "dim", TURF_LAYER)
- t.dim.mouse_opacity = 0
-
- dim += t.dim
-
- cameranet.minimap += minimap_obj
-
-var/datum/cameranet/cameranet = new()
-
-/datum/cameranet
- var/list/cameras = list()
- var/list/chunks = list()
- var/network = "net1"
- var/ready = 0
-
- var/list/minimap = list()
-
- var/generating_minimap = TRUE
- var/list/minimap_viewers = list()
-
-/datum/cameranet/New()
- ..()
-
- spawn(200)
- for(var/x = 0, x <= world.maxx, x += 16)
- for(var/y = 0, y <= world.maxy, y += 16)
- sleep(1)
- var/datum/camerachunk/c = getCameraChunk(x, y, 1)
- c.update_minimap()
-
- for(var/mob/m in minimap_viewers)
- m.client.screen |= c.minimap_obj
-
- generating_minimap = FALSE
- minimap_viewers = list()
-
-/datum/cameranet/proc/chunkGenerated(x, y, z)
- var/key = "[x],[y],[z]"
- return key in chunks
-
-/datum/cameranet/proc/getCameraChunk(x, y, z)
- var/key = "[x],[y],[z]"
-
- if(!(key in chunks))
- chunks[key] = new /datum/camerachunk(null, x, y, z)
-
- return chunks[key]
-
-/datum/cameranet/proc/visibility(mob/aiEye/ai)
- 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/datum/camerachunk/c in remove)
- c.remove(ai)
-
- for(var/datum/camerachunk/c in add)
- c.add(ai)
-
-/datum/cameranet/proc/updateVisibility(turf/loc)
- if(!chunkGenerated(loc.x & ~0xf, loc.y & ~0xf, loc.z))
- return
-
- var/datum/camerachunk/chunk = getCameraChunk(loc.x & ~0xf, loc.y & ~0xf, loc.z)
- chunk.visibilityChanged(loc)
-
-/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
- var/x1 = max(0, c.x - 16) & ~0xf
- var/y1 = max(0, c.y - 16) & ~0xf
- var/x2 = min(world.maxx, c.x + 16) & ~0xf
- var/y2 = min(world.maxy, c.y + 16) & ~0xf
-
- for(var/x = x1; x <= x2; x += 16)
- for(var/y = y1; y <= y2; y += 16)
- if(chunkGenerated(x, y, c.z))
- var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
- if(!(c in chunk.cameras))
- chunk.cameras += c
- chunk.hasChanged()
-
-/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
- var/x1 = max(0, c.x - 16) & ~0xf
- var/y1 = max(0, c.y - 16) & ~0xf
- var/x2 = min(world.maxx, c.x + 16) & ~0xf
- var/y2 = min(world.maxy, c.y + 16) & ~0xf
-
- for(var/x = x1; x <= x2; x += 16)
- for(var/y = y1; y <= y2; y += 16)
- if(chunkGenerated(x, y, c.z))
- var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
- if(!c)
- chunk.hasChanged()
- if(c in chunk.cameras)
- chunk.cameras -= c
- chunk.hasChanged()
-
-/mob/living/silicon/ai/var/mob/aiEye/eyeobj = new()
-
-/mob/living/silicon/ai/New()
- ..()
- eyeobj.ai = src
- spawn(20)
- freelook()
-
-/mob/living/silicon/ai/death(gibbed)
- if(client && client.eye == eyeobj)
- for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
- c.remove(eyeobj)
- client.eye = src
- return ..(gibbed)
-
-/mob/living/silicon/ai/verb/freelook()
- set category = "AI Commands"
- set name = "freelook"
- current = null //cancel camera view first, it causes problems
- cameraFollow = null
-// machine = null
- if(!eyeobj) //if it got deleted somehow (like an admin trying to fix things <.<')
- eyeobj = new()
- eyeobj.ai = src
- client.eye = eyeobj
- eyeobj.loc = loc
- cameranet.visibility(eyeobj)
- cameraFollow = null
-
-/mob/aiEye/Move()
- . = ..()
- if(.)
- cameranet.visibility(src)
-
-/client/AIMove(n, direct, var/mob/living/silicon/ai/user)
- if(eye == user.eyeobj)
- user.eyeobj.loc = get_step(user.eyeobj, direct)
- cameranet.visibility(user.eyeobj)
-
- else
- return ..()
-
-/*
-/client/AIMoveZ(direct, var/mob/living/silicon/ai/user)
- if(eye == user.eyeobj)
- var/dif = 0
- if(direct == UP && user.eyeobj.z > 1)
- dif = -1
- else if(direct == DOWN && user.eyeobj.z < 4)
- dif = 1
- user.eyeobj.loc = locate(user.eyeobj.x, user.eyeobj.y, user.eyeobj.z + dif)
- cameranet.visibility(user.eyeobj)
- else
- return ..()
-*/
-
-/turf/move_camera_by_click()
- if(istype(usr, /mob/living/silicon/ai))
- var/mob/living/silicon/ai/AI = usr
- if(AI.client.eye == AI.eyeobj)
- return
- return ..()
-
-
-/obj/machinery/door/update_nearby_tiles(need_rebuild)
- . = ..(need_rebuild)
- cameranet.updateVisibility(loc)
-
-/obj/machinery/camera/New()
- ..()
- cameranet.addCamera(src)
-
-/obj/machinery/camera/Del()
- cameranet.removeCamera(src)
- ..()
-
-/obj/machinery/camera/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
- . = ..(W, user)
- if(istype(W, /obj/item/weapon/wirecutters))
- if(status)
- cameranet.addCamera(src)
- else
- cameranet.removeCamera(src)
-
-/proc/checkcameravis(atom/A)
- for(var/obj/machinery/camera/C in view(A,7))
- if(!C.status || C.stat == 2)
- continue
- return 1
- return 0
-
-/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
- if (user != src)
- return
-
- if (stat == 2)
- return
-
- var/list/L = list()
- for (var/obj/machinery/camera/C in world)
- L.Add(C)
-
- camera_sort(L)
- L = camera_network_sort(L)
-
- var/list/D = list()
- for (var/obj/machinery/camera/C in L)
- if ( C.network in src.networks )
- D[text("[]: [][]", C.network, C.c_tag, (C.status ? null : " (Deactivated)"))] = C
- D["Cancel"] = "Cancel"
-
- var/t = input(user, "Which camera should you change to?") as null|anything in D
-
- if (!t || t == "Cancel")
- return 0
-
- var/obj/machinery/camera/C = D[t]
-
- eyeobj.loc = C.loc
- cameranet.visibility(eyeobj)
-
- return
-
-/mob/living/silicon/ai/cancel_camera()
- set name = "Cancel Camera View"
- set category = "OOC"
- reset_view(null)
- machine = null
-
-/mob/living/silicon/ai/reset_view(atom/A)
- if (client)
- if(!eyeobj)
- eyeobj = new()
- eyeobj.ai = src
-
- client.eye = eyeobj
- client.perspective = EYE_PERSPECTIVE
-
- if (istype(A, /atom/movable))
- eyeobj.loc = locate(A.x, A.y, A.z)
-
- else
- eyeobj.loc = locate(src.x, src.y, src.z)
-
+//All credit for this goes to Uristqwerty.
+
+//And some to me! -Mini
+
+
+
+//This file is partly designed around being able to uninclude it to go back to the old ai viewing system completely.
+//(And therefore also be portable to another similar codebase simply by transferring the file and including it after the other AI code files.)
+//There are probably a few parts that don't do that at the moment, but I'll fix them at some point.
+
+
+#define MINIMAP_UPDATE_DELAY 1200
+
+/turf
+ var/image/obscured
+ var/image/dim
+
+/turf/proc/visibilityChanged()
+ cameranet.updateVisibility(src)
+
+/turf/New()
+ ..()
+ cameranet.updateVisibility(src)
+/*
+/turf/Del()
+ ..()
+ cameranet.updateVisibility(src)
+*/
+/datum/camerachunk
+ var/list/obscuredTurfs = list()
+ var/list/visibleTurfs = list()
+ var/list/dimTurfs = list()
+ var/list/obscured = list()
+ var/list/dim = list()
+ var/list/cameras = list()
+ var/list/turfs = list()
+ var/list/seenby = list()
+ var/visible = 0
+ var/changed = 1
+ var/updating = 0
+
+ var/x
+ var/y
+ var/z
+
+ var/minimap_updating = 0
+
+ var/icon/minimap_icon = new('minimap.dmi', "chunk_base")
+ var/obj/minimap_obj/minimap_obj = new()
+
+/obj/minimap_obj/Click(location, control, params)
+ if(!istype(usr, /mob/dead) && !istype(usr, /mob/living/silicon/ai) && !(usr.client && usr.client.holder && usr.client.holder.level >= 4))
+ return
+
+ var/list/par = params2list(params)
+ var/screen_loc = par["screen-loc"]
+
+ if(findtext(screen_loc, "minimap:") != 1)
+ return
+
+ screen_loc = copytext(screen_loc, length("minimap:") + 1)
+
+ var/x_text = copytext(screen_loc, 1, findtext(screen_loc, ","))
+ var/y_text = copytext(screen_loc, findtext(screen_loc, ",") + 1)
+
+ var/x = (text2num(copytext(x_text, 1, findtext(x_text, ":"))) - 1) * 16
+ x += round((text2num(copytext(x_text, findtext(x_text, ":") + 1)) + 1) / 2)
+
+ var/y = (text2num(copytext(y_text, 1, findtext(y_text, ":"))) - 1) * 16
+ y += round((text2num(copytext(y_text, findtext(y_text, ":") + 1)) + 1) / 2)
+
+ if(istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/ai = usr
+ ai.freelook()
+ ai.eyeobj.loc = locate(max(1, x - 1), max(1, y - 1), ai.eyeobj.z)
+ cameranet.visibility(ai.eyeobj)
+
+ else
+ usr.loc = locate(max(1, x - 1), max(1, y - 1), usr.z)
+
+/mob/dead/verb/Open_Minimap()
+ set category = "Ghost"
+ winshow(src, "minimapwindow", 1)
+ client.screen |= cameranet.minimap
+
+ if(cameranet.generating_minimap)
+ cameranet.minimap_viewers += src
+
+/mob/living/silicon/ai/verb/Open_Minimap()
+ set category = "AI Commands"
+ winshow(src, "minimapwindow", 1)
+ client.screen |= cameranet.minimap
+
+ if(cameranet.generating_minimap)
+ cameranet.minimap_viewers += src
+
+/client/proc/Open_Minimap()
+ set category = "Admin"
+ winshow(src, "minimapwindow", 1)
+ screen |= cameranet.minimap
+
+ if(cameranet.generating_minimap)
+ cameranet.minimap_viewers += src.mob
+
+/datum/camerachunk/proc/update_minimap()
+ if(changed && !updating)
+ update()
+
+ minimap_icon.Blend(rgb(255, 0, 0), ICON_MULTIPLY)
+
+ var/list/turfs = visibleTurfs | dimTurfs
+
+ for(var/turf/turf in turfs)
+ var/x = (turf.x & 0xf) * 2
+ var/y = (turf.y & 0xf) * 2
+
+ if(turf.density)
+ minimap_icon.DrawBox(rgb(100, 100, 100), x + 1, y + 1, x + 2, y + 2)
+ continue
+
+ else if(istype(turf, /turf/space))
+ minimap_icon.DrawBox(rgb(0, 0, 0), x + 1, y + 1, x + 2, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(200, 200, 200), x + 1, y + 1, x + 2, y + 2)
+
+ for(var/obj/structure/o in turf)
+ if(o.density)
+ if(istype(o, /obj/structure/window) && (o.dir == NORTH || o.dir == SOUTH || o.dir == EAST || o.dir == WEST))
+ if(o.dir == NORTH)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 2, x + 2, y + 2)
+ else if(o.dir == SOUTH)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 2, y + 1)
+ else if(o.dir == EAST)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 3, y + 1, x + 2, y + 2)
+ else if(o.dir == WEST)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 1, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(150, 150, 150), x + 1, y + 1, x + 2, y + 2)
+ break
+
+ for(var/obj/machinery/door/o in turf)
+ if(istype(o, /obj/machinery/door/window))
+ if(o.dir == NORTH)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 2, x + 2, y + 2)
+ else if(o.dir == SOUTH)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 1)
+ else if(o.dir == EAST)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 2, y + 1, x + 2, y + 2)
+ else if(o.dir == WEST)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 1, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 2)
+ break
+
+ minimap_obj.screen_loc = "minimap:[src.x / 16],[src.y / 16]"
+ minimap_obj.icon = minimap_icon
+
+/mob/aiEye
+ var/list/visibleCameraChunks = list()
+ var/mob/ai = null
+ density = 0
+
+/datum/camerachunk/proc/add(mob/aiEye/ai)
+ ai.visibleCameraChunks += src
+ if(ai.ai.client)
+ ai.ai.client.images += obscured
+ ai.ai.client.images += dim
+ visible++
+ seenby += ai
+ if(changed && !updating)
+ update()
+ changed = 0
+
+/datum/camerachunk/proc/remove(mob/aiEye/ai)
+ ai.visibleCameraChunks -= src
+ if(ai.ai.client)
+ ai.ai.client.images -= obscured
+ ai.ai.client.images -= dim
+ seenby -= ai
+ if(visible > 0)
+ visible--
+
+/datum/camerachunk/proc/visibilityChanged(turf/loc)
+ if(!(loc in visibleTurfs))
+ return
+
+ hasChanged()
+
+/datum/camerachunk/proc/hasChanged()
+ if(visible)
+ if(!updating)
+ updating = 1
+ spawn(10)//Batch large changes, such as many doors opening or closing at once
+ update()
+ updating = 0
+ else
+ changed = 1
+
+ if(!minimap_updating)
+ minimap_updating = 1
+
+ spawn(MINIMAP_UPDATE_DELAY)
+ if(changed && !updating)
+ update()
+ changed = 0
+
+ update_minimap()
+ minimap_updating = 0
+
+/datum/camerachunk/proc/update()
+
+ var/list/newDimTurfs = list()
+ var/list/newVisibleTurfs = list()
+
+ for(var/obj/machinery/camera/c in cameras)
+ var/lum = c.luminosity
+ c.luminosity = 7
+
+ newDimTurfs |= turfs & view(7, c)
+ newVisibleTurfs |= turfs & view(6, c)
+
+ c.luminosity = lum
+
+ var/list/dimAdded = newDimTurfs - dimTurfs
+ var/list/dimRemoved = dimTurfs - newDimTurfs
+ var/list/visAdded = newVisibleTurfs - visibleTurfs
+ var/list/visRemoved = visibleTurfs - newVisibleTurfs
+
+ visibleTurfs = newVisibleTurfs
+ dimTurfs = newDimTurfs
+ obscuredTurfs = turfs - dimTurfs
+ dimTurfs -= visibleTurfs
+
+ for(var/turf/t in dimRemoved)
+ if(t.dim)
+ dim -= t.dim
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images -= t.dim
+
+ if(!(t in visibleTurfs))
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images += t.obscured
+
+ for(var/turf/t in dimAdded)
+ if(!(t in visibleTurfs))
+ if(!t.dim)
+ t.dim = image('cameravis.dmi', t, "dim", 15)
+ t.mouse_opacity = 0
+
+ dim += t.dim
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images += t.dim
+
+ if(t.obscured)
+ obscured -= t.obscured
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images -= t.obscured
+
+ for(var/turf/t in visAdded)
+ if(t.obscured)
+ obscured -= t.obscured
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images -= t.obscured
+
+ for(var/turf/t in visRemoved)
+ if(t in obscuredTurfs)
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+ for(var/mob/aiEye/m in seenby)
+ if(m.ai.client)
+ m.ai.client.images += t.obscured
+
+
+/datum/camerachunk/New(loc, x, y, z)
+ x &= ~0xf
+ y &= ~0xf
+
+ src.x = x
+ src.y = y
+ src.z = z
+
+ for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
+ if(c.status)
+ cameras += c
+
+ turfs = block(locate(x, y, z), locate(min(world.maxx, x + 15), min(world.maxy, y + 15), z))
+
+ for(var/obj/machinery/camera/c in cameras)
+ var/lum = c.luminosity
+ c.luminosity = 7
+
+ dimTurfs |= turfs & view(7, c)
+ visibleTurfs |= turfs & view(6, c)
+
+ c.luminosity = lum
+
+ obscuredTurfs = turfs - dimTurfs
+ dimTurfs -= visibleTurfs
+
+ for(var/turf/t in obscuredTurfs)
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+
+ for(var/turf/t in dimTurfs)
+ if(!(t in visibleTurfs))
+ if(!t.dim)
+ t.dim = image('cameravis.dmi', t, "dim", TURF_LAYER)
+ t.dim.mouse_opacity = 0
+
+ dim += t.dim
+
+ cameranet.minimap += minimap_obj
+
+var/datum/cameranet/cameranet = new()
+
+/datum/cameranet
+ var/list/cameras = list()
+ var/list/chunks = list()
+ var/network = "net1"
+ var/ready = 0
+
+ var/list/minimap = list()
+
+ var/generating_minimap = TRUE
+ var/list/minimap_viewers = list()
+
+/datum/cameranet/New()
+ ..()
+
+ spawn(200)
+ for(var/x = 0, x <= world.maxx, x += 16)
+ for(var/y = 0, y <= world.maxy, y += 16)
+ sleep(1)
+ var/datum/camerachunk/c = getCameraChunk(x, y, 1)
+ c.update_minimap()
+
+ for(var/mob/m in minimap_viewers)
+ m.client.screen |= c.minimap_obj
+
+ generating_minimap = FALSE
+ minimap_viewers = list()
+
+/datum/cameranet/proc/chunkGenerated(x, y, z)
+ var/key = "[x],[y],[z]"
+ return key in chunks
+
+/datum/cameranet/proc/getCameraChunk(x, y, z)
+ var/key = "[x],[y],[z]"
+
+ if(!(key in chunks))
+ chunks[key] = new /datum/camerachunk(null, x, y, z)
+
+ return chunks[key]
+
+/datum/cameranet/proc/visibility(mob/aiEye/ai)
+ 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/datum/camerachunk/c in remove)
+ c.remove(ai)
+
+ for(var/datum/camerachunk/c in add)
+ c.add(ai)
+
+/datum/cameranet/proc/updateVisibility(turf/loc)
+ if(!chunkGenerated(loc.x & ~0xf, loc.y & ~0xf, loc.z))
+ return
+
+ var/datum/camerachunk/chunk = getCameraChunk(loc.x & ~0xf, loc.y & ~0xf, loc.z)
+ chunk.visibilityChanged(loc)
+
+/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
+ var/x1 = max(0, c.x - 16) & ~0xf
+ var/y1 = max(0, c.y - 16) & ~0xf
+ var/x2 = min(world.maxx, c.x + 16) & ~0xf
+ var/y2 = min(world.maxy, c.y + 16) & ~0xf
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ if(chunkGenerated(x, y, c.z))
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
+ if(!(c in chunk.cameras))
+ chunk.cameras += c
+ chunk.hasChanged()
+
+/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
+ var/x1 = max(0, c.x - 16) & ~0xf
+ var/y1 = max(0, c.y - 16) & ~0xf
+ var/x2 = min(world.maxx, c.x + 16) & ~0xf
+ var/y2 = min(world.maxy, c.y + 16) & ~0xf
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ if(chunkGenerated(x, y, c.z))
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
+ if(!c)
+ chunk.hasChanged()
+ if(c in chunk.cameras)
+ chunk.cameras -= c
+ chunk.hasChanged()
+
+/mob/living/silicon/ai/var/mob/aiEye/eyeobj = new()
+
+/mob/living/silicon/ai/New()
+ ..()
+ eyeobj.ai = src
+ spawn(20)
+ freelook()
+
+/mob/living/silicon/ai/death(gibbed)
+ if(client && client.eye == eyeobj)
+ for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
+ c.remove(eyeobj)
+ client.eye = src
+ return ..(gibbed)
+
+/mob/living/silicon/ai/verb/freelook()
+ set category = "AI Commands"
+ set name = "freelook"
+ current = null //cancel camera view first, it causes problems
+ cameraFollow = null
+// machine = null
+ if(!eyeobj) //if it got deleted somehow (like an admin trying to fix things <.<')
+ eyeobj = new()
+ eyeobj.ai = src
+ client.eye = eyeobj
+ eyeobj.loc = loc
+ cameranet.visibility(eyeobj)
+ cameraFollow = null
+
+/mob/aiEye/Move()
+ . = ..()
+ if(.)
+ cameranet.visibility(src)
+
+/client/AIMove(n, direct, var/mob/living/silicon/ai/user)
+ if(eye == user.eyeobj)
+ user.eyeobj.loc = get_step(user.eyeobj, direct)
+ cameranet.visibility(user.eyeobj)
+
+ else
+ return ..()
+
+/*
+/client/AIMoveZ(direct, var/mob/living/silicon/ai/user)
+ if(eye == user.eyeobj)
+ var/dif = 0
+ if(direct == UP && user.eyeobj.z > 1)
+ dif = -1
+ else if(direct == DOWN && user.eyeobj.z < 4)
+ dif = 1
+ user.eyeobj.loc = locate(user.eyeobj.x, user.eyeobj.y, user.eyeobj.z + dif)
+ cameranet.visibility(user.eyeobj)
+ else
+ return ..()
+*/
+
+/turf/move_camera_by_click()
+ if(istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/AI = usr
+ if(AI.client.eye == AI.eyeobj)
+ return
+ return ..()
+
+
+/obj/machinery/door/update_nearby_tiles(need_rebuild)
+ . = ..(need_rebuild)
+ cameranet.updateVisibility(loc)
+
+/obj/machinery/camera/New()
+ ..()
+ cameranet.addCamera(src)
+
+/obj/machinery/camera/Del()
+ cameranet.removeCamera(src)
+ ..()
+
+/obj/machinery/camera/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
+ . = ..(W, user)
+ if(istype(W, /obj/item/weapon/wirecutters))
+ if(status)
+ cameranet.addCamera(src)
+ else
+ cameranet.removeCamera(src)
+
+/proc/checkcameravis(atom/A)
+ for(var/obj/machinery/camera/C in view(A,7))
+ if(!C.status || C.stat == 2)
+ continue
+ return 1
+ return 0
+
+/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
+ if (user != src)
+ return
+
+ if (stat == 2)
+ return
+
+ var/list/L = list()
+ for (var/obj/machinery/camera/C in world)
+ L.Add(C)
+
+ camera_sort(L)
+ L = camera_network_sort(L)
+
+ var/list/D = list()
+ for (var/obj/machinery/camera/C in L)
+ if ( C.network in src.networks )
+ D[text("[]: [][]", C.network, C.c_tag, (C.status ? null : " (Deactivated)"))] = C
+ D["Cancel"] = "Cancel"
+
+ var/t = input(user, "Which camera should you change to?") as null|anything in D
+
+ if (!t || t == "Cancel")
+ return 0
+
+ var/obj/machinery/camera/C = D[t]
+
+ eyeobj.loc = C.loc
+ cameranet.visibility(eyeobj)
+
+ return
+
+/mob/living/silicon/ai/cancel_camera()
+ set name = "Cancel Camera View"
+ set category = "OOC"
+ reset_view(null)
+ machine = null
+
+/mob/living/silicon/ai/reset_view(atom/A)
+ if (client)
+ if(!eyeobj)
+ eyeobj = new()
+ eyeobj.ai = src
+
+ client.eye = eyeobj
+ client.perspective = EYE_PERSPECTIVE
+
+ if (istype(A, /atom/movable))
+ eyeobj.loc = locate(A.x, A.y, A.z)
+
+ else
+ eyeobj.loc = locate(src.x, src.y, src.z)
+
cameranet.visibility(eyeobj)
diff --git a/code/WorkInProgress/AI_Visibility/ai.dm b/code/WorkInProgress/AI_Visibility/ai.dm
new file mode 100644
index 0000000000..7dcbf54e67
--- /dev/null
+++ b/code/WorkInProgress/AI_Visibility/ai.dm
@@ -0,0 +1,107 @@
+
+/mob/aiEye
+ var/list/visibleCameraChunks = list()
+ var/mob/ai = null
+ density = 0
+
+/mob/living/silicon/ai/var/mob/aiEye/eyeobj = new()
+
+/mob/living/silicon/ai/New()
+ ..()
+ eyeobj.ai = src
+ spawn(20)
+ freelook()
+
+/mob/living/silicon/ai/death(gibbed)
+ if(client && client.eye == eyeobj)
+ for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
+ c.remove(eyeobj)
+ client.eye = src
+ return ..(gibbed)
+
+/mob/living/silicon/ai/verb/freelook()
+ set category = "AI Commands"
+ set name = "freelook"
+ current = null //cancel camera view first, it causes problems
+ cameraFollow = null
+ if(!eyeobj) //if it got deleted somehow (like an admin trying to fix things <.<')
+ eyeobj = new()
+ eyeobj.ai = src
+ client.eye = eyeobj
+ eyeobj.loc = loc
+ cameranet.visibility(eyeobj)
+
+/mob/aiEye/Move()
+ . = ..()
+ if(.)
+ cameranet.visibility(src)
+
+/client/AIMove(n, direct, var/mob/living/silicon/ai/user)
+ if(eye == user.eyeobj)
+ user.eyeobj.loc = get_step(user.eyeobj, direct)
+ cameranet.visibility(user.eyeobj)
+
+ else
+ return ..()
+
+/turf/move_camera_by_click()
+ if(istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/AI = usr
+ if(AI.client.eye == AI.eyeobj)
+ return
+ return ..()
+
+/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
+ if (user != src)
+ return
+
+ if (stat == 2)
+ return
+
+ var/list/L = list()
+ for (var/obj/machinery/camera/C in world)
+ L.Add(C)
+
+ camera_sort(L)
+ L = camera_network_sort(L)
+
+ var/list/D = list()
+ for (var/obj/machinery/camera/C in L)
+ if ( C.network in src.networks )
+ D[text("[]: [][]", C.network, C.c_tag, (C.status ? null : " (Deactivated)"))] = C
+ D["Cancel"] = "Cancel"
+
+ var/t = input(user, "Which camera should you change to?") as null|anything in D
+
+ if (!t || t == "Cancel")
+ return 0
+
+ var/obj/machinery/camera/C = D[t]
+
+ eyeobj.loc = C.loc
+ cameranet.visibility(eyeobj)
+
+ return
+
+/mob/living/silicon/ai/cancel_camera()
+ set name = "Cancel Camera View"
+ set category = "OOC"
+ reset_view(null)
+ machine = null
+
+/mob/living/silicon/ai/reset_view(atom/A)
+ if (client)
+ if(!eyeobj)
+ eyeobj = new()
+ eyeobj.ai = src
+
+ client.eye = eyeobj
+ client.perspective = EYE_PERSPECTIVE
+
+ if (istype(A, /atom/movable))
+ eyeobj.loc = locate(A.x, A.y, A.z)
+
+ else
+ eyeobj.loc = locate(src.x, src.y, src.z)
+
+ cameranet.visibility(eyeobj)
diff --git a/code/WorkInProgress/AI_Visibility/cameranet.dm b/code/WorkInProgress/AI_Visibility/cameranet.dm
new file mode 100644
index 0000000000..3b46844e6b
--- /dev/null
+++ b/code/WorkInProgress/AI_Visibility/cameranet.dm
@@ -0,0 +1,156 @@
+//------------------------------------------------------------
+//
+// The Cameranet
+//
+// The cameranet is a single global instance of a unique
+// datum, which contains logic for managing the individual
+// chunks.
+//
+//------------------------------------------------------------
+
+/datum/cameranet
+ var/list/cameras = list()
+ var/list/chunks = list()
+ var/network = "net1"
+ var/ready = 0
+
+ var/list/minimap = list()
+
+ var/generating_minimap = TRUE
+
+var/datum/cameranet/cameranet = new()
+
+
+
+/datum/cameranet/New()
+ ..()
+
+ spawn(100)
+ init_minimap()
+
+
+/datum/cameranet/proc/init_minimap()
+ for(var/x = 0, x <= world.maxx, x += 16)
+ for(var/y = 0, y <= world.maxy, y += 16)
+ sleep(1)
+ getCameraChunk(x, y, 5)
+ getCameraChunk(x, y, 1)
+
+ generating_minimap = FALSE
+
+
+/datum/cameranet/proc/chunkGenerated(x, y, z)
+ var/key = "[x],[y],[z]"
+ return key in chunks
+
+
+/datum/cameranet/proc/getCameraChunk(x, y, z)
+ var/key = "[x],[y],[z]"
+
+ if(!(key in chunks))
+ chunks[key] = new /datum/camerachunk(null, x, y, z)
+
+ return chunks[key]
+
+
+
+
+// This proc updates what chunks are considered seen
+// by an aiEye. As part of the process, it will force
+// any newly visible chunks with pending unscheduled
+// updates to update, and show the correct obscuring
+// and dimming image sets. If you do not call this
+// after the eye has moved, it may result in the
+// affected AI gaining (partial) xray, seeing through
+// now-closed doors, not seeing through open doors,
+// or other visibility oddities, depending on if/when
+// they last visited any of the chunks in the nearby
+// area.
+
+// It must be called manually, as there is no way to
+// have a proc called automatically every time an
+// object's loc changes.
+
+/datum/cameranet/proc/visibility(mob/aiEye/ai)
+ 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/datum/camerachunk/c in remove)
+ c.remove(ai)
+
+ for(var/datum/camerachunk/c in add)
+ c.add(ai)
+
+
+
+
+// This proc should be called if a turf, or the contents
+// of a turf, changes opacity. This includes such things
+// as changing the turf, opening or closing a door, or
+// anything else that would alter line of sight in the
+// general area.
+
+/datum/cameranet/proc/updateVisibility(turf/loc)
+ if(!chunkGenerated(loc.x & ~0xf, loc.y & ~0xf, loc.z))
+ return
+
+ var/datum/camerachunk/chunk = getCameraChunk(loc.x & ~0xf, loc.y & ~0xf, loc.z)
+ chunk.visibilityChanged(loc)
+
+
+
+
+// This proc updates all relevant chunks when enabling or
+// creating a camera, allowing freelook and the minimap to
+// respond correctly.
+
+/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
+ var/x1 = max(0, c.x - 16) & ~0xf
+ var/y1 = max(0, c.y - 16) & ~0xf
+ var/x2 = min(world.maxx, c.x + 16) & ~0xf
+ var/y2 = min(world.maxy, c.y + 16) & ~0xf
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ if(chunkGenerated(x, y, c.z))
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
+
+ if(!(c in chunk.cameras))
+ chunk.cameras += c
+ chunk.hasChanged()
+
+
+
+
+// This proc updates all relevant chunks when disabling or
+// deleting a camera, allowing freelook and the minimap to
+// respond correctly.
+
+/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
+ var/x1 = max(0, c.x - 16) & ~0xf
+ var/y1 = max(0, c.y - 16) & ~0xf
+ var/x2 = min(world.maxx, c.x + 16) & ~0xf
+ var/y2 = min(world.maxy, c.y + 16) & ~0xf
+
+ for(var/x = x1; x <= x2; x += 16)
+ for(var/y = y1; y <= y2; y += 16)
+ if(chunkGenerated(x, y, c.z))
+ var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
+
+ if(!c)
+ chunk.hasChanged()
+
+ if(c in chunk.cameras)
+ chunk.cameras -= c
+ chunk.hasChanged()
diff --git a/code/WorkInProgress/AI_Visibility/chunk.dm b/code/WorkInProgress/AI_Visibility/chunk.dm
new file mode 100644
index 0000000000..73306facb4
--- /dev/null
+++ b/code/WorkInProgress/AI_Visibility/chunk.dm
@@ -0,0 +1,221 @@
+#define MINIMAP_UPDATE_DELAY 1200
+
+/datum/camerachunk
+ var/list/turfs = list()
+
+ var/list/obscuredTurfs = list()
+ var/list/visibleTurfs = list()
+ var/list/dimTurfs = list()
+
+ var/list/obscured = list()
+ var/list/dim = list()
+
+ var/list/cameras = list()
+ var/list/seenby = list()
+
+ var/changed = 1
+ var/updating = 0
+ var/minimap_updating = 0
+
+ var/x
+ var/y
+ var/z
+
+
+ var/icon/minimap_icon = new('minimap.dmi', "chunk_base")
+ var/obj/minimap_obj/minimap_obj = new()
+
+
+
+/datum/camerachunk/New(loc, x, y, z)
+ //Round X and Y down to a multiple of 16, if nessecary
+ src.x = x & ~0xF
+ src.y = y & ~0xF
+ src.z = z
+
+ rebuild_chunk()
+
+
+
+// Completely re-calculate the whole chunk.
+
+/datum/camerachunk/proc/rebuild_chunk()
+ for(var/mob/aiEye/eye in seenby)
+ if(!eye.ai)
+ seenby -= eye
+ continue
+
+ if(eye.ai.client)
+ eye.ai.client.images -= obscured
+ eye.ai.client.images -= dim
+
+ var/start = locate(x, y, z)
+ var/end = locate(min(x + 15, world.maxx), min(y + 15, world.maxy), z)
+
+ turfs = block(start, end)
+ dimTurfs = list()
+ visibleTurfs = list()
+ obscured = list()
+ dim = list()
+ cameras = list()
+
+ for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
+ if(c.status)
+ cameras += c
+
+ for(var/obj/machinery/camera/c in cameras)
+ var/lum = c.luminosity
+ c.luminosity = 7
+
+ dimTurfs |= turfs & view(7, c)
+ visibleTurfs |= turfs & view(6, c)
+
+ c.luminosity = lum
+
+ obscuredTurfs = turfs - dimTurfs
+ dimTurfs -= visibleTurfs
+
+ for(var/turf/t in obscuredTurfs)
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+
+ for(var/turf/t in dimTurfs)
+ if(!t.dim)
+ t.dim = image('cameravis.dmi', t, "dim", TURF_LAYER)
+ t.dim.mouse_opacity = 0
+
+ dim += t.dim
+
+ cameranet.minimap |= minimap_obj
+
+ for(var/mob/aiEye/eye in seenby)
+ if(eye.ai.client)
+ eye.ai.client.images |= obscured
+ eye.ai.client.images |= dim
+
+
+
+/datum/camerachunk/proc/add(mob/aiEye/eye)
+ eye.visibleCameraChunks |= src
+
+ if(eye.ai.client)
+ eye.ai.client.images |= obscured
+ eye.ai.client.images |= dim
+
+ seenby |= eye
+
+ if(changed && !updating)
+ update()
+ changed = 0
+
+
+
+/datum/camerachunk/proc/remove(mob/aiEye/eye)
+ eye.visibleCameraChunks -= src
+
+ if(eye.ai.client)
+ eye.ai.client.images -= obscured
+ eye.ai.client.images -= dim
+
+ seenby -= eye
+
+/datum/camerachunk/proc/visibilityChanged(turf/loc)
+ if(!(loc in visibleTurfs))
+ return
+
+ hasChanged()
+
+/datum/camerachunk/proc/hasChanged()
+ if(length(seenby) > 0)
+ if(!updating)
+ updating = 1
+
+ spawn(10)//Batch large changes, such as many doors opening or closing at once
+ update()
+ updating = 0
+
+ else
+ changed = 1
+
+ if(!minimap_updating)
+ minimap_updating = 1
+
+ spawn(MINIMAP_UPDATE_DELAY)
+ if(changed && !updating)
+ update()
+ changed = 0
+
+ update_minimap()
+ minimap_updating = 0
+
+/datum/camerachunk/proc/update()
+
+ var/list/newDimTurfs = list()
+ var/list/newVisibleTurfs = list()
+
+ for(var/obj/machinery/camera/c in cameras)
+ var/lum = c.luminosity
+ c.luminosity = 7
+
+ newDimTurfs |= turfs & view(7, c)
+ newVisibleTurfs |= turfs & view(6, c)
+
+ c.luminosity = lum
+
+ var/list/dimAdded = newDimTurfs - dimTurfs
+ var/list/dimRemoved = dimTurfs - newDimTurfs
+ var/list/visAdded = newVisibleTurfs - visibleTurfs
+ var/list/visRemoved = visibleTurfs - newVisibleTurfs
+
+ visibleTurfs = newVisibleTurfs
+ dimTurfs = newDimTurfs
+ obscuredTurfs = turfs - dimTurfs
+ dimTurfs -= visibleTurfs
+
+ var/list/images_added = list()
+ var/list/images_removed = list()
+
+ for(var/turf/t in dimRemoved)
+ if(t.dim)
+ dim -= t.dim
+ images_removed += t.dim
+
+ if(!(t in visibleTurfs))
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+ images_added += t.obscured
+
+ for(var/turf/t in dimAdded)
+ if(!(t in visibleTurfs))
+ if(!t.dim)
+ t.dim = image('cameravis.dmi', t, "dim", 15)
+ t.mouse_opacity = 0
+
+ dim += t.dim
+ images_added += t.dim
+
+ if(t.obscured)
+ obscured -= t.obscured
+ images_removed += t.obscured
+
+ for(var/turf/t in visAdded)
+ if(t.obscured)
+ obscured -= t.obscured
+ images_removed += t.obscured
+
+ for(var/turf/t in visRemoved)
+ if(t in obscuredTurfs)
+ if(!t.obscured)
+ t.obscured = image('cameravis.dmi', t, "black", 15)
+
+ obscured += t.obscured
+ images_added += t.obscured
+
+ for(var/mob/aiEye/eye in seenby)
+ if(eye.ai.client)
+ eye.ai.client.images -= images_removed
+ eye.ai.client.images |= images_added
diff --git a/code/WorkInProgress/AI_Visibility/minimap.dm b/code/WorkInProgress/AI_Visibility/minimap.dm
new file mode 100644
index 0000000000..c97b01e0f8
--- /dev/null
+++ b/code/WorkInProgress/AI_Visibility/minimap.dm
@@ -0,0 +1,137 @@
+/client/var/minimap_view_z = 1
+
+/obj/minimap_obj
+ var/datum/camerachunk/chunk
+
+/obj/minimap_obj/Click(location, control, params)
+ if(!istype(usr, /mob/dead) && !istype(usr, /mob/living/silicon/ai) && !(usr.client && usr.client.holder && usr.client.holder.level >= 4))
+ return
+
+ var/list/par = params2list(params)
+ var/screen_loc = par["screen-loc"]
+
+ if(findtext(screen_loc, "minimap:") != 1)
+ return
+
+ screen_loc = copytext(screen_loc, length("minimap:") + 1)
+
+ var/x_text = copytext(screen_loc, 1, findtext(screen_loc, ","))
+ var/y_text = copytext(screen_loc, findtext(screen_loc, ",") + 1)
+
+ var/x = chunk.x
+ x += round((text2num(copytext(x_text, findtext(x_text, ":") + 1)) + 1) / 2)
+
+ var/y = chunk.y
+ y += round((text2num(copytext(y_text, findtext(y_text, ":") + 1)) + 1) / 2)
+
+ if(istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/ai = usr
+ ai.freelook()
+ ai.eyeobj.loc = locate(max(1, x - 1), max(1, y - 1), usr.client.minimap_view_z)
+ cameranet.visibility(ai.eyeobj)
+
+ else
+ usr.loc = locate(max(1, x - 1), max(1, y - 1), usr.client.minimap_view_z)
+
+/mob/dead/verb/Open_Minimap()
+ set category = "Ghost"
+ cameranet.show_minimap(client)
+
+
+/mob/living/silicon/ai/verb/Open_Minimap()
+ set category = "AI Commands"
+ cameranet.show_minimap(client)
+
+
+/client/proc/Open_Minimap()
+ set category = "Admin"
+ cameranet.show_minimap(src)
+
+
+/mob/verb/Open_Minimap_Z()
+ set hidden = 1
+
+ if(!istype(src, /mob/dead) && !istype(src, /mob/living/silicon/ai) && !(client && client.holder && client.holder.level >= 4))
+ return
+
+ var/level = input("Select a Z level", "Z select", null) as null | anything in cameranet.minimap
+
+ if(level != null)
+ cameranet.show_minimap(client, level)
+
+
+
+/datum/cameranet/proc/show_minimap(client/client, z_level = "z-1")
+ if(!istype(client.mob, /mob/dead) && !istype(client.mob, /mob/living/silicon/ai) && !(client.holder && client.holder.level >= 4))
+ return
+
+ if(z_level in cameranet.minimap)
+ winshow(client, "minimapwindow", 1)
+
+ for(var/key in cameranet.minimap)
+ client.screen -= cameranet.minimap[key]
+
+ client.screen |= cameranet.minimap[z_level]
+
+ if(cameranet.generating_minimap)
+ spawn(50)
+ show_minimap(client, z_level)
+
+ client.minimap_view_z = text2num(copytext(z_level, 3))
+
+
+/datum/camerachunk/proc/update_minimap()
+ if(changed && !updating)
+ update()
+
+ minimap_icon.Blend(rgb(255, 0, 0), ICON_MULTIPLY)
+
+ var/list/turfs = visibleTurfs | dimTurfs
+
+ for(var/turf/turf in turfs)
+ var/x = (turf.x & 0xf) * 2
+ var/y = (turf.y & 0xf) * 2
+
+ if(turf.density)
+ minimap_icon.DrawBox(rgb(100, 100, 100), x + 1, y + 1, x + 2, y + 2)
+ continue
+
+ else if(istype(turf, /turf/space))
+ minimap_icon.DrawBox(rgb(0, 0, 0), x + 1, y + 1, x + 2, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(200, 200, 200), x + 1, y + 1, x + 2, y + 2)
+
+ for(var/obj/structure/o in turf)
+ if(o.density)
+ if(istype(o, /obj/structure/window) && (o.dir == NORTH || o.dir == SOUTH || o.dir == EAST || o.dir == WEST))
+ if(o.dir == NORTH)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 2, x + 2, y + 2)
+ else if(o.dir == SOUTH)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 2, y + 1)
+ else if(o.dir == EAST)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 3, y + 1, x + 2, y + 2)
+ else if(o.dir == WEST)
+ minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 1, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(150, 150, 150), x + 1, y + 1, x + 2, y + 2)
+ break
+
+ for(var/obj/machinery/door/o in turf)
+ if(istype(o, /obj/machinery/door/window))
+ if(o.dir == NORTH)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 2, x + 2, y + 2)
+ else if(o.dir == SOUTH)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 1)
+ else if(o.dir == EAST)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 2, y + 1, x + 2, y + 2)
+ else if(o.dir == WEST)
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 1, y + 2)
+
+ else
+ minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 2)
+ break
+
+ minimap_obj.screen_loc = "minimap:[src.x / 16],[src.y / 16]"
+ minimap_obj.icon = minimap_icon
diff --git a/code/WorkInProgress/AI_Visibility/util.dm b/code/WorkInProgress/AI_Visibility/util.dm
new file mode 100644
index 0000000000..da576cbd40
--- /dev/null
+++ b/code/WorkInProgress/AI_Visibility/util.dm
@@ -0,0 +1,38 @@
+
+/turf
+ var/image/obscured
+ var/image/dim
+
+/turf/proc/visibilityChanged()
+ cameranet.updateVisibility(src)
+
+/turf/New()
+ ..()
+ cameranet.updateVisibility(src)
+
+/obj/machinery/door/update_nearby_tiles(need_rebuild)
+ . = ..(need_rebuild)
+ cameranet.updateVisibility(loc)
+
+/obj/machinery/camera/New()
+ ..()
+ cameranet.addCamera(src)
+
+/obj/machinery/camera/Del()
+ cameranet.removeCamera(src)
+ ..()
+
+/obj/machinery/camera/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
+ . = ..(W, user)
+ if(istype(W, /obj/item/weapon/wirecutters))
+ if(status)
+ cameranet.addCamera(src)
+ else
+ cameranet.removeCamera(src)
+
+/proc/checkcameravis(atom/A)
+ for(var/obj/machinery/camera/C in view(A,7))
+ if(!C.status || C.stat == 2)
+ continue
+ return 1
+ return 0
diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm b/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm
index 321b835209..ad6a754ba7 100644
--- a/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm
@@ -131,7 +131,7 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
radiation = 0
//update values
- var/transfer_ratio = 50 / field_strength
+ var/transfer_ratio = field_strength / 50
major_radius = field_strength * 0.21875// max = 8.75
minor_radius = field_strength * 0.2125// max = 8.625
volume_covered = PI * major_radius * minor_radius * 2.5 * 2.5 * 2.5 * 7 * 7 * transfer_ratio
@@ -159,10 +159,12 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
var/datum/gas_mixture/plasma_captured = new /datum/gas_mixture()
//
plasma_captured.toxins = round(gas_covered.toxins * transfer_ratio)
+ //world << "\blue[plasma_captured.toxins] moles of plasma captured"
plasma_captured.temperature = gas_covered.temperature
+ //plasma_captured.update_values()
gas_covered.toxins -= plasma_captured.toxins
- plasma_captured.update_values()
- gas_covered.update_values()
+ //gas_covered.update_values()
+ //
held_plasma.merge(plasma_captured)
//
environment.merge(gas_covered)
@@ -187,7 +189,25 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
//if there is too much plasma in the field, lose some
/*if( held_plasma.toxins > (MOLES_CELLSTANDARD * 7) * (50 / field_strength) )
LosePlasma()*/
- LosePlasma()
+ if(held_plasma.toxins > 1)
+ //lose a random amount of plasma back into the air, increased by the field strength (want to switch this over to frequency eventually)
+ var/loss_ratio = rand() * (0.05 + (0.05 * 50 / field_strength))
+ //world << "lost [loss_ratio*100]% of held plasma"
+ //
+ var/datum/gas_mixture/plasma_lost = new
+ plasma_lost.temperature = held_plasma.temperature
+ //
+ plasma_lost.toxins = held_plasma.toxins * loss_ratio
+ //plasma_lost.update_values()
+ held_plasma.toxins -= held_plasma.toxins * loss_ratio
+ //held_plasma.update_values()
+ //
+ environment.merge(plasma_lost)
+ radiation += loss_ratio * mega_energy * 0.1
+ mega_energy -= loss_ratio * mega_energy * 0.1
+ else
+ held_plasma.toxins = 0
+ //held_plasma.update_values()
//handle some reactants formatting
//helium-4 has no use at the moment, but a buttload of it is produced
@@ -293,30 +313,6 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
catcher.UpdateSize()
return changed
- proc/LosePlasma()
- if(held_plasma.toxins > 1)
- //lose a random amount of plasma back into the air, increased by the field strength (want to switch this over to frequency eventually)
- var/datum/gas_mixture/environment = loc.return_air()
- var/loss_ratio = rand() * (0.05 + (0.05 * 50 / field_strength))
- //world << "lost [loss_ratio*100]% of held plasma"
- //
- var/datum/gas_mixture/plasma_lost = new
- plasma_lost.temperature = held_plasma.temperature
- //
- plasma_lost.toxins = held_plasma.toxins * loss_ratio
- plasma_lost.update_values()
- held_plasma.toxins -= held_plasma.toxins * loss_ratio
- held_plasma.update_values()
- //
- environment.merge(plasma_lost)
- radiation += loss_ratio * mega_energy * 0.1
- mega_energy -= loss_ratio * mega_energy * 0.1
- return 1
- else
- held_plasma.toxins = 0
- held_plasma.update_values()
- return 0
-
//the !!fun!! part
//reactions have to be individually hardcoded, see AttemptReaction() below this
proc/React()
diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm b/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
index 91c35089c2..da06f39cca 100644
--- a/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
@@ -104,11 +104,11 @@
user.machine = null
user << browse(null, "window=fuel_injector")
return
- var/t = "Reactor Core Fuel Injector
"
+ var/t = "Reactor Core Fuel Injector