v1.3.0: Overhauled entrance/exit logic to account for branches

This commit is contained in:
Evan Debenham
2022-05-20 13:50:27 -04:00
parent 5cc8734dc2
commit 654bce1f65
31 changed files with 494 additions and 226 deletions
@@ -91,6 +91,10 @@ public class Bundle {
return !data.isNull( key ); return !data.isNull( key );
} }
public boolean remove( String key ){
return data.remove(key) != null;
}
//JSONObject.keyset() doesn't exist on Android/iOS //JSONObject.keyset() doesn't exist on Android/iOS
public ArrayList<String> getKeys(){ public ArrayList<String> getKeys(){
Iterator<String> keys = data.keys(); Iterator<String> keys = data.keys();
@@ -61,6 +61,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.secret.SecretRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.secret.SecretRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -218,7 +219,7 @@ public class Dungeon {
quickslot.reset(); quickslot.reset();
QuickSlotButton.reset(); QuickSlotButton.reset();
depth = 0; depth = 1;
branch = 0; branch = 0;
gold = 0; gold = 0;
@@ -253,7 +254,6 @@ public class Dungeon {
Dungeon.level = null; Dungeon.level = null;
Actor.clear(); Actor.clear();
depth++;
if (depth > Statistics.deepestFloor) { if (depth > Statistics.deepestFloor) {
Statistics.deepestFloor = depth; Statistics.deepestFloor = depth;
@@ -337,7 +337,7 @@ public class Dungeon {
Actor.clear(); Actor.clear();
level.reset(); level.reset();
switchLevel( level, level.entrance ); switchLevel( level, level.entrance() );
} }
public static long seedCurDepth(){ public static long seedCurDepth(){
@@ -374,9 +374,12 @@ public class Dungeon {
public static void switchLevel( final Level level, int pos ) { public static void switchLevel( final Level level, int pos ) {
if (pos == -2){ if (pos == -2){
pos = level.exit; LevelTransition t = level.getTransition(LevelTransition.Type.REGULAR_EXIT);
} else if (pos < 0 || pos >= level.length() || (!level.passable[pos] && !level.avoid[pos])){ if (t != null) pos = t.cell();
pos = level.entrance; }
if (pos < 0 || pos >= level.length() || (!level.passable[pos] && !level.avoid[pos])){
pos = level.getTransition(null).cell();
} }
PathFinder.setMapSize(level.width(), level.height()); PathFinder.setMapSize(level.width(), level.height());
@@ -30,7 +30,6 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Alchemy;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AdrenalineSurge; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AdrenalineSurge;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AnkhInvulnerability; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AnkhInvulnerability;
@@ -59,7 +58,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.En
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Snake; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Snake;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.CheckedCell; import com.shatteredpixel.shatteredpixeldungeon.effects.CheckedCell;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
@@ -120,6 +118,7 @@ import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster; import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -152,7 +151,6 @@ import com.watabou.utils.Random;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
public class Hero extends Char { public class Hero extends Char {
@@ -709,11 +707,8 @@ public class Hero extends Char {
} else if (curAction instanceof HeroAction.Unlock) { } else if (curAction instanceof HeroAction.Unlock) {
actResult = actUnlock((HeroAction.Unlock) curAction); actResult = actUnlock((HeroAction.Unlock) curAction);
} else if (curAction instanceof HeroAction.Descend) { } else if (curAction instanceof HeroAction.LvlTransition) {
actResult = actDescend( (HeroAction.Descend)curAction ); actResult = actTransition( (HeroAction.LvlTransition)curAction );
} else if (curAction instanceof HeroAction.Ascend) {
actResult = actAscend( (HeroAction.Ascend)curAction );
} else if (curAction instanceof HeroAction.Attack) { } else if (curAction instanceof HeroAction.Attack) {
actResult = actAttack( (HeroAction.Attack)curAction ); actResult = actAttack( (HeroAction.Attack)curAction );
@@ -751,7 +746,7 @@ public class Hero extends Char {
public void interrupt() { public void interrupt() {
if (isAlive() && curAction != null && if (isAlive() && curAction != null &&
((curAction instanceof HeroAction.Move && curAction.dst != pos) || ((curAction instanceof HeroAction.Move && curAction.dst != pos) ||
(curAction instanceof HeroAction.Ascend || curAction instanceof HeroAction.Descend))) { (curAction instanceof HeroAction.LvlTransition))) {
lastAction = curAction; lastAction = curAction;
} }
curAction = null; curAction = null;
@@ -1006,53 +1001,17 @@ public class Hero extends Char {
} }
} }
private boolean actDescend( HeroAction.Descend action ) { private boolean actTransition(HeroAction.LvlTransition action ) {
int stairs = action.dst; int stairs = action.dst;
LevelTransition transition = Dungeon.level.getTransition(stairs);
if (rooted) { if (rooted) {
Camera.main.shake(1, 1f); Camera.main.shake(1, 1f);
ready(); ready();
return false; return false;
//there can be multiple exit tiles, so descend on any of them } else if (transition != null && transition.inside(pos)) {
//TODO this is slightly brittle, it assumes there are no disjointed sets of exit tiles
} else if ((Dungeon.level.map[pos] == Terrain.EXIT || Dungeon.level.map[pos] == Terrain.UNLOCKED_EXIT)) {
curAction = null;
TimekeepersHourglass.timeFreeze timeFreeze = buff(TimekeepersHourglass.timeFreeze.class);
if (timeFreeze != null) timeFreeze.disarmPressedTraps();
Swiftthistle.TimeBubble timeBubble = buff(Swiftthistle.TimeBubble.class);
if (timeBubble != null) timeBubble.disarmPressedTraps();
InterlevelScene.mode = InterlevelScene.Mode.DESCEND;
Game.switchScene( InterlevelScene.class );
return false;
} else if (getCloser( stairs )) {
return true;
} else {
ready();
return false;
}
}
private boolean actAscend( HeroAction.Ascend action ) {
int stairs = action.dst;
if (rooted){
Camera.main.shake( 1, 1f );
ready();
return false;
//there can be multiple entrance tiles, so descend on any of them
//TODO this is slightly brittle, it assumes there are no disjointed sets of entrance tiles
} else if (Dungeon.level.map[pos] == Terrain.ENTRANCE) {
if (Dungeon.depth == 1) {
if (transition.type == LevelTransition.Type.SURFACE){
if (belongings.getItem( Amulet.class ) == null) { if (belongings.getItem( Amulet.class ) == null) {
Game.runOnRenderThread(new Callback() { Game.runOnRenderThread(new Callback() {
@Override @Override
@@ -1078,8 +1037,15 @@ public class Hero extends Char {
Swiftthistle.TimeBubble timeBubble = buff(Swiftthistle.TimeBubble.class); Swiftthistle.TimeBubble timeBubble = buff(Swiftthistle.TimeBubble.class);
if (timeBubble != null) timeBubble.disarmPressedTraps(); if (timeBubble != null) timeBubble.disarmPressedTraps();
InterlevelScene.mode = InterlevelScene.Mode.ASCEND; InterlevelScene.curTransition = transition;
Game.switchScene( InterlevelScene.class ); //TODO probably want to make this more flexible when more types exist
if (transition.type == LevelTransition.Type.REGULAR_EXIT) {
InterlevelScene.mode = InterlevelScene.Mode.DESCEND;
} else {
InterlevelScene.mode = InterlevelScene.Mode.ASCEND;
}
Game.switchScene(InterlevelScene.class);
} }
return false; return false;
@@ -1486,16 +1452,13 @@ public class Hero extends Char {
curAction = new HeroAction.Unlock( cell ); curAction = new HeroAction.Unlock( cell );
} else if ((cell == Dungeon.level.exit || Dungeon.level.map[cell] == Terrain.EXIT || Dungeon.level.map[cell] == Terrain.UNLOCKED_EXIT) } else if (Dungeon.level.getTransition(cell) != null
&& Dungeon.depth < 26) { && !Dungeon.level.locked
&& (Dungeon.depth < 26 || Dungeon.level.getTransition(cell).type == LevelTransition.Type.REGULAR_ENTRANCE) ) {
curAction = new HeroAction.Descend( cell ); curAction = new HeroAction.LvlTransition( cell );
} else if (cell == Dungeon.level.entrance || Dungeon.level.map[cell] == Terrain.ENTRANCE) { } else {
curAction = new HeroAction.Ascend( cell );
} else {
if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell] if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell]
&& Dungeon.level.traps.get(cell) != null && Dungeon.level.traps.get(cell).visible) { && Dungeon.level.traps.get(cell) != null && Dungeon.level.traps.get(cell).visible) {
@@ -64,14 +64,8 @@ public class HeroAction {
} }
} }
public static class Descend extends HeroAction { public static class LvlTransition extends HeroAction {
public Descend( int stairs ) { public LvlTransition(int stairs ) {
this.dst = stairs;
}
}
public static class Ascend extends HeroAction {
public Ascend( int stairs ) {
this.dst = stairs; this.dst = stairs;
} }
} }
@@ -110,7 +110,7 @@ public class WarpBeacon extends ArmorAbility {
armor.charge -= chargeNeeded; armor.charge -= chargeNeeded;
armor.updateQuickslot(); armor.updateQuickslot();
if (tracker.depth == Dungeon.depth){ if (tracker.depth == Dungeon.depth && tracker.branch == Dungeon.branch){
Char existing = Actor.findChar(tracker.pos); Char existing = Actor.findChar(tracker.pos);
ScrollOfTeleportation.appear(hero, tracker.pos); ScrollOfTeleportation.appear(hero, tracker.pos);
@@ -172,6 +172,7 @@ public class WarpBeacon extends ArmorAbility {
InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = tracker.depth; InterlevelScene.returnDepth = tracker.depth;
InterlevelScene.returnBranch = tracker.branch;
InterlevelScene.returnPos = tracker.pos; InterlevelScene.returnPos = tracker.pos;
Game.switchScene( InterlevelScene.class ); Game.switchScene( InterlevelScene.class );
} }
@@ -203,6 +204,7 @@ public class WarpBeacon extends ArmorAbility {
WarpBeaconTracker tracker = new WarpBeaconTracker(); WarpBeaconTracker tracker = new WarpBeaconTracker();
tracker.pos = target; tracker.pos = target;
tracker.depth = Dungeon.depth; tracker.depth = Dungeon.depth;
tracker.branch = Dungeon.branch;
tracker.attachTo(hero); tracker.attachTo(hero);
hero.sprite.operate(target); hero.sprite.operate(target);
@@ -220,6 +222,7 @@ public class WarpBeacon extends ArmorAbility {
int pos; int pos;
int depth; int depth;
int branch;
Emitter e; Emitter e;
@@ -234,12 +237,14 @@ public class WarpBeacon extends ArmorAbility {
public static final String POS = "pos"; public static final String POS = "pos";
public static final String DEPTH = "depth"; public static final String DEPTH = "depth";
public static final String BRANCH = "branch";
@Override @Override
public void storeInBundle(Bundle bundle) { public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle); super.storeInBundle(bundle);
bundle.put(POS, pos); bundle.put(POS, pos);
bundle.put(DEPTH, depth); bundle.put(DEPTH, depth);
bundle.put(BRANCH, branch);
} }
@Override @Override
@@ -247,6 +252,7 @@ public class WarpBeacon extends ArmorAbility {
super.restoreFromBundle(bundle); super.restoreFromBundle(bundle);
pos = bundle.getInt(POS); pos = bundle.getInt(POS);
depth = bundle.getInt(DEPTH); depth = bundle.getInt(DEPTH);
branch = bundle.getInt(BRANCH);
} }
} }
@@ -376,9 +376,9 @@ public class YogDzewa extends Mob {
addFist((YogFist)Reflection.newInstance(challengeSummons.remove(0))); addFist((YogFist)Reflection.newInstance(challengeSummons.remove(0)));
} }
CellEmitter.get(Dungeon.level.exit-1).burst(ShadowParticle.UP, 25); CellEmitter.get(Dungeon.level.exit()-1).burst(ShadowParticle.UP, 25);
CellEmitter.get(Dungeon.level.exit).burst(ShadowParticle.UP, 100); CellEmitter.get(Dungeon.level.exit()).burst(ShadowParticle.UP, 100);
CellEmitter.get(Dungeon.level.exit+1).burst(ShadowParticle.UP, 25); CellEmitter.get(Dungeon.level.exit()+1).burst(ShadowParticle.UP, 25);
if (abilityCooldown < 5) abilityCooldown = 5; if (abilityCooldown < 5) abilityCooldown = 5;
if (summonCooldown < 5) summonCooldown = 5; if (summonCooldown < 5) summonCooldown = 5;
@@ -391,16 +391,16 @@ public class YogDzewa extends Mob {
} }
public void addFist(YogFist fist){ public void addFist(YogFist fist){
fist.pos = Dungeon.level.exit; fist.pos = Dungeon.level.exit();
CellEmitter.get(Dungeon.level.exit-1).burst(ShadowParticle.UP, 25); CellEmitter.get(Dungeon.level.exit()-1).burst(ShadowParticle.UP, 25);
CellEmitter.get(Dungeon.level.exit).burst(ShadowParticle.UP, 100); CellEmitter.get(Dungeon.level.exit()).burst(ShadowParticle.UP, 100);
CellEmitter.get(Dungeon.level.exit+1).burst(ShadowParticle.UP, 25); CellEmitter.get(Dungeon.level.exit()+1).burst(ShadowParticle.UP, 25);
if (abilityCooldown < 5) abilityCooldown = 5; if (abilityCooldown < 5) abilityCooldown = 5;
if (summonCooldown < 5) summonCooldown = 5; if (summonCooldown < 5) summonCooldown = 5;
int targetPos = Dungeon.level.exit + Dungeon.level.width(); int targetPos = Dungeon.level.exit() + Dungeon.level.width();
if (!Dungeon.isChallenged(Challenges.STRONGER_BOSSES) if (!Dungeon.isChallenged(Challenges.STRONGER_BOSSES)
&& Actor.findChar(targetPos) == null){ && Actor.findChar(targetPos) == null){
@@ -414,7 +414,7 @@ public class YogDzewa extends Mob {
} }
GameScene.add(fist, 4); GameScene.add(fist, 4);
Actor.addDelayed( new Pushing( fist, Dungeon.level.exit, fist.pos ), -1 ); Actor.addDelayed( new Pushing( fist, Dungeon.level.exit(), fist.pos ), -1 );
} }
public void updateVisibility( Level level ){ public void updateVisibility( Level level ){
@@ -105,7 +105,7 @@ public abstract class YogFist extends Mob {
private boolean invulnWarned = false; private boolean invulnWarned = false;
protected boolean isNearYog(){ protected boolean isNearYog(){
int yogPos = Dungeon.level.exit + 3*Dungeon.level.width(); int yogPos = Dungeon.level.exit() + 3*Dungeon.level.width();
return Dungeon.level.distance(pos, yogPos) <= 4; return Dungeon.level.distance(pos, yogPos) <= 4;
} }
@@ -339,7 +339,7 @@ public abstract class YogFist extends Mob {
} }
private boolean canSpreadGrass(int cell){ private boolean canSpreadGrass(int cell){
int yogPos = Dungeon.level.exit + Dungeon.level.width()*3; int yogPos = Dungeon.level.exit() + Dungeon.level.width()*3;
return Dungeon.level.distance(cell, yogPos) > 4 && !Dungeon.level.solid[cell] return Dungeon.level.distance(cell, yogPos) > 4 && !Dungeon.level.solid[cell]
&& !(Dungeon.level.map[cell] == Terrain.FURROWED_GRASS || Dungeon.level.map[cell] == Terrain.HIGH_GRASS); && !(Dungeon.level.map[cell] == Terrain.FURROWED_GRASS || Dungeon.level.map[cell] == Terrain.HIGH_GRASS);
} }
@@ -499,7 +499,7 @@ public abstract class YogFist extends Mob {
} while (Dungeon.level.heroFOV[i] } while (Dungeon.level.heroFOV[i]
|| Dungeon.level.solid[i] || Dungeon.level.solid[i]
|| Actor.findChar(i) != null || Actor.findChar(i) != null
|| PathFinder.getStep(i, Dungeon.level.exit, Dungeon.level.passable) == -1); || PathFinder.getStep(i, Dungeon.level.exit(), Dungeon.level.passable) == -1);
ScrollOfTeleportation.appear(this, i); ScrollOfTeleportation.appear(this, i);
state = WANDERING; state = WANDERING;
GameScene.flash(0x80FFFFFF); GameScene.flash(0x80FFFFFF);
@@ -570,7 +570,7 @@ public abstract class YogFist extends Mob {
} while (Dungeon.level.heroFOV[i] } while (Dungeon.level.heroFOV[i]
|| Dungeon.level.solid[i] || Dungeon.level.solid[i]
|| Actor.findChar(i) != null || Actor.findChar(i) != null
|| PathFinder.getStep(i, Dungeon.level.exit, Dungeon.level.passable) == -1); || PathFinder.getStep(i, Dungeon.level.exit(), Dungeon.level.passable) == -1);
ScrollOfTeleportation.appear(this, i); ScrollOfTeleportation.appear(this, i);
state = WANDERING; state = WANDERING;
GameScene.flash(0, false); GameScene.flash(0, false);
@@ -84,18 +84,18 @@ public class RatKing extends NPC {
@Override @Override
protected boolean act() { protected boolean act() {
if (Dungeon.depth < 5){ if (Dungeon.depth < 5){
if (pos == Dungeon.level.exit){ if (pos == Dungeon.level.exit()){
destroy(); destroy();
sprite.killAndErase(); sprite.killAndErase();
} else { } else {
target = Dungeon.level.exit; target = Dungeon.level.exit();
} }
} else if (Dungeon.depth > 5){ } else if (Dungeon.depth > 5){
if (pos == Dungeon.level.entrance){ if (pos == Dungeon.level.entrance()){
destroy(); destroy();
sprite.killAndErase(); sprite.killAndErase();
} else { } else {
target = Dungeon.level.entrance; target = Dungeon.level.entrance();
} }
} }
return super.act(); return super.act();
@@ -285,7 +285,7 @@ public class Wandmaker extends NPC {
do { do {
validPos = true; validPos = true;
npc.pos = level.pointToCell(room.random()); npc.pos = level.pointToCell(room.random());
if (npc.pos == level.entrance){ if (npc.pos == level.entrance()){
validPos = false; validPos = false;
} }
for (Point door : room.connected.values()){ for (Point door : room.connected.values()){
@@ -57,6 +57,7 @@ public class ScrollOfPassage extends ExoticScroll {
InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1 - (Dungeon.depth-2)%5)); InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1 - (Dungeon.depth-2)%5));
InterlevelScene.returnBranch = 0;
InterlevelScene.returnPos = -1; InterlevelScene.returnPos = -1;
Game.switchScene( InterlevelScene.class ); Game.switchScene( InterlevelScene.class );
} }
@@ -51,6 +51,7 @@ public class BeaconOfReturning extends Spell {
} }
public int returnDepth = -1; public int returnDepth = -1;
public int returnBranch = 0;
public int returnPos; public int returnPos;
@Override @Override
@@ -94,6 +95,7 @@ public class BeaconOfReturning extends Spell {
private void setBeacon(Hero hero ){ private void setBeacon(Hero hero ){
returnDepth = Dungeon.depth; returnDepth = Dungeon.depth;
returnBranch = Dungeon.branch;
returnPos = hero.pos; returnPos = hero.pos;
hero.spend( 1f ); hero.spend( 1f );
@@ -120,9 +122,9 @@ public class BeaconOfReturning extends Spell {
} }
} }
if (returnDepth == Dungeon.depth) { if (returnDepth == Dungeon.depth && returnBranch == Dungeon.branch) {
if (!Dungeon.level.passable[returnPos] && !Dungeon.level.avoid[returnPos]){ if (!Dungeon.level.passable[returnPos] && !Dungeon.level.avoid[returnPos]){
returnPos = Dungeon.level.entrance; returnPos = Dungeon.level.entrance();
} }
ScrollOfTeleportation.appear( hero, returnPos ); ScrollOfTeleportation.appear( hero, returnPos );
for(Mob m : Dungeon.level.mobs){ for(Mob m : Dungeon.level.mobs){
@@ -149,6 +151,7 @@ public class BeaconOfReturning extends Spell {
InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = returnDepth; InterlevelScene.returnDepth = returnDepth;
InterlevelScene.returnBranch = returnBranch;
InterlevelScene.returnPos = returnPos; InterlevelScene.returnPos = returnPos;
Game.switchScene( InterlevelScene.class ); Game.switchScene( InterlevelScene.class );
} }
@@ -309,6 +309,7 @@ public class CursedWand {
InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = depth; InterlevelScene.returnDepth = depth;
InterlevelScene.returnBranch = 0;
InterlevelScene.returnPos = -1; InterlevelScene.returnPos = -1;
Game.switchScene(InterlevelScene.class); Game.switchScene(InterlevelScene.class);
@@ -331,8 +331,8 @@ public class WandOfRegrowth extends Wand {
ArrayList<Integer> candidates = new ArrayList<>(); ArrayList<Integer> candidates = new ArrayList<>();
for (int i : PathFinder.NEIGHBOURS8){ for (int i : PathFinder.NEIGHBOURS8){
if (Dungeon.level.passable[pos+i] if (Dungeon.level.passable[pos+i]
&& pos+i != Dungeon.level.entrance && pos+i != Dungeon.level.entrance()
&& pos+i != Dungeon.level.exit){ && pos+i != Dungeon.level.exit()){
candidates.add(pos+i); candidates.add(pos+i);
} }
} }
@@ -371,8 +371,8 @@ public class WandOfRegrowth extends Wand {
ArrayList<Integer> candidates = new ArrayList<>(); ArrayList<Integer> candidates = new ArrayList<>();
for (int i : PathFinder.NEIGHBOURS8){ for (int i : PathFinder.NEIGHBOURS8){
if (Dungeon.level.passable[pos+i] if (Dungeon.level.passable[pos+i]
&& pos+i != Dungeon.level.entrance && pos+i != Dungeon.level.entrance()
&& pos+i != Dungeon.level.exit){ && pos+i != Dungeon.level.exit()){
candidates.add(pos+i); candidates.add(pos+i);
} }
} }
@@ -40,6 +40,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.BlastParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.CavesPainter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.CavesPainter;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -151,7 +152,10 @@ public class CavesBossLevel extends Level {
Painter.fill(this, 16, 5, 1, 6, Terrain.EMPTY_SP); Painter.fill(this, 16, 5, 1, 6, Terrain.EMPTY_SP);
Painter.fill(this, 15, 0, 3, 3, Terrain.EXIT); Painter.fill(this, 15, 0, 3, 3, Terrain.EXIT);
exit = 16 + 2*width(); int exitCell = 16 + 2*width();
LevelTransition exit = new LevelTransition(this, exitCell, LevelTransition.Type.REGULAR_EXIT);
exit.set(14, 0, 18, 2);
transitions.add(exit);
CustomTilemap customVisuals = new CityEntrance(); CustomTilemap customVisuals = new CityEntrance();
customVisuals.setRect(0, 0, width(), 11); customVisuals.setRect(0, 0, width(), 11);
@@ -173,6 +177,13 @@ public class CavesBossLevel extends Level {
public void restoreFromBundle(Bundle bundle) { public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle); super.restoreFromBundle(bundle);
//pre-1.3.0 saves, modifies exit transition with custom size
if (bundle.contains("exit")){
LevelTransition exit = getTransition(LevelTransition.Type.REGULAR_EXIT);
exit.set(14, 0, 18, 2);
transitions.add(exit);
}
for (CustomTilemap c : customTiles){ for (CustomTilemap c : customTiles){
if (c instanceof ArenaVisuals){ if (c instanceof ArenaVisuals){
customArenaVisuals = (ArenaVisuals) c; customArenaVisuals = (ArenaVisuals) c;
@@ -201,7 +212,7 @@ public class CavesBossLevel extends Level {
int pos; int pos;
do { do {
pos = randomRespawnCell(null); pos = randomRespawnCell(null);
} while (pos == entrance); } while (pos == entrance());
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
} }
} }
@@ -209,12 +220,12 @@ public class CavesBossLevel extends Level {
@Override @Override
public int randomRespawnCell( Char ch ) { public int randomRespawnCell( Char ch ) {
//this check is mainly here for DM-300, to prevent an infinite loop //this check is mainly here for DM-300, to prevent an infinite loop
if (Char.hasProp(ch, Char.Property.LARGE) && map[entrance] != Terrain.ENTRANCE){ if (Char.hasProp(ch, Char.Property.LARGE) && map[entrance()] != Terrain.ENTRANCE){
return -1; return -1;
} }
int cell; int cell;
do { do {
cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)];
} while (!passable[cell] } while (!passable[cell]
|| (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell])
|| Actor.findChar(cell) != null); || Actor.findChar(cell) != null);
@@ -252,6 +263,7 @@ public class CavesBossLevel extends Level {
public void seal() { public void seal() {
super.seal(); super.seal();
int entrance = entrance();
set( entrance, Terrain.WALL ); set( entrance, Terrain.WALL );
Heap heap = Dungeon.level.heaps.get( entrance ); Heap heap = Dungeon.level.heaps.get( entrance );
@@ -302,7 +314,7 @@ public class CavesBossLevel extends Level {
blobs.get(PylonEnergy.class).fullyClear(); blobs.get(PylonEnergy.class).fullyClear();
set( entrance, Terrain.ENTRANCE ); set( entrance(), Terrain.ENTRANCE );
int i = 14 + 13*width(); int i = 14 + 13*width();
for (int j = 0; j < 5; j++){ for (int j = 0; j < 5; j++){
set( i+j, Terrain.EMPTY ); set( i+j, Terrain.EMPTY );
@@ -480,7 +492,7 @@ public class CavesBossLevel extends Level {
}; };
private void buildEntrance(){ private void buildEntrance(){
entrance = 16 + 25*width(); int entrance = 16 + 25*width();
//entrance area //entrance area
int NW = entrance - 7 - 7*width(); int NW = entrance - 7 - 7*width();
@@ -502,6 +514,7 @@ public class CavesBossLevel extends Level {
} }
Painter.set(this, entrance, Terrain.ENTRANCE); Painter.set(this, entrance, Terrain.ENTRANCE);
transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
} }
private static short[] corner1 = { private static short[] corner1 = {
@@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.CityPainter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.CityPainter;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ImpShopRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ImpShopRoom;
@@ -119,6 +120,12 @@ public class CityBossLevel extends Level {
@Override @Override
public void restoreFromBundle( Bundle bundle ) { public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle ); super.restoreFromBundle( bundle );
//pre-1.3.0 saves, modifies exit transition with custom size
if (bundle.contains("exit")){
LevelTransition exit = getTransition(LevelTransition.Type.REGULAR_EXIT);
exit.set(end.left+4, end.top+4, end.left+4+6, end.top+4+4);
transitions.add(exit);
}
impShop = (ImpShopRoom) bundle.get( IMP_SHOP ); impShop = (ImpShopRoom) bundle.get( IMP_SHOP );
if (map[topDoor] != Terrain.LOCKED_DOOR && Imp.Quest.isCompleted() && !impShop.shopSpawned()){ if (map[topDoor] != Terrain.LOCKED_DOOR && Imp.Quest.isCompleted() && !impShop.shopSpawned()){
spawnShop(); spawnShop();
@@ -147,8 +154,9 @@ public class CityBossLevel extends Level {
Painter.set(this, c.x, entry.top, Terrain.DOOR); Painter.set(this, c.x, entry.top, Terrain.DOOR);
entrance = c.x + (c.y+2)*width(); int entrance = c.x + (c.y+2)*width();
Painter.set(this, entrance, Terrain.ENTRANCE); Painter.set(this, entrance, Terrain.ENTRANCE);
transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
//DK's throne room //DK's throne room
Painter.fillDiamond(this, arena, 1, Terrain.EMPTY); Painter.fillDiamond(this, arena, 1, Terrain.EMPTY);
@@ -173,7 +181,11 @@ public class CityBossLevel extends Level {
Painter.fill(this, end, Terrain.CHASM); Painter.fill(this, end, Terrain.CHASM);
Painter.fill(this, end.left+4, end.top+5, 7, 18, Terrain.EMPTY); Painter.fill(this, end.left+4, end.top+5, 7, 18, Terrain.EMPTY);
Painter.fill(this, end.left+4, end.top+5, 7, 4, Terrain.EXIT); Painter.fill(this, end.left+4, end.top+5, 7, 4, Terrain.EXIT);
exit = end.left+7 + (end.top+8)*width();
int exitCell = end.left+7 + (end.top+8)*width();
LevelTransition exit = new LevelTransition(this, exitCell, LevelTransition.Type.REGULAR_EXIT);
exit.set(end.left+4, end.top+4, end.left+4+6, end.top+4+4);
transitions.add(exit);
impShop = new ImpShopRoom(); impShop = new ImpShopRoom();
impShop.set(end.left+3, end.top+12, end.left+11, end.top+20); impShop.set(end.left+3, end.top+12, end.left+11, end.top+20);
@@ -255,7 +267,7 @@ public class CityBossLevel extends Level {
int pos; int pos;
do { do {
pos = randomRespawnCell(null); pos = randomRespawnCell(null);
} while (pos == entrance); } while (pos == entrance());
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
} }
} }
@@ -264,7 +276,7 @@ public class CityBossLevel extends Level {
public int randomRespawnCell( Char ch ) { public int randomRespawnCell( Char ch ) {
int cell; int cell;
do { do {
cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)];
} while (!passable[cell] } while (!passable[cell]
|| (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell])
|| Actor.findChar(cell) != null); || Actor.findChar(cell) != null);
@@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
public class DeadEndLevel extends Level { public class DeadEndLevel extends Level {
@@ -64,11 +65,10 @@ public class DeadEndLevel extends Level {
Terrain.WATER; Terrain.WATER;
} }
entrance = SIZE * width() + SIZE / 2 + 1; int entrance = SIZE * width() + SIZE / 2 + 1;
transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
map[entrance] = Terrain.ENTRANCE; map[entrance] = Terrain.ENTRANCE;
exit = 0;
return true; return true;
} }
@@ -91,7 +91,7 @@ public class DeadEndLevel extends Level {
@Override @Override
public int randomRespawnCell( Char ch ) { public int randomRespawnCell( Char ch ) {
return entrance-width(); return entrance()-width();
} }
} }
@@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
@@ -68,7 +69,7 @@ public class HallsBossLevel extends Level {
if (locked){ if (locked){
Music.INSTANCE.play(Assets.Music.HALLS_BOSS, true); Music.INSTANCE.play(Assets.Music.HALLS_BOSS, true);
//if exit isn't unlocked //if exit isn't unlocked
} else if (map[exit] != Terrain.EXIT){ } else if (map[exit()] != Terrain.EXIT){
Music.INSTANCE.end(); Music.INSTANCE.end();
} else { } else {
Music.INSTANCE.playTracks( Music.INSTANCE.playTracks(
@@ -112,7 +113,8 @@ public class HallsBossLevel extends Level {
Painter.fill(this, 4 + i * 5, top, 5, bottom - top + 1, Terrain.EMPTY); Painter.fill(this, 4 + i * 5, top, 5, bottom - top + 1, Terrain.EMPTY);
if (i == 2) { if (i == 2) {
entrance = (6 + i * 5) + (bottom - 1) * width(); int entrance = (6 + i * 5) + (bottom - 1) * width();
transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
} }
} }
@@ -124,7 +126,7 @@ public class HallsBossLevel extends Level {
} }
} }
map[entrance] = Terrain.ENTRANCE; map[entrance()] = Terrain.ENTRANCE;
Painter.fill(this, ROOM_LEFT-1, ROOM_TOP-1, 11, 11, Terrain.EMPTY ); Painter.fill(this, ROOM_LEFT-1, ROOM_TOP-1, 11, 11, Terrain.EMPTY );
@@ -149,7 +151,12 @@ public class HallsBossLevel extends Level {
Painter.fill(this, ROOM_LEFT+3, ROOM_TOP+2, 3, 4, Terrain.EMPTY ); Painter.fill(this, ROOM_LEFT+3, ROOM_TOP+2, 3, 4, Terrain.EMPTY );
exit = width/2 + ((ROOM_TOP+1) * width); int exitCell = width/2 + ((ROOM_TOP+1) * width);
LevelTransition exit = new LevelTransition(this, exitCell, LevelTransition.Type.REGULAR_EXIT);
exit.top--;
exit.left--;
exit.right++;
transitions.add(exit);
CustomTilemap vis = new CenterPieceVisuals(); CustomTilemap vis = new CenterPieceVisuals();
vis.pos(ROOM_LEFT, ROOM_TOP+1); vis.pos(ROOM_LEFT, ROOM_TOP+1);
@@ -165,7 +172,7 @@ public class HallsBossLevel extends Level {
} }
//ensures a path to the exit exists //ensures a path to the exit exists
return (PathFinder.getStep(entrance, exit, passable) != -1); return (PathFinder.getStep(entrance(), exit(), passable) != -1);
} }
@Override @Override
@@ -183,14 +190,14 @@ public class HallsBossLevel extends Level {
int pos; int pos;
do { do {
pos = randomRespawnCell(null); pos = randomRespawnCell(null);
} while (pos == entrance); } while (pos == entrance());
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
} }
} }
@Override @Override
public int randomRespawnCell( Char ch ) { public int randomRespawnCell( Char ch ) {
int pos = entrance; int pos = entrance();
int cell; int cell;
do { do {
cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)]; cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
@@ -204,8 +211,8 @@ public class HallsBossLevel extends Level {
public void occupyCell( Char ch ) { public void occupyCell( Char ch ) {
super.occupyCell( ch ); super.occupyCell( ch );
if (map[entrance] == Terrain.ENTRANCE && map[exit] != Terrain.EXIT if (map[entrance()] == Terrain.ENTRANCE && map[exit()] != Terrain.EXIT
&& ch == Dungeon.hero && Dungeon.level.distance(ch.pos, entrance) >= 2) { && ch == Dungeon.hero && Dungeon.level.distance(ch.pos, entrance()) >= 2) {
seal(); seal();
} }
} }
@@ -213,6 +220,7 @@ public class HallsBossLevel extends Level {
@Override @Override
public void seal() { public void seal() {
super.seal(); super.seal();
int entrance = entrance();
set( entrance, Terrain.EMPTY_SP ); set( entrance, Terrain.EMPTY_SP );
GameScene.updateMap( entrance ); GameScene.updateMap( entrance );
CellEmitter.get( entrance ).start( FlameParticle.FACTORY, 0.1f, 10 ); CellEmitter.get( entrance ).start( FlameParticle.FACTORY, 0.1f, 10 );
@@ -220,22 +228,22 @@ public class HallsBossLevel extends Level {
Dungeon.observe(); Dungeon.observe();
YogDzewa boss = new YogDzewa(); YogDzewa boss = new YogDzewa();
boss.pos = exit + width*3; boss.pos = exit() + width*3;
GameScene.add( boss ); GameScene.add( boss );
} }
@Override @Override
public void unseal() { public void unseal() {
super.unseal(); super.unseal();
set( entrance, Terrain.ENTRANCE ); set( entrance(), Terrain.ENTRANCE );
GameScene.updateMap( entrance ); GameScene.updateMap( entrance() );
set( exit, Terrain.EXIT ); set( exit(), Terrain.EXIT );
GameScene.updateMap( exit ); GameScene.updateMap( exit() );
CellEmitter.get(exit-1).burst(ShadowParticle.UP, 25); CellEmitter.get(exit()-1).burst(ShadowParticle.UP, 25);
CellEmitter.get(exit).burst(ShadowParticle.UP, 100); CellEmitter.get(exit()).burst(ShadowParticle.UP, 100);
CellEmitter.get(exit+1).burst(ShadowParticle.UP, 25); CellEmitter.get(exit()+1).burst(ShadowParticle.UP, 25);
for( CustomTilemap t : customTiles){ for( CustomTilemap t : customTiles){
if (t instanceof CenterPieceVisuals){ if (t instanceof CenterPieceVisuals){
((CenterPieceVisuals) t).updateState(); ((CenterPieceVisuals) t).updateState();
@@ -336,7 +344,7 @@ public class HallsBossLevel extends Level {
private void updateState(){ private void updateState(){
if (vis != null){ if (vis != null){
int[] data = map.clone(); int[] data = map.clone();
if (Dungeon.level.map[Dungeon.level.exit] == Terrain.EXIT) { if (Dungeon.level.map[Dungeon.level.exit()] == Terrain.EXIT) {
data[4] = 19; data[4] = 19;
data[12] = data[14] = 31; data[12] = data[14] = 31;
} }
@@ -375,7 +383,7 @@ public class HallsBossLevel extends Level {
private void updateState(){ private void updateState(){
if (vis != null){ if (vis != null){
int[] data = map.clone(); int[] data = map.clone();
if (Dungeon.level.map[Dungeon.level.exit] == Terrain.EXIT) { if (Dungeon.level.map[Dungeon.level.exit()] == Terrain.EXIT) {
data[3] = 1; data[3] = 1;
data[4] = 0; data[4] = 0;
data[5] = 2; data[5] = 2;
@@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Amulet; import com.shatteredpixel.shatteredpixeldungeon.items.Amulet;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap; import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
@@ -89,6 +90,9 @@ public class LastLevel extends Level {
} }
private static final int ROOM_TOP = 10; private static final int ROOM_TOP = 10;
private static final int WIDTH = 16;
private static final int MID = WIDTH/2;
public static int AMULET_POS = 12*WIDTH + MID;
@Override @Override
protected boolean build() { protected boolean build() {
@@ -103,15 +107,18 @@ public class LastLevel extends Level {
Painter.fill( this, MID - 2, height - 3, 5, 1, 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 - 3, height - 2, 7, 1, Terrain.EMPTY);
entrance = (height-ROOM_TOP) * width() + MID; int entrance = (height-ROOM_TOP) * width() + MID;
Painter.fill(this, 0, height - ROOM_TOP, width, 2, Terrain.WALL); Painter.fill(this, 0, height - ROOM_TOP, width, 2, Terrain.WALL);
map[entrance] = Terrain.ENTRANCE; map[entrance] = Terrain.ENTRANCE;
map[entrance+width] = Terrain.ENTRANCE; map[entrance+width] = Terrain.ENTRANCE;
LevelTransition entry = new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE);
entry.left--;
entry.right++;
entry.bottom += 2;
transitions.add(entry);
Painter.fill(this, 0, height - ROOM_TOP + 2, width, 8, Terrain.EMPTY); 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); Painter.fill(this, MID-1, height - ROOM_TOP + 2, 3, 1, Terrain.ENTRANCE);
exit = 12*(width()) + MID;
for (int i=0; i < length(); i++) { for (int i=0; i < length(); i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 5 ) == 0) { if (map[i] == Terrain.EMPTY && Random.Int( 5 ) == 0) {
map[i] = Terrain.EMPTY_DECO; map[i] = Terrain.EMPTY_DECO;
@@ -154,14 +161,14 @@ public class LastLevel extends Level {
@Override @Override
protected void createItems() { protected void createItems() {
drop( new Amulet(), exit ); drop( new Amulet(), AMULET_POS );
} }
@Override @Override
public int randomRespawnCell( Char ch ) { public int randomRespawnCell( Char ch ) {
int cell; int cell;
do { do {
cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)];
} while (!passable[cell] } while (!passable[cell]
|| (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell])
|| Actor.findChar(cell) != null); || Actor.findChar(cell) != null);
@@ -209,6 +216,9 @@ public class LastLevel extends Level {
@Override @Override
public void restoreFromBundle(Bundle bundle) { public void restoreFromBundle(Bundle bundle) {
//pre-1.3.0 saves, deletes unneeded exit
if (bundle.contains("exit")) bundle.remove("exit");
super.restoreFromBundle(bundle); super.restoreFromBundle(bundle);
for (int i=0; i < length(); i++) { for (int i=0; i < length(); i++) {
int flags = Terrain.flags[map[i]]; int flags = Terrain.flags[map[i]];
@@ -250,7 +260,7 @@ public class LastLevel extends Level {
public Tilemap create() { public Tilemap create() {
Tilemap v = super.create(); Tilemap v = super.create();
int candlesStart = Dungeon.level.exit - 3 - 3*Dungeon.level.width(); int candlesStart = AMULET_POS - 3 - 3*Dungeon.level.width();
int cell = tileX + tileY * Dungeon.level.width(); int cell = tileX + tileY * Dungeon.level.width();
int[] map = Dungeon.level.map; int[] map = Dungeon.level.map;
@@ -121,7 +121,7 @@ public class LastShopLevel extends RegularLevel {
int pos; int pos;
do { do {
pos = pointToCell(roomEntrance.random()); pos = pointToCell(roomEntrance.random());
} while (pos == entrance); } while (pos == entrance());
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
} }
} }
@@ -69,6 +69,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.HeavyBoome
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.HighGrass; import com.shatteredpixel.shatteredpixeldungeon.levels.features.HighGrass;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster; import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster;
@@ -143,6 +144,8 @@ public abstract class Level implements Bundlable {
public int entrance; public int entrance;
public int exit; public int exit;
public ArrayList<LevelTransition> transitions;
//when a boss level has become locked. //when a boss level has become locked.
public boolean locked = false; public boolean locked = false;
@@ -167,8 +170,7 @@ public abstract class Level implements Bundlable {
private static final String MAP = "map"; private static final String MAP = "map";
private static final String VISITED = "visited"; private static final String VISITED = "visited";
private static final String MAPPED = "mapped"; private static final String MAPPED = "mapped";
private static final String ENTRANCE = "entrance"; private static final String TRANSITIONS = "transitions";
private static final String EXIT = "exit";
private static final String LOCKED = "locked"; private static final String LOCKED = "locked";
private static final String HEAPS = "heaps"; private static final String HEAPS = "heaps";
private static final String PLANTS = "plants"; private static final String PLANTS = "plants";
@@ -249,6 +251,8 @@ public abstract class Level implements Bundlable {
do { do {
width = height = length = 0; width = height = length = 0;
transitions = new ArrayList<>();
mobs = new HashSet<>(); mobs = new HashSet<>();
heaps = new SparseArray<>(); heaps = new SparseArray<>();
blobs = new HashMap<>(); blobs = new HashMap<>();
@@ -335,8 +339,23 @@ public abstract class Level implements Bundlable {
visited = bundle.getBooleanArray( VISITED ); visited = bundle.getBooleanArray( VISITED );
mapped = bundle.getBooleanArray( MAPPED ); mapped = bundle.getBooleanArray( MAPPED );
entrance = bundle.getInt( ENTRANCE ); transitions = new ArrayList<>();
exit = bundle.getInt( EXIT ); if (bundle.contains(TRANSITIONS)){
for (Bundlable b : bundle.getCollection( TRANSITIONS )){
transitions.add((LevelTransition) b);
}
//pre-1.3.0 saves, converts old entrance/exit to new transitions
} else {
if (bundle.contains("entrance")){
transitions.add(new LevelTransition(
this,
bundle.getInt("entrance"),
Dungeon.depth == 1 ? LevelTransition.Type.SURFACE : LevelTransition.Type.REGULAR_ENTRANCE));
}
if (bundle.contains("exit")){
transitions.add(new LevelTransition(this, bundle.getInt("exit"), LevelTransition.Type.REGULAR_EXIT));
}
}
locked = bundle.getBoolean( LOCKED ); locked = bundle.getBoolean( LOCKED );
@@ -412,8 +431,7 @@ public abstract class Level implements Bundlable {
bundle.put( MAP, map ); bundle.put( MAP, map );
bundle.put( VISITED, visited ); bundle.put( VISITED, visited );
bundle.put( MAPPED, mapped ); bundle.put( MAPPED, mapped );
bundle.put( ENTRANCE, entrance ); bundle.put( TRANSITIONS, transitions );
bundle.put( EXIT, exit );
bundle.put( LOCKED, locked ); bundle.put( LOCKED, locked );
bundle.put( HEAPS, heaps.valueList() ); bundle.put( HEAPS, heaps.valueList() );
bundle.put( PLANTS, plants.valueList() ); bundle.put( PLANTS, plants.valueList() );
@@ -471,6 +489,44 @@ public abstract class Level implements Bundlable {
abstract protected void createItems(); abstract protected void createItems();
public int entrance(){
LevelTransition l = getTransition(null);
if (l != null){
return l.cell();
}
return 0;
}
public int exit(){
LevelTransition l = getTransition(LevelTransition.Type.REGULAR_EXIT);
if (l != null){
return l.cell();
}
return 0;
}
public LevelTransition getTransition(LevelTransition.Type type){
for (LevelTransition transition : transitions){
//if we don't specify a type, prefer to return any entrance
if (type == null &&
(transition.type == LevelTransition.Type.REGULAR_ENTRANCE || transition.type == LevelTransition.Type.SURFACE)){
return transition;
} else if (transition.type == type){
return transition;
}
}
return (type == null && !transitions.isEmpty() ? transitions.get(0) : null);
}
public LevelTransition getTransition(int cell){
for (LevelTransition transition : transitions){
if (transition.inside(cell)){
return transition;
}
}
return null;
}
public void seal(){ public void seal(){
if (!locked) { if (!locked) {
locked = true; locked = true;
@@ -39,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey; import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.HeavyBoomerang; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.HeavyBoomerang;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.TenguDartTrap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.TenguDartTrap;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap;
@@ -133,6 +134,20 @@ public class PrisonBossLevel extends Level {
super.restoreFromBundle(bundle); super.restoreFromBundle(bundle);
state = bundle.getEnum( STATE, State.class ); state = bundle.getEnum( STATE, State.class );
//pre-1.3.0 saves, recreates custom exit and entrance transitions
if (bundle.contains("entrance")){
transitions.clear();
if (state == State.START || state == State.WON){
transitions.add(new LevelTransition(this, ENTRANCE_POS, LevelTransition.Type.REGULAR_ENTRANCE));
}
if (state == State.WON){
LevelTransition exit = new LevelTransition(this, pointToCell(levelExit), LevelTransition.Type.REGULAR_EXIT);
exit.right+=2;
exit.bottom+=3;
transitions.add(exit);
}
}
//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.FIGHT_PAUSE) { if (state == State.START || state == State.FIGHT_PAUSE) {
tengu = (Tengu)bundle.get( TENGU ); tengu = (Tengu)bundle.get( TENGU );
@@ -177,15 +192,14 @@ public class PrisonBossLevel extends Level {
new Point(8, 23), new Point(12, 23)}; new Point(8, 23), new Point(12, 23)};
private void setMapStart(){ private void setMapStart(){
entrance = ENTRANCE_POS; transitions.add(new LevelTransition(this, ENTRANCE_POS, LevelTransition.Type.REGULAR_ENTRANCE));
exit = 0;
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL); Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
//Start //Start
Painter.fill(this, entranceRoom, Terrain.WALL); Painter.fill(this, entranceRoom, Terrain.WALL);
Painter.fill(this, entranceRoom, 1, Terrain.EMPTY); Painter.fill(this, entranceRoom, 1, Terrain.EMPTY);
Painter.set(this, entrance, Terrain.ENTRANCE); Painter.set(this, ENTRANCE_POS, Terrain.ENTRANCE);
Painter.fill(this, startHallway, Terrain.WALL); Painter.fill(this, startHallway, Terrain.WALL);
Painter.fill(this, startHallway, 1, Terrain.EMPTY); Painter.fill(this, startHallway, 1, Terrain.EMPTY);
@@ -217,8 +231,7 @@ public class PrisonBossLevel extends Level {
private void setMapPause(){ private void setMapPause(){
setMapStart(); setMapStart();
transitions.clear();
exit = entrance = 0;
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR); Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR);
@@ -234,7 +247,7 @@ public class PrisonBossLevel extends Level {
private static final Rect arena = new Rect(3, 1, 18, 16); private static final Rect arena = new Rect(3, 1, 18, 16);
private void setMapArena(){ private void setMapArena(){
exit = entrance = 0; transitions.clear();
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL); Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
@@ -250,7 +263,7 @@ public class PrisonBossLevel extends Level {
private static int C = Terrain.CHASM; private static int C = Terrain.CHASM;
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+11, endStart.y+6);
private static final int[] endMap = new int[]{ private static final int[] endMap = new int[]{
W, W, D, 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,
@@ -309,7 +322,10 @@ public class PrisonBossLevel extends Level {
cell += width(); cell += width();
} }
exit = pointToCell(levelExit); LevelTransition exit = new LevelTransition(this, pointToCell(levelExit), LevelTransition.Type.REGULAR_EXIT);
exit.right+=2;
exit.bottom+=3;
transitions.add(exit);
} }
//keep track of removed items as the level is changed. Dump them back into the level at the end. //keep track of removed items as the level is changed. Dump them back into the level at the end.
@@ -224,7 +224,7 @@ public abstract class RegularLevel extends Level {
do { do {
mob.pos = pointToCell(roomToSpawn.random()); mob.pos = pointToCell(roomToSpawn.random());
tries--; tries--;
} while (tries >= 0 && (findMob(mob.pos) != null || !passable[mob.pos] || solid[mob.pos] || mob.pos == exit } while (tries >= 0 && (findMob(mob.pos) != null || !passable[mob.pos] || solid[mob.pos] || mob.pos == exit()
|| (!openSpace[mob.pos] && mob.properties().contains(Char.Property.LARGE)))); || (!openSpace[mob.pos] && mob.properties().contains(Char.Property.LARGE))));
if (tries >= 0) { if (tries >= 0) {
@@ -239,7 +239,7 @@ public abstract class RegularLevel extends Level {
do { do {
mob.pos = pointToCell(roomToSpawn.random()); mob.pos = pointToCell(roomToSpawn.random());
tries--; tries--;
} while (tries >= 0 && (findMob(mob.pos) != null || !passable[mob.pos] || solid[mob.pos] || mob.pos == exit } while (tries >= 0 && (findMob(mob.pos) != null || !passable[mob.pos] || solid[mob.pos] || mob.pos == exit()
|| (!openSpace[mob.pos] && mob.properties().contains(Char.Property.LARGE)))); || (!openSpace[mob.pos] && mob.properties().contains(Char.Property.LARGE))));
if (tries >= 0) { if (tries >= 0) {
@@ -283,7 +283,7 @@ public abstract class RegularLevel extends Level {
&& !solid[cell] && !solid[cell]
&& (!Char.hasProp(ch, Char.Property.LARGE) || openSpace[cell]) && (!Char.hasProp(ch, Char.Property.LARGE) || openSpace[cell])
&& room.canPlaceCharacter(cellToPoint(cell), this) && room.canPlaceCharacter(cellToPoint(cell), this)
&& cell != exit) { && cell != exit()) {
return cell; return cell;
} }
@@ -530,7 +530,7 @@ public abstract class RegularLevel extends Level {
if (room != roomEntrance) { if (room != roomEntrance) {
int pos = pointToCell(room.random()); int pos = pointToCell(room.random());
if (passable[pos] && !solid[pos] if (passable[pos] && !solid[pos]
&& pos != exit && pos != exit()
&& heaps.get(pos) == null && heaps.get(pos) == null
&& findMob(pos) == null) { && findMob(pos) == null) {
@@ -56,8 +56,6 @@ public class SewerBossLevel extends SewerLevel {
color2 = 0x59994a; color2 = 0x59994a;
} }
private int stairs = 0;
@Override @Override
public void playLevelMusic() { public void playLevelMusic() {
if (locked){ if (locked){
@@ -147,7 +145,7 @@ public class SewerBossLevel extends SewerLevel {
int pos; int pos;
do { do {
pos = pointToCell(roomEntrance.random()); pos = pointToCell(roomEntrance.random());
} while (pos == entrance || solid[pos]); } while (pos == entrance() || solid[pos]);
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
} }
} }
@@ -157,7 +155,7 @@ public class SewerBossLevel extends SewerLevel {
int pos; int pos;
do { do {
pos = pointToCell(roomEntrance.random()); pos = pointToCell(roomEntrance.random());
} while (pos == entrance } while (pos == entrance()
|| !passable[pos] || !passable[pos]
|| (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[pos]) || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[pos])
|| Actor.findChar(pos) != null); || Actor.findChar(pos) != null);
@@ -166,16 +164,13 @@ public class SewerBossLevel extends SewerLevel {
public void seal() { public void seal() {
if (entrance != 0) { if (!locked) {
super.seal(); super.seal();
set( entrance, Terrain.WATER ); set( entrance(), Terrain.WATER );
GameScene.updateMap( entrance ); GameScene.updateMap( entrance() );
GameScene.ripple( entrance ); GameScene.ripple( entrance() );
stairs = entrance;
entrance = 0;
Game.runOnRenderThread(new Callback() { Game.runOnRenderThread(new Callback() {
@Override @Override
@@ -187,15 +182,12 @@ public class SewerBossLevel extends SewerLevel {
} }
public void unseal() { public void unseal() {
if (stairs != 0) { if (locked) {
super.unseal(); super.unseal();
entrance = stairs; set( entrance(), Terrain.ENTRANCE );
stairs = 0; GameScene.updateMap( entrance() );
set( entrance, Terrain.ENTRANCE );
GameScene.updateMap( entrance );
Game.runOnRenderThread(new Callback() { Game.runOnRenderThread(new Callback() {
@Override @Override
@@ -209,23 +201,19 @@ public class SewerBossLevel extends SewerLevel {
@Override @Override
public Group addVisuals() { public Group addVisuals() {
super.addVisuals(); super.addVisuals();
if (map[exit-1] != Terrain.WALL_DECO) visuals.add(new PrisonLevel.Torch(exit-1)); if (map[exit()-1] != Terrain.WALL_DECO) visuals.add(new PrisonLevel.Torch(exit()-1));
if (map[exit+1] != Terrain.WALL_DECO) visuals.add(new PrisonLevel.Torch(exit+1)); if (map[exit()+1] != Terrain.WALL_DECO) visuals.add(new PrisonLevel.Torch(exit()+1));
return visuals; return visuals;
} }
private static final String STAIRS = "stairs";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( STAIRS, stairs );
}
@Override @Override
public void restoreFromBundle( Bundle bundle ) { public void restoreFromBundle( Bundle bundle ) {
//pre-1.3.0 saves
if (bundle.getInt("stairs") != 0){
bundle.put("entrance", bundle.getInt("stairs"));
bundle.remove("stairs");
}
super.restoreFromBundle( bundle ); super.restoreFromBundle( bundle );
stairs = bundle.getInt( STAIRS );
roomExit = roomEntrance; roomExit = roomEntrance;
} }
} }
@@ -0,0 +1,154 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2022 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.features;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
import com.watabou.utils.Rect;
public class LevelTransition extends Rect implements Bundlable {
public enum Type {
SURFACE,
REGULAR_ENTRANCE,
REGULAR_EXIT;
}
public Type type;
public int destDepth;
public int destBranch;
public Type destType;
public int centerCell;
//for bundling
public LevelTransition(){
super();
}
public LevelTransition(Level level, int cell, Type type, int destDepth, int destBranch, Type destType){
centerCell = cell;
Point p = level.cellToPoint(cell);
set(p.x, p.y, p.x, p.y);
this.type = type;
this.destDepth = destDepth;
this.destBranch = destBranch;
this.destType = destType;
}
//gives default values for common transition types
public LevelTransition(Level level, int cell, Type type){
centerCell = cell;
Point p = level.cellToPoint(cell);
set(p.x, p.y, p.x, p.y);
this.type = type;
switch (type){
case REGULAR_ENTRANCE: default:
destDepth = Dungeon.depth-1;
destBranch = Dungeon.branch;
destType = Type.REGULAR_EXIT;
break;
case REGULAR_EXIT:
destDepth = Dungeon.depth+1;
destBranch = Dungeon.branch;
destType = Type.REGULAR_ENTRANCE;
break;
case SURFACE:
destDepth = 0;
destBranch = 0;
destType = null;
break;
}
}
//note that the center cell isn't always the actual center.
// It is important when game logic needs to pick a specific cell for some action
// e.g. where to place the hero
public int cell(){
return centerCell;
}
//Transitions are inclusive to their right and bottom sides
@Override
public int width() {
return super.width()+1;
}
@Override
public int height() {
return super.height()+1;
}
@Override
public boolean inside(Point p) {
return p.x >= left && p.x <= right && p.y >= top && p.y <= bottom;
}
public boolean inside(int cell){
return inside(new Point(Dungeon.level.cellToPoint(cell)));
}
public Point center() {
return new Point(
(left + right) / 2 + (((right - left) % 2) == 1 ? Random.Int( 2 ) : 0),
(top + bottom) / 2 + (((bottom - top) % 2) == 1 ? Random.Int( 2 ) : 0) );
}
public static final String TYPE = "type";
public static final String DEST_DEPTH = "dest_depth";
public static final String DEST_BRANCH = "dest_branch";
public static final String DEST_TYPE = "dest_type";
@Override
public void storeInBundle(Bundle bundle) {
bundle.put( "left", left );
bundle.put( "top", top );
bundle.put( "right", right );
bundle.put( "bottom", bottom );
bundle.put( "center", centerCell );
bundle.put(TYPE, type);
bundle.put(DEST_DEPTH, destDepth);
bundle.put(DEST_BRANCH, destBranch);
bundle.put(DEST_TYPE, destType);
}
@Override
public void restoreFromBundle(Bundle bundle) {
left = bundle.getInt( "left" );
top = bundle.getInt( "top" );
right = bundle.getInt( "right" );
bottom = bundle.getInt( "bottom" );
centerCell = bundle.getInt( "center" );
type = bundle.getEnum(TYPE, Type.class);
destDepth = bundle.getInt(DEST_DEPTH);
destBranch = bundle.getInt(DEST_BRANCH);
if (bundle.contains(DEST_TYPE)) destType = bundle.getEnum(DEST_TYPE, Type.class);
}
}
@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRoom;
@@ -47,10 +48,12 @@ public class SewerBossEntranceRoom extends EntranceRoom {
Painter.fill( level, left+1, top+1, width()-2, 1, Terrain.WALL_DECO); Painter.fill( level, left+1, top+1, width()-2, 1, Terrain.WALL_DECO);
Painter.fill( level, left+1, top+2, width()-2, 1, Terrain.WATER); Painter.fill( level, left+1, top+2, width()-2, 1, Terrain.WATER);
int entrance;
do { do {
level.entrance = level.pointToCell(random(3)); entrance = level.pointToCell(random(3));
} while (level.findMob(level.entrance) != null); } while (level.findMob(entrance) != null);
Painter.set( level, level.entrance, Terrain.ENTRANCE ); Painter.set( level, entrance, Terrain.ENTRANCE );
level.transitions.add(new LevelTransition(level, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
for (Room.Door door : connected.values()) { for (Room.Door door : connected.values()) {
door.set( Room.Door.Type.REGULAR ); door.set( Room.Door.Type.REGULAR );
@@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss;
import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ExitRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ExitRoom;
@@ -58,8 +59,13 @@ public class SewerBossExitRoom extends ExitRoom {
Painter.fill( level, c.x-1, c.y-1, 3, 2, Terrain.WALL ); Painter.fill( level, c.x-1, c.y-1, 3, 2, Terrain.WALL );
Painter.fill( level, c.x-1, c.y+1, 3, 1, Terrain.EMPTY_SP ); Painter.fill( level, c.x-1, c.y+1, 3, 1, Terrain.EMPTY_SP );
level.exit = level.pointToCell(c); int exitCell = level.pointToCell(c);
Painter.set( level, level.exit, Terrain.LOCKED_EXIT ); Painter.set( level, exitCell, Terrain.LOCKED_EXIT );
LevelTransition exit = new LevelTransition(level, exitCell, LevelTransition.Type.REGULAR_EXIT);
exit.top--;
exit.left--;
exit.right++;
level.transitions.add(exit);
CustomTilemap vis = new SewerExit(); CustomTilemap vis = new SewerExit();
vis.pos(c.x-1, c.y); vis.pos(c.x-1, c.y);
@@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.journal.Guidebook;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.watabou.utils.Point; import com.watabou.utils.Point;
@@ -58,10 +59,17 @@ public class EntranceRoom extends StandardRoom {
door.set( Room.Door.Type.REGULAR ); door.set( Room.Door.Type.REGULAR );
} }
int entrance;
do { do {
level.entrance = level.pointToCell(random(2)); entrance = level.pointToCell(random(2));
} while (level.findMob(level.entrance) != null); } while (level.findMob(entrance) != null);
Painter.set( level, level.entrance, Terrain.ENTRANCE ); Painter.set( level, entrance, Terrain.ENTRANCE );
if (Dungeon.depth == 1){
level.transitions.add(new LevelTransition(level, entrance, LevelTransition.Type.SURFACE));
} else {
level.transitions.add(new LevelTransition(level, entrance, LevelTransition.Type.REGULAR_ENTRANCE));
}
//use a separate generator here so meta progression doesn't affect levelgen //use a separate generator here so meta progression doesn't affect levelgen
Random.pushGenerator(); Random.pushGenerator();
@@ -73,7 +81,7 @@ public class EntranceRoom extends StandardRoom {
//can't be on bottom row of tiles //can't be on bottom row of tiles
pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ), pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ),
Random.IntRange( top + 1, bottom - 2 ))); Random.IntRange( top + 1, bottom - 2 )));
} while (pos == level.entrance || level.findMob(level.entrance) != null); } while (pos == level.entrance() || level.findMob(level.entrance()) != null);
level.drop( new Guidebook(), pos ); level.drop( new Guidebook(), pos );
} }
@@ -84,7 +92,7 @@ public class EntranceRoom extends StandardRoom {
//can't be on bottom row of tiles //can't be on bottom row of tiles
pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ), pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ),
Random.IntRange( top + 1, bottom - 2 ))); Random.IntRange( top + 1, bottom - 2 )));
} while (pos == level.entrance || level.findMob(level.entrance) != null); } while (pos == level.entrance() || level.findMob(level.entrance()) != null);
GuidePage p = new GuidePage(); GuidePage p = new GuidePage();
p.page(Document.GUIDE_SEARCHING); p.page(Document.GUIDE_SEARCHING);
level.drop( p, pos ); level.drop( p, pos );
@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.watabou.utils.Point; import com.watabou.utils.Point;
@@ -48,13 +49,14 @@ public class ExitRoom extends StandardRoom {
door.set( Room.Door.Type.REGULAR ); door.set( Room.Door.Type.REGULAR );
} }
level.exit = level.pointToCell(random( 2 )); int exit = level.pointToCell(random( 2 ));
Painter.set( level, level.exit, Terrain.EXIT ); Painter.set( level, exit, Terrain.EXIT );
level.transitions.add(new LevelTransition(level, exit, LevelTransition.Type.REGULAR_EXIT));
} }
@Override @Override
public boolean canPlaceCharacter(Point p, Level l) { public boolean canPlaceCharacter(Point p, Level l) {
return super.canPlaceCharacter(p, l) && l.pointToCell(p) != l.exit; return super.canPlaceCharacter(p, l) && l.pointToCell(p) != l.exit();
} }
@Override @Override
@@ -66,6 +66,7 @@ public class Fadeleaf extends Plant {
InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1)); InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1));
InterlevelScene.returnBranch = 0;
InterlevelScene.returnPos = -2; InterlevelScene.returnPos = -2;
Game.switchScene( InterlevelScene.class ); Game.switchScene( InterlevelScene.class );
@@ -35,6 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.LostBackpack;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
@@ -76,7 +77,9 @@ public class InterlevelScene extends PixelScene {
} }
public static Mode mode; public static Mode mode;
public static LevelTransition curTransition = null;
public static int returnDepth; public static int returnDepth;
public static int returnBranch;
public static int returnPos; public static int returnPos;
public static boolean noStory = false; public static boolean noStory = false;
@@ -123,7 +126,7 @@ public class InterlevelScene extends PixelScene {
loadingDepth = 1; loadingDepth = 1;
fadeTime = SLOW_FADE; fadeTime = SLOW_FADE;
} else { } else {
loadingDepth = Dungeon.depth+1; loadingDepth = curTransition.destDepth;
if (!(Statistics.deepestFloor < loadingDepth)) { if (!(Statistics.deepestFloor < loadingDepth)) {
fadeTime = FAST_FADE; fadeTime = FAST_FADE;
} else if (loadingDepth == 6 || loadingDepth == 11 } else if (loadingDepth == 6 || loadingDepth == 11
@@ -139,7 +142,7 @@ public class InterlevelScene extends PixelScene {
break; break;
case ASCEND: case ASCEND:
fadeTime = FAST_FADE; fadeTime = FAST_FADE;
loadingDepth = Dungeon.depth-1; loadingDepth = curTransition.destDepth;
scrollSpeed = -5; scrollSpeed = -5;
break; break;
case RETURN: case RETURN:
@@ -376,21 +379,31 @@ public class InterlevelScene extends PixelScene {
noStory = false; noStory = false;
} }
GameLog.wipe(); GameLog.wipe();
Level level = Dungeon.newLevel();
Dungeon.switchLevel( level, -1 );
} else { } else {
Mob.holdAllies( Dungeon.level ); Mob.holdAllies( Dungeon.level );
Dungeon.saveAll(); Dungeon.saveAll();
Level level;
Dungeon.depth = curTransition.destDepth;
Dungeon.branch = curTransition.destBranch;
//TODO this is brittle atm, assumes we're always going down in depth 1 at a time
if (curTransition.destDepth > Statistics.deepestFloor) {
level = Dungeon.newLevel();
} else {
level = Dungeon.loadLevel( GamesInProgress.curSlot );
}
LevelTransition destTransition = level.getTransition(curTransition.destType);
curTransition = null;
Dungeon.switchLevel( level, destTransition.cell() );
} }
Level level;
if (Dungeon.depth >= Statistics.deepestFloor) {
level = Dungeon.newLevel();
} else {
Dungeon.depth++;
level = Dungeon.loadLevel( GamesInProgress.curSlot );
}
Dungeon.switchLevel( level, level.entrance );
} }
//TODO atm falling always just increments depth by 1, do we eventually want to roll it into the transition system?
private void fall() throws IOException { private void fall() throws IOException {
Mob.holdAllies( Dungeon.level ); Mob.holdAllies( Dungeon.level );
@@ -413,9 +426,13 @@ public class InterlevelScene extends PixelScene {
Mob.holdAllies( Dungeon.level ); Mob.holdAllies( Dungeon.level );
Dungeon.saveAll(); Dungeon.saveAll();
Dungeon.depth--; Dungeon.depth = curTransition.destDepth;
Dungeon.branch = curTransition.destBranch;
Level level = Dungeon.loadLevel( GamesInProgress.curSlot ); Level level = Dungeon.loadLevel( GamesInProgress.curSlot );
Dungeon.switchLevel( level, level.exit );
LevelTransition destTransition = level.getTransition(curTransition.destType);
curTransition = null;
Dungeon.switchLevel( level, destTransition.cell() );
} }
private void returnTo() throws IOException { private void returnTo() throws IOException {
@@ -424,6 +441,7 @@ public class InterlevelScene extends PixelScene {
Dungeon.saveAll(); Dungeon.saveAll();
Dungeon.depth = returnDepth; Dungeon.depth = returnDepth;
Dungeon.branch = returnBranch;
Level level = Dungeon.loadLevel( GamesInProgress.curSlot ); Level level = Dungeon.loadLevel( GamesInProgress.curSlot );
Dungeon.switchLevel( level, returnPos ); Dungeon.switchLevel( level, returnPos );
} }
@@ -453,7 +471,6 @@ public class InterlevelScene extends PixelScene {
ArrayList<Item> preservedItems = Dungeon.level.getItemsToPreserveFromSealedResurrect(); ArrayList<Item> preservedItems = Dungeon.level.getItemsToPreserveFromSealedResurrect();
Dungeon.hero.resurrect(); Dungeon.hero.resurrect();
Dungeon.depth--;
level = Dungeon.newLevel(); level = Dungeon.newLevel();
Dungeon.hero.pos = level.randomRespawnCell(Dungeon.hero); Dungeon.hero.pos = level.randomRespawnCell(Dungeon.hero);
@@ -495,9 +512,8 @@ public class InterlevelScene extends PixelScene {
SpecialRoom.resetPitRoom(Dungeon.depth+1); SpecialRoom.resetPitRoom(Dungeon.depth+1);
Dungeon.depth--;
Level level = Dungeon.newLevel(); Level level = Dungeon.newLevel();
Dungeon.switchLevel( level, level.entrance ); Dungeon.switchLevel( level, level.entrance() );
} }
@Override @Override
@@ -115,7 +115,7 @@ public class StatusPane extends Component {
talentBlink = 0; talentBlink = 0;
compass = new Compass( Statistics.amuletObtained ? Dungeon.level.entrance : Dungeon.level.exit ); compass = new Compass( Statistics.amuletObtained ? Dungeon.level.entrance() : Dungeon.level.exit() );
add( compass ); add( compass );
if (large) rawShielding = new Image(asset, 0, 112, 128, 9); if (large) rawShielding = new Image(asset, 0, 112, 128, 9);