diff -ruN ../src_orig/Battlescape/TileEngine.cpp ../src_new/Battlescape/TileEngine.cpp
--- ../src_orig/Battlescape/TileEngine.cpp	Fri Oct 28 03:13:00 2016
+++ ../src_new/Battlescape/TileEngine.cpp	Fri Oct 28 03:11:55 2016
@@ -53,8 +53,9 @@
  * @param save Pointer to SavedBattleGame object.
  * @param voxelData List of voxel data.
  */
-TileEngine::TileEngine(SavedBattleGame *save, std::vector<Uint16> *voxelData) : _save(save), _voxelData(voxelData), _personalLighting(true)
+TileEngine::TileEngine(SavedBattleGame *save, std::vector<Uint16> *voxelData) : _save(save), _voxelData(voxelData), _personalLighting(true), _cacheTile(0), _cacheTileBelow(0)
 {
+	_cacheTilePos = Position(-1,-1,-1);
 }
 
 /**
@@ -678,6 +679,7 @@
 		return false;
 	}
 
+	voxelCheckFlush();
 // find out height range
 
 	if (!minZfound)
@@ -1045,6 +1047,7 @@
 
 	BattleUnit *bu = tile->getUnit();
 	int adjustedDamage = 0;
+	voxelCheckFlush();
 	const int part = voxelCheck(center, unit);
 	if (part >= V_FLOOR && part <= V_OBJECT)
 	{
@@ -2146,6 +2130,12 @@
 	Position lastPoint(origin);
 	int result;
 	int steps = 0;
+	bool excludeAllUnits = false;
+
+	if (_save->isBeforeGame())
+	{
+		excludeAllUnits = true; // don't start unit spotting before pre-game inventory stuff (large units on the craftInventory tile will cause a crash if they're "spotted")
+	}
 
 	//start and end points
 	x0 = origin.x;	 x1 = target.x;
@@ -2187,6 +2177,8 @@
 	y = y0;
 	z = z0;
 
+	if (doVoxelCheck) voxelCheckFlush();
+
 	//step through longest delta (which we have swapped to x)
 	for (x = x0; x != (x1+step_x); x += step_x)
 	{
@@ -2252,7 +2244,7 @@
 				cx = x;	cz = z; cy = y;
 				if (swap_xz) std::swap(cx, cz);
 				if (swap_xy) std::swap(cx, cy);
-				result = voxelCheck(Position(cx, cy, cz), excludeUnit, false, onlyVisible, excludeAllBut);
+				result = voxelCheck(Position(cx, cy, cz), excludeUnit, excludeAllUnits, onlyVisible, excludeAllBut);
 				if (result != V_EMPTY)
 				{
 					if (trajectory != 0)
@@ -2276,7 +2268,7 @@
 				cx = x;	cz = z; cy = y;
 				if (swap_xz) std::swap(cx, cz);
 				if (swap_xy) std::swap(cx, cy);
-				result = voxelCheck(Position(cx, cy, cz), excludeUnit, false, onlyVisible,  excludeAllBut);
+				result = voxelCheck(Position(cx, cy, cz), excludeUnit, excludeAllUnits, onlyVisible,  excludeAllBut);
 				if (result != V_EMPTY)
 				{
 					if (trajectory != 0)
@@ -2377,6 +2369,7 @@
 	Position tmpVoxel = voxel;
 	int z;
 
+	voxelCheckFlush();
 	for (z = zstart; z>0; z--)
 	{
 		tmpVoxel.z = z;
@@ -2398,6 +2391,8 @@
 		return true; // visible!
 	Position tmpVoxel = voxel;
 	int zend = (zstart/24)*24 +24;
+
+	voxelCheckFlush();
 	for (int z = zstart; z<zend; z++)
 	{
 		tmpVoxel.z=z;
@@ -2422,33 +2417,48 @@
  */
 int TileEngine::voxelCheck(const Position& voxel, BattleUnit *excludeUnit, bool excludeAllUnits, bool onlyVisible, BattleUnit *excludeAllBut)
 {
-	if (_save->isBeforeGame())
+	if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) //preliminary out of map
 	{
-		excludeAllUnits = true; // don't start unit spotting before pre-game inventory stuff (large units on the craftInventory tile will cause a crash if they're "spotted")
+		return V_OUTOFBOUNDS;
 	}
