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
This commit is contained in:
parent
cf793e3b0d
commit
b369cf28ea
|
@ -106,7 +106,11 @@ public class NewTengu extends Mob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int attackSkill( Char target ) {
|
public int attackSkill( Char target ) {
|
||||||
return 18;
|
if (Dungeon.level.adjacent(pos, target.pos)){
|
||||||
|
return 12;
|
||||||
|
} else {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -138,7 +142,7 @@ public class NewTengu extends Mob {
|
||||||
|
|
||||||
//tengu cannot be hit through multiple brackets at a time
|
//tengu cannot be hit through multiple brackets at a time
|
||||||
if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){
|
if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){
|
||||||
HP = hpBracket * ((beforeHitHP/hpBracket)-1);
|
HP = hpBracket * ((beforeHitHP/hpBracket)-1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
||||||
|
@ -239,7 +243,7 @@ public class NewTengu extends Mob {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
newPos = ((NewPrisonBossLevel)Dungeon.level).randomTenguCellPos();
|
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 );
|
if (level.heroFOV[pos]) CellEmitter.get( pos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
|
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
|
import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator;
|
import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
|
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
|
||||||
import com.watabou.noosa.Camera;
|
import com.watabou.noosa.Camera;
|
||||||
|
@ -75,7 +74,8 @@ public class NewPrisonBossLevel extends Level {
|
||||||
public enum State {
|
public enum State {
|
||||||
START,
|
START,
|
||||||
FIGHT_START,
|
FIGHT_START,
|
||||||
TRAP_MAZES,
|
TRAP_MAZES, //pre-0.8.1 saves
|
||||||
|
FIGHT_PAUSE,
|
||||||
FIGHT_ARENA,
|
FIGHT_ARENA,
|
||||||
WON
|
WON
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ public class NewPrisonBossLevel extends Level {
|
||||||
state = bundle.getEnum( STATE, State.class );
|
state = bundle.getEnum( STATE, State.class );
|
||||||
|
|
||||||
//in some states tengu won't be in the world, in others he will be.
|
//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 );
|
tengu = (NewTengu)bundle.get( TENGU );
|
||||||
} else {
|
} else {
|
||||||
for (Mob mob : mobs){
|
for (Mob mob : mobs){
|
||||||
|
@ -190,62 +190,25 @@ public class NewPrisonBossLevel extends Level {
|
||||||
|
|
||||||
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.LOCKED_DOOR);
|
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.LOCKED_DOOR);
|
||||||
|
|
||||||
drop(new IronKey(10), randomPrisonCellPos());
|
|
||||||
|
|
||||||
for (Point p : startTorches){
|
for (Point p : startTorches){
|
||||||
Painter.set(this, p, Terrain.WALL_DECO);
|
Painter.set(this, p, Terrain.WALL_DECO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Rect mazeHallway = new Rect(9, 6, 12, 24);
|
private void setMapPause(){
|
||||||
private static final Rect[] mazeCells = new Rect[]{ new Rect(1, 9, 10, 16), new Rect(11, 9, 20, 16),
|
setMapStart();
|
||||||
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(){
|
|
||||||
exit = entrance = 0;
|
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, tenguCell.left+4, tenguCell.top, Terrain.DOOR);
|
||||||
|
|
||||||
Painter.set(this, mazeHallway.left+1, mazeHallway.top+2, Terrain.LOCKED_DOOR);
|
Painter.fill(this, startCells[1].left, startCells[1].top+3, 1, 7, Terrain.EMPTY);
|
||||||
Painter.set(this, mazeHallway.left+1, mazeHallway.top+4, Terrain.LOCKED_DOOR);
|
Painter.fill(this, startCells[1].left+2, startCells[1].top+2, 3, 10, Terrain.EMPTY);
|
||||||
Painter.set(this, mazeHallway.left+1, mazeHallway.top+8, Terrain.LOCKED_DOOR);
|
|
||||||
Painter.set(this, mazeHallway.left+1, mazeHallway.top+10, Terrain.LOCKED_DOOR);
|
Painter.fill(this, entranceRoom, Terrain.WALL);
|
||||||
|
Painter.set(this, startHallway.left+1, startHallway.top, Terrain.EMPTY);
|
||||||
for (Point p : mazeKeySpawns){
|
Painter.set(this, startHallway.left+1, startHallway.top+1, Terrain.DOOR);
|
||||||
drop(new IronKey(10), pointToCell(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Point p : mazeTorches){
|
|
||||||
Painter.set(this, p, Terrain.WALL_DECO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Rect arena = new Rect(3, 1, 18, 16);
|
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 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 Point levelExit = new Point( endStart.x+12, endStart.y+6);
|
||||||
private static final int[] endMap = new int[]{
|
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, W, W, W, W, W, W, W, W, W, W,
|
||||||
W, e, e, e, e, e, e, e, e, 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,
|
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
|
clearEntities( tenguCell ); //clear anything not in tengu's cell
|
||||||
|
|
||||||
setMapMazes();
|
setMapPause();
|
||||||
cleanMapState();
|
cleanMapState();
|
||||||
|
|
||||||
Actor.remove(tengu);
|
Actor.remove(tengu);
|
||||||
|
@ -443,10 +406,11 @@ public class NewPrisonBossLevel extends Level {
|
||||||
GameScene.flash(0xFFFFFF);
|
GameScene.flash(0xFFFFFF);
|
||||||
Sample.INSTANCE.play(Assets.Sounds.BLAST);
|
Sample.INSTANCE.play(Assets.Sounds.BLAST);
|
||||||
|
|
||||||
state = State.TRAP_MAZES;
|
state = State.FIGHT_PAUSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRAP_MAZES:
|
case TRAP_MAZES: //for pre-0.8.1 saves
|
||||||
|
case FIGHT_PAUSE:
|
||||||
|
|
||||||
Dungeon.hero.interrupt();
|
Dungeon.hero.interrupt();
|
||||||
|
|
||||||
|
@ -531,63 +495,10 @@ public class NewPrisonBossLevel extends Level {
|
||||||
progress();
|
progress();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TRAP_MAZES:
|
case TRAP_MAZES: //pre-0.8.1
|
||||||
|
case FIGHT_PAUSE:
|
||||||
|
|
||||||
for (int i = 0; i < mazeCellDoors.length; i++){
|
if (cellToPoint(ch.pos).y <= startHallway.top+1){
|
||||||
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){
|
|
||||||
progress();
|
progress();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -610,6 +521,7 @@ public class NewPrisonBossLevel extends Level {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
drop( item, randomRespawnCell( null ) ).setHauntedIfCursed().type = Heap.Type.REMAINS;
|
drop( item, randomRespawnCell( null ) ).setHauntedIfCursed().type = Heap.Type.REMAINS;
|
||||||
}
|
}
|
||||||
|
drop(new IronKey(10), randomPrisonCellPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int randomPrisonCellPos(){
|
private int randomPrisonCellPos(){
|
||||||
|
@ -648,7 +560,10 @@ public class NewPrisonBossLevel extends Level {
|
||||||
trapsPatch = Patch.generate(7, 7, fill, 0, false);
|
trapsPatch = Patch.generate(7, 7, fill, 0, false);
|
||||||
|
|
||||||
PathFinder.buildDistanceMap(tenguPos, BArray.not(trapsPatch, null));
|
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());
|
PathFinder.setMapSize(width(), height());
|
||||||
|
|
||||||
|
@ -658,7 +573,8 @@ public class NewPrisonBossLevel extends Level {
|
||||||
int y = i / 7;
|
int y = i / 7;
|
||||||
int cell = x+tenguCell.left+1 + (y+tenguCell.top+1)*width();
|
int cell = x+tenguCell.left+1 + (y+tenguCell.top+1)*width();
|
||||||
if (Blob.volumeAt(cell, StormCloud.class) == 0
|
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);
|
Level.set(cell, Terrain.SECRET_TRAP);
|
||||||
setTrap(new TenguDartTrap().hide(), cell);
|
setTrap(new TenguDartTrap().hide(), cell);
|
||||||
CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2);
|
CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user