From b369cf28ea08aaf43d9b4a483b9bd0e8a10f892c Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 9 May 2020 19:27:59 -0400 Subject: [PATCH] v0.8.1: design improvements to Tengu: - Removed phase 2 entirely, replaced with a brief pause before phase 3 (now phase 2) - Increased the intensity of traps in phase 1 to compensate - Fixed a bug that could let high damage builds skip some Tengu jumps - Reduced Tengu's accuracy a bit in melee range to help melee characters --- .../actors/mobs/NewTengu.java | 10 +- .../levels/NewPrisonBossLevel.java | 148 ++++-------------- 2 files changed, 39 insertions(+), 119 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewTengu.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewTengu.java index bd447bf3c..726296c84 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewTengu.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewTengu.java @@ -106,7 +106,11 @@ public class NewTengu extends Mob { @Override public int attackSkill( Char target ) { - return 18; + if (Dungeon.level.adjacent(pos, target.pos)){ + return 12; + } else { + return 18; + } } @Override @@ -138,7 +142,7 @@ public class NewTengu extends Mob { //tengu cannot be hit through multiple brackets at a time if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){ - HP = hpBracket * ((beforeHitHP/hpBracket)-1); + HP = hpBracket * ((beforeHitHP/hpBracket)-1) + 1; } LockedFloor lock = Dungeon.hero.buff(LockedFloor.class); @@ -239,7 +243,7 @@ public class NewTengu extends Mob { do { newPos = ((NewPrisonBossLevel)Dungeon.level).randomTenguCellPos(); - } while ( (level.distance(newPos, enemy.pos) < 3 || Actor.findChar(newPos) != null)); + } while ( (level.trueDistance(newPos, enemy.pos) <= 4 || Actor.findChar(newPos) != null)); if (level.heroFOV[pos]) CellEmitter.get( pos ).burst( Speck.factory( Speck.WOOL ), 6 ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewPrisonBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewPrisonBossLevel.java index 765d087f1..59875e2fd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewPrisonBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewPrisonBossLevel.java @@ -45,7 +45,6 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap; -import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; import com.shatteredpixel.shatteredpixeldungeon.utils.BArray; import com.watabou.noosa.Camera; @@ -75,7 +74,8 @@ public class NewPrisonBossLevel extends Level { public enum State { START, FIGHT_START, - TRAP_MAZES, + TRAP_MAZES, //pre-0.8.1 saves + FIGHT_PAUSE, FIGHT_ARENA, WON } @@ -117,7 +117,7 @@ public class NewPrisonBossLevel extends Level { state = bundle.getEnum( STATE, State.class ); //in some states tengu won't be in the world, in others he will be. - if (state == State.START || state == State.TRAP_MAZES) { + if (state == State.START || state == State.TRAP_MAZES || state == State.FIGHT_PAUSE) { tengu = (NewTengu)bundle.get( TENGU ); } else { for (Mob mob : mobs){ @@ -190,62 +190,25 @@ public class NewPrisonBossLevel extends Level { Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.LOCKED_DOOR); - drop(new IronKey(10), randomPrisonCellPos()); - for (Point p : startTorches){ Painter.set(this, p, Terrain.WALL_DECO); } } - - private static final Rect mazeHallway = new Rect(9, 6, 12, 24); - private static final Rect[] mazeCells = new Rect[]{ new Rect(1, 9, 10, 16), new Rect(11, 9, 20, 16), - new Rect(3, 15, 10, 22), new Rect(11, 15, 18, 22)}; - private static final Point[] mazeKeySpawns = new Point[]{new Point(mazeCells[0].left+1, mazeCells[0].top+3), - new Point(mazeCells[1].right-2, mazeCells[1].top+3), - new Point(mazeCells[2].left+1, mazeCells[2].top+3), - new Point(mazeCells[3].right-2, mazeCells[3].top+3)}; - private static final Point[] mazeCellDoors = new Point[]{new Point(mazeCells[0].right-1, mazeCells[0].top+3), - new Point(mazeCells[1].left, mazeCells[1].top+3), - new Point(mazeCells[2].right-1, mazeCells[2].top+3), - new Point(mazeCells[3].left, mazeCells[3].top+3)}; - private static final Point[] mazeTorches = new Point[]{ new Point(5, 9), new Point(15, 9), - new Point(6, 15), new Point(14, 15), - new Point(8, 23), new Point(12, 23)}; - - private void setMapMazes(){ + + private void setMapPause(){ + setMapStart(); + exit = entrance = 0; - - Painter.fill(this, 0, 0, 32, 32, Terrain.WALL); - - Painter.fill(this, mazeHallway, Terrain.WALL); - Painter.fill(this, mazeHallway, 1, Terrain.EMPTY); - - for (Rect r : mazeCells){ - Painter.fill(this, r, Terrain.WALL); - Painter.fill(this, r, 1, Terrain.EMPTY); - } - - for (Point p : mazeCellDoors){ - Painter.set(this, p, Terrain.DOOR); - } - - Painter.fill(this, tenguCell, Terrain.WALL); - Painter.fill(this, tenguCell, 1, Terrain.EMPTY); - + Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR); - - Painter.set(this, mazeHallway.left+1, mazeHallway.top+2, Terrain.LOCKED_DOOR); - Painter.set(this, mazeHallway.left+1, mazeHallway.top+4, Terrain.LOCKED_DOOR); - Painter.set(this, mazeHallway.left+1, mazeHallway.top+8, Terrain.LOCKED_DOOR); - Painter.set(this, mazeHallway.left+1, mazeHallway.top+10, Terrain.LOCKED_DOOR); - - for (Point p : mazeKeySpawns){ - drop(new IronKey(10), pointToCell(p)); - } - - for (Point p : mazeTorches){ - Painter.set(this, p, Terrain.WALL_DECO); - } + + Painter.fill(this, startCells[1].left, startCells[1].top+3, 1, 7, Terrain.EMPTY); + Painter.fill(this, startCells[1].left+2, startCells[1].top+2, 3, 10, Terrain.EMPTY); + + Painter.fill(this, entranceRoom, Terrain.WALL); + Painter.set(this, startHallway.left+1, startHallway.top, Terrain.EMPTY); + Painter.set(this, startHallway.left+1, startHallway.top+1, Terrain.DOOR); + } private static final Rect arena = new Rect(3, 1, 18, 16); @@ -269,7 +232,7 @@ public class NewPrisonBossLevel extends Level { private static final Point endStart = new Point( startHallway.left+2, startHallway.top+2); private static final Point levelExit = new Point( endStart.x+12, endStart.y+6); private static final int[] endMap = new int[]{ - W, W, W, W, W, W, W, W, W, W, W, W, W, W, + W, W, D, W, W, W, W, W, W, W, W, W, W, W, W, e, e, e, W, W, W, W, W, W, W, W, W, W, W, e, e, e, e, e, e, e, e, W, W, W, W, W, e, e, e, e, e, e, e, e, e, e, e, e, W, W, @@ -432,7 +395,7 @@ public class NewPrisonBossLevel extends Level { clearEntities( tenguCell ); //clear anything not in tengu's cell - setMapMazes(); + setMapPause(); cleanMapState(); Actor.remove(tengu); @@ -443,10 +406,11 @@ public class NewPrisonBossLevel extends Level { GameScene.flash(0xFFFFFF); Sample.INSTANCE.play(Assets.Sounds.BLAST); - state = State.TRAP_MAZES; + state = State.FIGHT_PAUSE; break; - - case TRAP_MAZES: + + case TRAP_MAZES: //for pre-0.8.1 saves + case FIGHT_PAUSE: Dungeon.hero.interrupt(); @@ -531,63 +495,10 @@ public class NewPrisonBossLevel extends Level { progress(); } break; - case TRAP_MAZES: + case TRAP_MAZES: //pre-0.8.1 + case FIGHT_PAUSE: - for (int i = 0; i < mazeCellDoors.length; i++){ - if (ch.pos == pointToCell(mazeCellDoors[i]) && !triggered[i]){ - triggered[i] = true; - Maze.allowDiagonals = true; - boolean[][] maze; - boolean validMaze; - - do { - maze = Maze.generate(mazeCells[i], map, width(), Terrain.WALL); - - //prevents a maze that is just a straight line from the door - validMaze = false; - for (int x = 1; x < maze.length-1; x++){ - if (maze[x][3]){ - int cell = mazeCells[i].left+x + width()*(mazeCells[i].top+3); - if (heaps.get(cell) == null) { - validMaze = true; - break; - } - } - } - - } while (!validMaze); - - for (int x = 1; x < maze.length-1; x++) { - for (int y = 1; y < maze[0].length-1; y++) { - if (maze[x][y]){ - int cell = mazeCells[i].left+x + width()*(mazeCells[i].top+y); - if (heaps.get(cell) == null - && Blob.volumeAt(cell, StormCloud.class) == 0 - && Blob.volumeAt(cell, Regrowth.class) <= 9){ - Level.set( cell, Terrain.SECRET_TRAP ); - setTrap(new TenguDartTrap().hide(), cell); - CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2); - } - } - } - } - - FadingTraps f = new FadingTraps(); - f.setCoveringArea(mazeCells[i]); - f.fadeDelay = 2f; - GameScene.add(f, false); - customTiles.add(f); - - Sample.INSTANCE.play(Assets.Sounds.TELEPORT); - int roomCenter = (mazeCells[i].left + mazeCells[i].right)/2 + - (mazeCells[i].top + mazeCells[i].bottom)/2 * width(); - Camera.main.panTo(DungeonTilemap.tileCenterToWorld(roomCenter), 5f); - - Dungeon.hero.interrupt(); - } - } - - if (cellToPoint(ch.pos).y <= mazeHallway.top+2){ + if (cellToPoint(ch.pos).y <= startHallway.top+1){ progress(); } break; @@ -610,6 +521,7 @@ public class NewPrisonBossLevel extends Level { if (item != null) { drop( item, randomRespawnCell( null ) ).setHauntedIfCursed().type = Heap.Type.REMAINS; } + drop(new IronKey(10), randomPrisonCellPos()); } private int randomPrisonCellPos(){ @@ -648,7 +560,10 @@ public class NewPrisonBossLevel extends Level { trapsPatch = Patch.generate(7, 7, fill, 0, false); PathFinder.buildDistanceMap(tenguPos, BArray.not(trapsPatch, null)); - } while (PathFinder.distance[heroPos] > 6); + //note that the effective range of fill is 40%-90% + //so distance to tengu starts at 3-4 tiles and scales up to 7-8 as fill increases + } while (PathFinder.distance[heroPos] > Math.ceil(1 + 7*fill) + || PathFinder.distance[heroPos] < Math.ceil(7*fill)); PathFinder.setMapSize(width(), height()); @@ -658,7 +573,8 @@ public class NewPrisonBossLevel extends Level { int y = i / 7; int cell = x+tenguCell.left+1 + (y+tenguCell.top+1)*width(); if (Blob.volumeAt(cell, StormCloud.class) == 0 - && Blob.volumeAt(cell, Regrowth.class) <= 9) { + && Blob.volumeAt(cell, Regrowth.class) <= 9 + && Actor.findChar(cell) != tengu) { Level.set(cell, Terrain.SECRET_TRAP); setTrap(new TenguDartTrap().hide(), cell); CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2);