-	Tile *tile = _save->getTile(voxel / Position(16, 16, 24));
-	// check if we are not out of the map
-	if (tile == 0 || voxel.x < 0 || voxel.y < 0 || voxel.z < 0)
+	Position pos = voxel / Position(16, 16, 24);
+	Tile *tile, *tileBelow;
+	if (_cacheTilePos==pos)
 	{
-		return V_OUTOFBOUNDS;
+		tile = _cacheTile;
+		tileBelow = _cacheTileBelow;
+	}
+	else
+	{
+		tile = _save->getTile(pos);
+		if (!tile) // check if we are not out of the map
+		{
+			return V_OUTOFBOUNDS; //not even cache
+		}
+		tileBelow = _save->getTile(pos + Position(0,0,-1));
+		_cacheTilePos = pos;
+		_cacheTile = tile;
+		_cacheTileBelow = tileBelow;
 	}
-	Tile *tileBelow = _save->getTile(tile->getPosition() + Position(0,0,-1));
+
 	if (tile->isVoid() && tile->getUnit() == 0 && (!tileBelow || tileBelow->getUnit() == 0))
 	{
 		return V_EMPTY;
 	}
 
-	if ((voxel.z % 24 == 0 || voxel.z % 24 == 1) && tile->getMapData(O_FLOOR) && tile->getMapData(O_FLOOR)->isGravLift())
+	if (tile->getMapData(O_FLOOR) && tile->getMapData(O_FLOOR)->isGravLift() && (voxel.z % 24 == 0 || voxel.z % 24 == 1))
 	{
 		if ((tile->getPosition().z == 0) || (tileBelow && tileBelow->getMapData(O_FLOOR) && !tileBelow->getMapData(O_FLOOR)->isGravLift()))
+		{
 			return V_FLOOR;
+		}
 	}
 
 	// first we check terrain voxel data, not to allow 2x2 units stick through walls
 	for (int i=0; i< 4; ++i)
 	{
 		MapData *mp = tile->getMapData(i);
-		if (tile->isUfoDoorOpen(i))
+		if (((i==1) || (i==2)) && tile->isUfoDoorOpen(i))
 			continue;
 		if (mp != 0)
 		{
@@ -2469,8 +2479,7 @@
 		// in this case we couldn't have unit standing at current tile.
 		if (unit == 0 && tile->hasNoFloor(0))
 		{
-			tile = _save->getTile(Position(voxel.x/16, voxel.y/16, (voxel.z/24)-1)); //below
-			if (tile) unit = tile->getUnit();
+			if (tileBelow) unit = tileBelow->getUnit();
 		}
 
 		if (unit != 0 && unit != excludeUnit && (!excludeAllBut || unit == excludeAllBut) && (!onlyVisible || unit->getVisible() ) )
@@ -2498,6 +2507,14 @@
 	}
 	return V_EMPTY;
 }
+
+void TileEngine::voxelCheckFlush(void)
+{
+	_cacheTilePos = Position(-1,-1,-1);
+	_cacheTile = 0;
+	_cacheTileBelow = 0;
+}
+
 
 /**
  * Toggles personal lighting on / off.
diff -ruN ../src_orig/Battlescape/TileEngine.h ../src_new/Battlescape/TileEngine.h
--- ../src_orig/Battlescape/TileEngine.h	Sun Oct 23 22:34:04 2016
+++ ../src_new/Battlescape/TileEngine.h	Fri Oct 28 02:54:47 2016
@@ -47,6 +47,9 @@
 	void addLight(const Position &center, int power, int layer);
 	int blockage(Tile *tile, const int part, ItemDamageType type, int direction = -1, bool checkingFromOrigin = false);
 	bool _personalLighting;
+	Tile *_cacheTile;
+	Tile *_cacheTileBelow;
+	Position _cacheTilePos;
 public:
 	/// Creates a new TileEngine class.
 	TileEngine(SavedBattleGame *save, std::vector<Uint16> *voxelData);
@@ -114,6 +117,8 @@
 	bool isVoxelVisible(const Position& voxel);
 	/// Checks what type of voxel occupies this space.
 	int voxelCheck(const Position& voxel, BattleUnit *excludeUnit, bool excludeAllUnits = false, bool onlyVisible = false, BattleUnit *excludeAllBut = 0);
+	/// Flushes cache of voxel check
+	void voxelCheckFlush(void);
 	/// Blows this tile up.
 	bool detonate(Tile* tile);
 	/// Validates a throwing action.
