From e8e1db5f674c50b526f6a98903bfdb5072666b3a Mon Sep 17 00:00:00 2001
From: Evan Debenham <Evan@ShatteredPixel.com>
Date: Tue, 3 Mar 2020 16:18:36 -0500
Subject: [PATCH] v0.8.0: reworked Yog's level, boss itself is largely
 unchanged atm.

---
 .../assets/custom_tiles/halls_special.png     | Bin 302 -> 3612 bytes
 .../shatteredpixeldungeon/Dungeon.java        |   4 +-
 .../ShatteredPixelDungeon.java                |   3 +
 .../actors/mobs/YogDzewa.java                 |  43 +++
 .../levels/LastLevel.java                     | 169 +++++++--
 .../levels/NewHallsBossLevel.java             | 354 ++++++++++++++++++
 ...sBossLevel.java => OldHallsBossLevel.java} |   2 +-
 .../rooms/special/DemonSpawnerRoom.java       |  10 +-
 .../tiles/WallBlockingTilemap.java            |   9 +
 9 files changed, 566 insertions(+), 28 deletions(-)
 create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java
 create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewHallsBossLevel.java
 rename core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/{HallsBossLevel.java => OldHallsBossLevel.java} (99%)

diff --git a/core/src/main/assets/custom_tiles/halls_special.png b/core/src/main/assets/custom_tiles/halls_special.png
index e48bc1059360ee30d18a5e68a18783d93dd62536..9eecf798ef906b3b50da8381dc6fc7c5fdbb0e29 100644
GIT binary patch
literal 3612
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
Dx(5@u

literal 302
zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!3-oF?)7E^DVqSF5LZ2Uc_&RxOCSO=jEy6F
z%ripl6M@Lb{Qv*g88Pnvzsg^`vhd8w#WSZ>HPoi9UELreBBClOsi&xD^8E@E(44iN
zE{-7;jH%}uvkn{ZFkJksIg`zMcFy1b@v-XHXS6<JxXIr$(ZTr2Qr)(2?u^MDdG~$S
zpFM4Hz27F1_oHaTv-EW<XL3H!w^_Js!G+wjrV6dQ!mrd^ySe1HVf#S=rVZ?Qx4qWf
z4u5vXQsK}2FJ<>nA1^$?;o2N&J7XT}VXlJp?CH(BPW05?-<^N|%#;8});hWVcfT@j
y>|9n*R@;*BgNtdWRPL!55B;{XsHGp@+510`K7V?~ly;!Q89ZJ6T-G@yGywpffPSF>

diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
index f424a6b3c..8335b81ed 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
@@ -46,7 +46,7 @@ import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
 import com.shatteredpixel.shatteredpixeldungeon.levels.CavesLevel;
 import com.shatteredpixel.shatteredpixeldungeon.levels.CityLevel;
 import com.shatteredpixel.shatteredpixeldungeon.levels.DeadEndLevel;
-import com.shatteredpixel.shatteredpixeldungeon.levels.HallsBossLevel;
+import com.shatteredpixel.shatteredpixeldungeon.levels.NewHallsBossLevel;
 import com.shatteredpixel.shatteredpixeldungeon.levels.HallsLevel;
 import com.shatteredpixel.shatteredpixeldungeon.levels.LastLevel;
 import com.shatteredpixel.shatteredpixeldungeon.levels.LastShopLevel;
@@ -295,7 +295,7 @@ public class Dungeon {
 			level = new HallsLevel();
 			break;
 		case 25:
-			level = new HallsBossLevel();
+			level = new NewHallsBossLevel();
 			break;
 		case 26:
 			level = new LastLevel();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
index f01e79b9a..059596fe3 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
@@ -135,6 +135,9 @@ public class ShatteredPixelDungeon extends Game {
 		com.watabou.utils.Bundle.addAlias(
 				com.shatteredpixel.shatteredpixeldungeon.levels.OldCityBossLevel.class,
 				"com.shatteredpixel.shatteredpixeldungeon.levels.CityBossLevel" );
+		com.watabou.utils.Bundle.addAlias(
+				com.shatteredpixel.shatteredpixeldungeon.levels.OldHallsBossLevel.class,
+				"com.shatteredpixel.shatteredpixeldungeon.levels.HallsBossLevel" );
 		
 	}
 	
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java
new file mode 100644
index 000000000..eec60afea
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java
@@ -0,0 +1,43 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2020 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
+
+
+import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
+
+//TODO boss implementation
+public class YogDzewa extends Yog {
+
+	{
+		HP = HT = 1;
+	}
+
+	@Override
+	public void die( Object cause ) {
+
+		super.die( cause );
+
+		Dungeon.level.unseal();
+		Dungeon.level.heaps.get(pos).destroy();
+	}
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java
index 32bc36096..c54804ec5 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java
@@ -22,13 +22,16 @@
 package com.shatteredpixel.shatteredpixeldungeon.levels;
 
 import com.shatteredpixel.shatteredpixeldungeon.Assets;
+import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
 import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
 import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
 import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
 import com.shatteredpixel.shatteredpixeldungeon.items.Amulet;
 import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
 import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
+import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
 import com.watabou.noosa.Group;
+import com.watabou.noosa.Tilemap;
 import com.watabou.utils.Bundle;
 import com.watabou.utils.PathFinder;
 import com.watabou.utils.Random;
@@ -40,6 +43,8 @@ public class LastLevel extends Level {
 	{
 		color1 = 0x801500;
 		color2 = 0xa68521;
+
+		viewDistance = Math.min(4, viewDistance);
 	}
 
 	private int pedestal;
@@ -64,51 +69,67 @@ public class LastLevel extends Level {
 				solid[i] = true;
 			}
 		}
+		for (int i = (height-ROOM_TOP+2)*width; i < length; i++){
+			passable[i] = avoid[i] = false;
+			solid[i] = true;
+		}
+		for (int i = (height-ROOM_TOP+1)*width; i < length; i++){
+			if (i % width < 4 || i % width > 12 || i >= (length-width)){
+				discoverable[i] = false;
+			} else {
+				visited[i] = true;
+			}
+		}
 	}
 
+	private static final int ROOM_TOP = 10;
+
 	@Override
 	protected boolean build() {
 		
 		setSize(16, 64);
 		Arrays.fill( map, Terrain.CHASM );
 
-		int mid = width/2;
+		final int MID = width/2;
 
 		Painter.fill( this, 0, height-1, width, 1, Terrain.WALL );
-		Painter.fill( this, mid - 1, 10, 3, (height-11), Terrain.EMPTY);
-		Painter.fill( this, mid - 2, height - 3, 5, 1, Terrain.EMPTY);
-		Painter.fill( this, mid - 3, height - 2, 7, 1, Terrain.EMPTY);
+		Painter.fill( this, MID - 1, 10, 3, (height-11), Terrain.EMPTY);
+		Painter.fill( this, MID - 2, height - 3, 5, 1, Terrain.EMPTY);
+		Painter.fill( this, MID - 3, height - 2, 7, 1, Terrain.EMPTY);
 
-		Painter.fill( this, mid - 2, 9, 5, 7, Terrain.EMPTY);
-		Painter.fill( this, mid - 3, 10, 7, 5, Terrain.EMPTY);
+		Painter.fill( this, MID - 2, 9, 5, 7, Terrain.EMPTY);
+		Painter.fill( this, MID - 3, 10, 7, 5, Terrain.EMPTY);
 
-		entrance = (height-2) * width() + mid;
+		entrance = (height-ROOM_TOP) * width() + MID;
+		Painter.fill(this, 0, height - ROOM_TOP, width, 2, Terrain.WALL);
 		map[entrance] = Terrain.ENTRANCE;
+		map[entrance+width] = Terrain.ENTRANCE;
+		Painter.fill(this, 0, height - ROOM_TOP + 2, width, 8, Terrain.EMPTY);
+		Painter.fill(this, MID-1, height - ROOM_TOP + 2, 3, 1, Terrain.ENTRANCE);
 
-		pedestal = 12*(width()) + mid;
-		map[pedestal] = Terrain.PEDESTAL;
-		map[pedestal-1-width()] = map[pedestal+1-width()] = map[pedestal-1+width()] = map[pedestal+1+width()] = Terrain.STATUE_SP;
-
+		pedestal = 12*(width()) + MID;
 		exit = pedestal;
 
-		int pos = pedestal;
-
-		map[pos-width()] = map[pos-1] = map[pos+1] = map[pos-2] = map[pos+2] = Terrain.WATER;
-		pos+=width();
-		map[pos] = map[pos-2] = map[pos+2] = map[pos-3] = map[pos+3] = Terrain.WATER;
-		pos+=width();
-		map[pos-3] = map[pos-2] = map[pos-1] = map[pos] = map[pos+1] = map[pos+2] = map[pos+3] = Terrain.WATER;
-		pos+=width();
-		map[pos-2] = map[pos+2] = Terrain.WATER;
-		
 		for (int i=0; i < length(); i++) {
-			if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
+			if (map[i] == Terrain.EMPTY && Random.Int( 5 ) == 0) {
 				map[i] = Terrain.EMPTY_DECO;
 			}
 		}
 
 		feeling = Feeling.NONE;
 
+		CustomTilemap vis = new CustomFloor();
+		vis.setRect( 5, 0, 7, height - ROOM_TOP);
+		customTiles.add(vis);
+
+		vis = new CenterPieceVisuals();
+		vis.pos(0, height - ROOM_TOP);
+		customTiles.add(vis);
+
+		vis = new CenterPieceWalls();
+		vis.pos(0, height - ROOM_TOP-1);
+		customWalls.add(vis);
+
 		return true;
 	}
 	
@@ -190,5 +211,109 @@ public class LastLevel extends Level {
 				solid[i] = true;
 			}
 		}
+		for (int i = (height-ROOM_TOP+2)*width; i < length; i++){
+			passable[i] = avoid[i] = false;
+			solid[i] = true;
+		}
+		for (int i = (height-ROOM_TOP+1)*width; i < length; i++){
+			if (i % width < 4 || i % width > 12 || i >= (length-width)){
+				discoverable[i] = false;
+			} else {
+				visited[i] = true;
+			}
+		}
+	}
+
+	public static class CustomFloor extends CustomTilemap {
+
+		{
+			texture = Assets.HALLS_SP;
+		}
+
+		@Override
+		public Tilemap create() {
+			Tilemap v = super.create();
+			int cell = tileX + tileY * Dungeon.level.width();
+			int[] map = Dungeon.level.map;
+			int[] data = new int[tileW*tileH];
+			for (int i = 0; i < data.length; i++){
+				if (i % tileW == 0){
+					cell = tileX + (tileY + i / tileW) * Dungeon.level.width();
+				}
+				if (map[cell] == Terrain.EMPTY_DECO) {
+					data[i] = 27;
+				} else if (map[cell] == Terrain.EMPTY) {
+					data[i] = 19;
+					if (map[cell+Dungeon.level.width] == Terrain.CHASM) {
+						data[i+tileW] = 6;
+					}
+				} else if (data[i] == 0) {
+					data[i] = -1;
+				}
+				cell++;
+			}
+			v.map( data, tileW );
+			return v;
+		}
+
+	}
+
+	public static class CenterPieceVisuals extends CustomTilemap {
+
+		{
+			texture = Assets.HALLS_SP;
+
+			tileW = 16;
+			tileH = 10;
+		}
+
+		private static final int[] map = new int[]{
+				-1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1,
+				 0,  0,  0,  0,  8,  9, 10, 11, 19, 11, 12, 13, 14,  0,  0,  0,
+				 0,  0,  0,  0, 16, 17, 18, 19, 19, 19, 20, 21, 22,  0,  0,  0,
+				 0,  0,  0,  0, 24, 25, 26, 27, 19, 27, 28, 29, 30,  0,  0,  0,
+				 0,  0,  0,  0, 24, 25, 26, 19, 19, 19, 28, 29, 30,  0,  0,  0,
+				 0,  0,  0,  0, 24, 25, 26, 27, 19, 27, 28, 29, 30,  0,  0,  0,
+				 0,  0,  0,  0, 24, 25, 34, 35, 35, 35, 34, 29, 30,  0,  0,  0,
+				 0,  0,  0,  0, 40, 41, 36, 36, 36, 36, 36, 40, 41,  0,  0,  0,
+				 0,  0,  0,  0, 48, 49, 36, 36, 36, 36, 36, 48, 49,  0,  0,  0,
+				 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+		};
+
+		@Override
+		public Tilemap create() {
+			Tilemap v = super.create();
+			v.map(map, tileW);
+			return v;
+		}
+	}
+
+	public static class CenterPieceWalls extends CustomTilemap {
+
+		{
+			texture = Assets.HALLS_SP;
+
+			tileW = 16;
+			tileH = 9;
+		}
+
+		private static final int[] map = new int[]{
+				 4,  4,  4,  4,  4,  4,  4,  5,  7,  3,  4,  4,  4,  4,  4,  4,
+				 0,  0,  0,  0,  0,  0,  0,  1, 15,  2,  0,  0,  0,  0,  0,  0,
+				-1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, 32, 33, -1, -1, -1, -1, -1, 32, 33, -1, -1, -1,
+				-1, -1, -1, -1, 40, 41, -1, -1, -1, -1, -1, 40, 41, -1, -1, -1,
+		};
+
+		@Override
+		public Tilemap create() {
+			Tilemap v = super.create();
+			v.map(map, tileW);
+			return v;
+		}
 	}
 }
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewHallsBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewHallsBossLevel.java
new file mode 100644
index 000000000..bd6866187
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewHallsBossLevel.java
@@ -0,0 +1,354 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2019 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package com.shatteredpixel.shatteredpixeldungeon.levels;
+
+import com.shatteredpixel.shatteredpixeldungeon.Assets;
+import com.shatteredpixel.shatteredpixeldungeon.Bones;
+import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
+import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
+import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
+import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogDzewa;
+import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog;
+import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
+import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
+import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
+import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
+import com.shatteredpixel.shatteredpixeldungeon.items.Item;
+import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
+import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
+import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
+import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
+import com.watabou.noosa.Group;
+import com.watabou.noosa.Tilemap;
+import com.watabou.utils.PathFinder;
+import com.watabou.utils.Random;
+
+public class NewHallsBossLevel extends Level {
+
+	{
+		color1 = 0x801500;
+		color2 = 0xa68521;
+
+		viewDistance = Math.min(4, viewDistance);
+	}
+
+	private static final int WIDTH = 32;
+	private static final int HEIGHT = 32;
+
+	private static final int ROOM_LEFT		= WIDTH / 2 - 4;
+	private static final int ROOM_RIGHT		= WIDTH / 2 + 4;
+	private static final int ROOM_TOP		= 8;
+	private static final int ROOM_BOTTOM	= ROOM_TOP + 8;
+
+	@Override
+	public String tilesTex() {
+		return Assets.TILES_HALLS;
+	}
+
+	@Override
+	public String waterTex() {
+		return Assets.WATER_HALLS;
+	}
+
+	@Override
+	protected boolean build() {
+
+		setSize(WIDTH, HEIGHT);
+
+		for (int i = 0; i < 5; i++) {
+
+			int top;
+			int bottom;
+
+			if (i == 0 || i == 4){
+				top = Random.IntRange(ROOM_TOP-1, ROOM_TOP+3);
+				bottom = Random.IntRange(ROOM_BOTTOM+2, ROOM_BOTTOM+6);
+			} else if (i == 1 || i == 3){
+				top = Random.IntRange(ROOM_TOP-5, ROOM_TOP-1);
+				bottom = Random.IntRange(ROOM_BOTTOM+6, ROOM_BOTTOM+10);
+			} else {
+				top = Random.IntRange(ROOM_TOP-6, ROOM_TOP-3);
+				bottom = Random.IntRange(ROOM_BOTTOM+8, ROOM_BOTTOM+12);
+			}
+
+			Painter.fill(this, 4 + i * 5, top, 5, bottom - top + 1, Terrain.EMPTY);
+
+			if (i == 2) {
+				entrance = (6 + i * 5) + (bottom - 1) * width();
+			}
+
+		}
+
+		boolean[] patch = Patch.generate(width, height, 0.20f, 0, true);
+		for (int i = 0; i < length(); i++) {
+			if (map[i] == Terrain.EMPTY && patch[i]) {
+				map[i] = Terrain.STATUE;
+			}
+		}
+
+		map[entrance] = Terrain.ENTRANCE;
+
+		Painter.fill(this, ROOM_LEFT-1, ROOM_TOP-1, 11, 11, Terrain.EMPTY );
+
+		patch = Patch.generate(width, height, 0.30f, 3, true);
+		for (int i = 0; i < length(); i++) {
+			if ((map[i] == Terrain.EMPTY || map[i] == Terrain.STATUE) && patch[i]) {
+				map[i] = Terrain.WATER;
+			}
+		}
+
+		for (int i = 0; i < length(); i++) {
+			if (map[i] == Terrain.EMPTY && Random.Int(4) == 0) {
+				map[i] = Terrain.EMPTY_DECO;
+			}
+		}
+
+		Painter.fill(this, ROOM_LEFT, ROOM_TOP, 9, 9, Terrain.EMPTY_SP );
+
+		Painter.fill(this, ROOM_LEFT, ROOM_TOP, 9, 2, Terrain.WALL_DECO );
+		Painter.fill(this, ROOM_LEFT, ROOM_BOTTOM-1, 2, 2, Terrain.WALL_DECO );
+		Painter.fill(this, ROOM_RIGHT-1, ROOM_BOTTOM-1, 2, 2, Terrain.WALL_DECO );
+
+		Painter.fill(this, ROOM_LEFT+3, ROOM_TOP+3, 3, 3, Terrain.EMPTY );
+
+		exit = width/2 + ((ROOM_TOP+1) * width);
+		//map[exit] = Terrain.EXIT;
+
+		CustomTilemap vis = new CenterPieceVisuals();
+		vis.pos(ROOM_LEFT, ROOM_TOP+1);
+		customTiles.add(vis);
+
+		vis = new CenterPieceWalls();
+		vis.pos(ROOM_LEFT, ROOM_TOP);
+		customWalls.add(vis);
+
+		//basic version of building flag maps for the pathfinder test
+		for (int i = 0; i < length; i++){
+			passable[i]	= ( Terrain.flags[map[i]] & Terrain.PASSABLE) != 0;
+		}
+
+		//ensures a path to the exit exists
+		return (PathFinder.getStep(entrance, exit, passable) != -1);
+	}
+
+	@Override
+	protected void createMobs() {
+	}
+
+	public Actor respawner() {
+		return null;
+	}
+
+	@Override
+	protected void createItems() {
+		Item item = Bones.get();
+		if (item != null) {
+			int pos;
+			do {
+				pos = Random.IntRange( ROOM_LEFT, ROOM_RIGHT ) + Random.IntRange( ROOM_TOP + 1, ROOM_BOTTOM ) * width();
+			} while (pos == entrance);
+			drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
+		}
+	}
+
+	@Override
+	public int randomRespawnCell( Char ch ) {
+		int pos = entrance;
+		int cell;
+		do {
+			cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
+		} while (!passable[cell]
+				|| (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell])
+				|| Actor.findChar(cell) != null);
+		return cell;
+	}
+
+	@Override
+	public void occupyCell( Char ch ) {
+		super.occupyCell( ch );
+
+		if (map[entrance] == Terrain.ENTRANCE && map[exit] != Terrain.EXIT
+				&& ch == Dungeon.hero && ch.pos != entrance) {
+
+			seal();
+		}
+	}
+
+	@Override
+	public void seal() {
+		set( entrance, Terrain.EMPTY_SP );
+		GameScene.updateMap( entrance );
+		CellEmitter.get( entrance ).start( FlameParticle.FACTORY, 0.1f, 10 );
+
+		Dungeon.observe();
+
+		Yog boss = new YogDzewa();
+		boss.pos = exit + width*3;
+		GameScene.add( boss );
+		//boss.spawnFists();
+	}
+
+	@Override
+	public void unseal() {
+		set( entrance, Terrain.ENTRANCE );
+		GameScene.updateMap( entrance );
+
+		set( exit, Terrain.EXIT );
+		GameScene.updateMap( exit );
+
+		CellEmitter.get(exit-1).burst(ShadowParticle.UP, 25);
+		CellEmitter.get(exit).burst(ShadowParticle.UP, 100);
+		CellEmitter.get(exit+1).burst(ShadowParticle.UP, 25);
+		GameScene.flash(0);
+		for( CustomTilemap t : customTiles){
+			if (t instanceof CenterPieceVisuals){
+				((CenterPieceVisuals) t).updateState();
+			}
+		}
+		for( CustomTilemap t : customWalls){
+			if (t instanceof CenterPieceWalls){
+				((CenterPieceWalls) t).updateState();
+			}
+		}
+
+		Dungeon.observe();
+	}
+
+	@Override
+	public String tileName( int tile ) {
+		switch (tile) {
+			case Terrain.WATER:
+				return Messages.get(HallsLevel.class, "water_name");
+			case Terrain.GRASS:
+				return Messages.get(HallsLevel.class, "grass_name");
+			case Terrain.HIGH_GRASS:
+				return Messages.get(HallsLevel.class, "high_grass_name");
+			case Terrain.STATUE:
+			case Terrain.STATUE_SP:
+				return Messages.get(HallsLevel.class, "statue_name");
+			default:
+				return super.tileName( tile );
+		}
+	}
+
+	@Override
+	public String tileDesc(int tile) {
+		switch (tile) {
+			case Terrain.WATER:
+				return Messages.get(HallsLevel.class, "water_desc");
+			case Terrain.STATUE:
+			case Terrain.STATUE_SP:
+				return Messages.get(HallsLevel.class, "statue_desc");
+			case Terrain.BOOKSHELF:
+				return Messages.get(HallsLevel.class, "bookshelf_desc");
+			default:
+				return super.tileDesc( tile );
+		}
+	}
+
+	@Override
+	public Group addVisuals () {
+		super.addVisuals();
+		HallsLevel.addHallsVisuals( this, visuals );
+		return visuals;
+	}
+
+	public static class CenterPieceVisuals extends CustomTilemap {
+
+		{
+			texture = Assets.HALLS_SP;
+
+			tileW = 9;
+			tileH = 8;
+		}
+
+		private static final int[] map = new int[]{
+				8,  9, 10, 11, 11, 11, 12, 13, 14,
+				16, 17, 18, 19, 19, 19, 20, 21, 22,
+				24, 25, 26, 27, 19, 27, 28, 29, 30,
+				24, 25, 26, 19, 19, 19, 28, 29, 30,
+				24, 25, 26, 27, 19, 27, 28, 29, 30,
+				24, 25, 34, 35, 35, 35, -1, 29, 30,
+				40, 41, 36, 36, 36, 36, 36, 40, 41,
+				48, 49, 36, 36, 36, 36, 36, 48, 49
+		};
+
+		@Override
+		public Tilemap create() {
+			Tilemap v = super.create();
+			updateState();
+			return v;
+		}
+
+		private void updateState(){
+			if (vis != null){
+				int[] data = map.clone();
+				if (Dungeon.level.map[Dungeon.level.exit] == Terrain.EXIT) {
+					data[4] = 19;
+				}
+				vis.map(data, tileW);
+			}
+		}
+	}
+
+	public static class CenterPieceWalls extends CustomTilemap {
+
+		{
+			texture = Assets.HALLS_SP;
+
+			tileW = 9;
+			tileH = 9;
+		}
+
+		private static final int[] map = new int[]{
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				-1, -1, -1, -1, -1, -1, -1, -1, -1,
+				32, 33, -1, -1, -1, -1, -1, 32, 33,
+				40, 41, -1, -1, -1, -1, -1, 40, 41,
+		};
+
+		@Override
+		public Tilemap create() {
+			Tilemap v = super.create();
+			updateState();
+			return v;
+		}
+
+		private void updateState(){
+			if (vis != null){
+				int[] data = map.clone();
+				if (Dungeon.level.map[Dungeon.level.exit] == Terrain.EXIT) {
+					data[3] = 1;
+					data[4] = 0;
+					data[5] = 2;
+					data[13] = 23;
+				}
+				vis.map(data, tileW);
+			}
+		}
+
+	}
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/OldHallsBossLevel.java
similarity index 99%
rename from core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java
rename to core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/OldHallsBossLevel.java
index b6c1f6808..283a7e39d 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/OldHallsBossLevel.java
@@ -40,7 +40,7 @@ import com.watabou.utils.Bundle;
 import com.watabou.utils.PathFinder;
 import com.watabou.utils.Random;
 
-public class HallsBossLevel extends Level {
+public class OldHallsBossLevel extends Level {
 	
 	{
 		color1 = 0x801500;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java
index 21532e17b..fec1e261a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java
@@ -83,12 +83,16 @@ public class DemonSpawnerRoom extends SpecialRoom {
 		@Override
 		public Tilemap create() {
 			Tilemap v = super.create();
-			int top = tileX + tileY* Dungeon.level.width();
+			int cell = tileX + tileY * Dungeon.level.width();
 			int[] map = Dungeon.level.map;
 			int[] data = new int[tileW*tileH];
 			for (int i = 0; i < data.length; i++){
-				if (map[i+top] == Terrain.EMPTY_DECO) data[i] = 1;
-				else                                  data[i] = 0;
+				if (i % tileW == 0){
+					cell = tileX + (tileY + i / tileW) * Dungeon.level.width();
+				}
+				if (map[cell] == Terrain.EMPTY_DECO)    data[i] = 27;
+				else                                    data[i] = 19;
+				cell++;
 			}
 			v.map( data, tileW );
 			return v;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java
index 3da9c7d38..6000f3af9 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java
@@ -22,6 +22,7 @@
 package com.shatteredpixel.shatteredpixeldungeon.tiles;
 
 import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
+import com.shatteredpixel.shatteredpixeldungeon.levels.NewHallsBossLevel;
 import com.watabou.noosa.TextureFilm;
 import com.watabou.noosa.Tilemap;
 
@@ -63,6 +64,14 @@ public class WallBlockingTilemap extends Tilemap {
 	
 	@Override
 	public synchronized void updateMapCell(int cell) {
+
+		//FIXME this is to address the wall blocking looking odd on the new yog floor.
+		// The true solution is to improve the fog of war so the blockers aren't necessary.
+		if (Dungeon.level instanceof NewHallsBossLevel){
+			data[cell] = CLEARED;
+			super.updateMapCell(cell);
+			return;
+		}
 		
 		//TODO should doors be considered? currently the blocking is a bit permissive around doors