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