From 654bce1f6500072e334bfde1aff296e050c8599a Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 20 May 2022 13:50:27 -0400 Subject: [PATCH] v1.3.0: Overhauled entrance/exit logic to account for branches --- .../main/java/com/watabou/utils/Bundle.java | 4 + .../shatteredpixeldungeon/Dungeon.java | 17 +- .../actors/hero/Hero.java | 87 +++------- .../actors/hero/HeroAction.java | 10 +- .../hero/abilities/mage/WarpBeacon.java | 8 +- .../actors/mobs/YogDzewa.java | 18 +- .../actors/mobs/YogFist.java | 8 +- .../actors/mobs/npcs/RatKing.java | 8 +- .../actors/mobs/npcs/Wandmaker.java | 2 +- .../items/scrolls/exotic/ScrollOfPassage.java | 1 + .../items/spells/BeaconOfReturning.java | 7 +- .../items/wands/CursedWand.java | 1 + .../items/wands/WandOfRegrowth.java | 8 +- .../levels/CavesBossLevel.java | 25 ++- .../levels/CityBossLevel.java | 20 ++- .../levels/DeadEndLevel.java | 8 +- .../levels/HallsBossLevel.java | 46 +++--- .../levels/LastLevel.java | 22 ++- .../levels/LastShopLevel.java | 2 +- .../shatteredpixeldungeon/levels/Level.java | 70 +++++++- .../levels/PrisonBossLevel.java | 36 ++-- .../levels/RegularLevel.java | 8 +- .../levels/SewerBossLevel.java | 48 ++---- .../levels/features/LevelTransition.java | 154 ++++++++++++++++++ .../sewerboss/SewerBossEntranceRoom.java | 13 +- .../rooms/sewerboss/SewerBossExitRoom.java | 10 +- .../levels/rooms/standard/EntranceRoom.java | 18 +- .../levels/rooms/standard/ExitRoom.java | 8 +- .../plants/Fadeleaf.java | 1 + .../scenes/InterlevelScene.java | 50 ++++-- .../shatteredpixeldungeon/ui/StatusPane.java | 2 +- 31 files changed, 494 insertions(+), 226 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/features/LevelTransition.java diff --git a/SPD-classes/src/main/java/com/watabou/utils/Bundle.java b/SPD-classes/src/main/java/com/watabou/utils/Bundle.java index 38f736e13..c7c5d0f9d 100644 --- a/SPD-classes/src/main/java/com/watabou/utils/Bundle.java +++ b/SPD-classes/src/main/java/com/watabou/utils/Bundle.java @@ -91,6 +91,10 @@ public class Bundle { return !data.isNull( key ); } + public boolean remove( String key ){ + return data.remove(key) != null; + } + //JSONObject.keyset() doesn't exist on Android/iOS public ArrayList getKeys(){ Iterator keys = data.keys(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 53c6cca09..f983ccf94 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -61,6 +61,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel; 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.special.SpecialRoom; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -218,7 +219,7 @@ public class Dungeon { quickslot.reset(); QuickSlotButton.reset(); - depth = 0; + depth = 1; branch = 0; gold = 0; @@ -252,8 +253,7 @@ public class Dungeon { Dungeon.level = null; Actor.clear(); - - depth++; + if (depth > Statistics.deepestFloor) { Statistics.deepestFloor = depth; @@ -337,7 +337,7 @@ public class Dungeon { Actor.clear(); level.reset(); - switchLevel( level, level.entrance ); + switchLevel( level, level.entrance() ); } public static long seedCurDepth(){ @@ -374,9 +374,12 @@ public class Dungeon { public static void switchLevel( final Level level, int pos ) { if (pos == -2){ - pos = level.exit; - } else if (pos < 0 || pos >= level.length() || (!level.passable[pos] && !level.avoid[pos])){ - pos = level.entrance; + LevelTransition t = level.getTransition(LevelTransition.Type.REGULAR_EXIT); + if (t != null) pos = t.cell(); + } + + if (pos < 0 || pos >= level.length() || (!level.passable[pos] && !level.avoid[pos])){ + pos = level.getTransition(null).cell(); } PathFinder.setMapSize(level.width(), level.height()); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 249ecf791..715fb7fae 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -30,7 +30,6 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; 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.Amok; 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.Monk; 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.CheckedCell; 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.Terrain; 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.mechanics.ShadowCaster; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -152,7 +151,6 @@ import com.watabou.utils.Random; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; public class Hero extends Char { @@ -709,11 +707,8 @@ public class Hero extends Char { } else if (curAction instanceof HeroAction.Unlock) { actResult = actUnlock((HeroAction.Unlock) curAction); - } else if (curAction instanceof HeroAction.Descend) { - actResult = actDescend( (HeroAction.Descend)curAction ); - - } else if (curAction instanceof HeroAction.Ascend) { - actResult = actAscend( (HeroAction.Ascend)curAction ); + } else if (curAction instanceof HeroAction.LvlTransition) { + actResult = actTransition( (HeroAction.LvlTransition)curAction ); } else if (curAction instanceof HeroAction.Attack) { actResult = actAttack( (HeroAction.Attack)curAction ); @@ -751,7 +746,7 @@ public class Hero extends Char { public void interrupt() { if (isAlive() && curAction != null && ((curAction instanceof HeroAction.Move && curAction.dst != pos) || - (curAction instanceof HeroAction.Ascend || curAction instanceof HeroAction.Descend))) { + (curAction instanceof HeroAction.LvlTransition))) { lastAction = curAction; } 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; + LevelTransition transition = Dungeon.level.getTransition(stairs); if (rooted) { Camera.main.shake(1, 1f); ready(); return false; - //there can be multiple exit tiles, so descend on any of them - //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; + } else if (transition != null && transition.inside(pos)) { - 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) { Game.runOnRenderThread(new Callback() { @Override @@ -1068,9 +1027,9 @@ public class Hero extends Char { Dungeon.deleteGame( GamesInProgress.curSlot, true ); Game.switchScene( SurfaceScene.class ); } - + } else { - + curAction = null; TimekeepersHourglass.timeFreeze timeFreeze = buff(TimekeepersHourglass.timeFreeze.class); @@ -1078,8 +1037,15 @@ public class Hero extends Char { Swiftthistle.TimeBubble timeBubble = buff(Swiftthistle.TimeBubble.class); if (timeBubble != null) timeBubble.disarmPressedTraps(); - InterlevelScene.mode = InterlevelScene.Mode.ASCEND; - Game.switchScene( InterlevelScene.class ); + InterlevelScene.curTransition = transition; + //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; @@ -1486,16 +1452,13 @@ public class Hero extends Char { curAction = new HeroAction.Unlock( cell ); - } else if ((cell == Dungeon.level.exit || Dungeon.level.map[cell] == Terrain.EXIT || Dungeon.level.map[cell] == Terrain.UNLOCKED_EXIT) - && Dungeon.depth < 26) { + } else if (Dungeon.level.getTransition(cell) != null + && !Dungeon.level.locked + && (Dungeon.depth < 26 || Dungeon.level.getTransition(cell).type == LevelTransition.Type.REGULAR_ENTRANCE) ) { + + curAction = new HeroAction.LvlTransition( cell ); - curAction = new HeroAction.Descend( cell ); - - } else if (cell == Dungeon.level.entrance || Dungeon.level.map[cell] == Terrain.ENTRANCE) { - - curAction = new HeroAction.Ascend( cell ); - - } else { + } else { if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell] && Dungeon.level.traps.get(cell) != null && Dungeon.level.traps.get(cell).visible) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroAction.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroAction.java index 8d8401969..8a7d9cc33 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroAction.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroAction.java @@ -64,14 +64,8 @@ public class HeroAction { } } - public static class Descend extends HeroAction { - public Descend( int stairs ) { - this.dst = stairs; - } - } - - public static class Ascend extends HeroAction { - public Ascend( int stairs ) { + public static class LvlTransition extends HeroAction { + public LvlTransition(int stairs ) { this.dst = stairs; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/mage/WarpBeacon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/mage/WarpBeacon.java index 68d2148d5..3800017ca 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/mage/WarpBeacon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/mage/WarpBeacon.java @@ -110,7 +110,7 @@ public class WarpBeacon extends ArmorAbility { armor.charge -= chargeNeeded; armor.updateQuickslot(); - if (tracker.depth == Dungeon.depth){ + if (tracker.depth == Dungeon.depth && tracker.branch == Dungeon.branch){ Char existing = Actor.findChar(tracker.pos); ScrollOfTeleportation.appear(hero, tracker.pos); @@ -172,6 +172,7 @@ public class WarpBeacon extends ArmorAbility { InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.returnDepth = tracker.depth; + InterlevelScene.returnBranch = tracker.branch; InterlevelScene.returnPos = tracker.pos; Game.switchScene( InterlevelScene.class ); } @@ -203,6 +204,7 @@ public class WarpBeacon extends ArmorAbility { WarpBeaconTracker tracker = new WarpBeaconTracker(); tracker.pos = target; tracker.depth = Dungeon.depth; + tracker.branch = Dungeon.branch; tracker.attachTo(hero); hero.sprite.operate(target); @@ -220,6 +222,7 @@ public class WarpBeacon extends ArmorAbility { int pos; int depth; + int branch; Emitter e; @@ -234,12 +237,14 @@ public class WarpBeacon extends ArmorAbility { public static final String POS = "pos"; public static final String DEPTH = "depth"; + public static final String BRANCH = "branch"; @Override public void storeInBundle(Bundle bundle) { super.storeInBundle(bundle); bundle.put(POS, pos); bundle.put(DEPTH, depth); + bundle.put(BRANCH, branch); } @Override @@ -247,6 +252,7 @@ public class WarpBeacon extends ArmorAbility { super.restoreFromBundle(bundle); pos = bundle.getInt(POS); depth = bundle.getInt(DEPTH); + branch = bundle.getInt(BRANCH); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java index 8bc6de19b..a0cca8403 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java @@ -376,9 +376,9 @@ public class YogDzewa extends Mob { addFist((YogFist)Reflection.newInstance(challengeSummons.remove(0))); } - CellEmitter.get(Dungeon.level.exit-1).burst(ShadowParticle.UP, 25); - 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); + CellEmitter.get(Dungeon.level.exit()).burst(ShadowParticle.UP, 100); + CellEmitter.get(Dungeon.level.exit()+1).burst(ShadowParticle.UP, 25); if (abilityCooldown < 5) abilityCooldown = 5; if (summonCooldown < 5) summonCooldown = 5; @@ -391,16 +391,16 @@ public class YogDzewa extends Mob { } 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).burst(ShadowParticle.UP, 100); - 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()+1).burst(ShadowParticle.UP, 25); if (abilityCooldown < 5) abilityCooldown = 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) && Actor.findChar(targetPos) == null){ @@ -414,7 +414,7 @@ public class YogDzewa extends Mob { } 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 ){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java index 8ab276aa0..3e9c0b714 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java @@ -105,7 +105,7 @@ public abstract class YogFist extends Mob { private boolean invulnWarned = false; 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; } @@ -339,7 +339,7 @@ public abstract class YogFist extends Mob { } 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] && !(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] || Dungeon.level.solid[i] || 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); state = WANDERING; GameScene.flash(0x80FFFFFF); @@ -570,7 +570,7 @@ public abstract class YogFist extends Mob { } while (Dungeon.level.heroFOV[i] || Dungeon.level.solid[i] || 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); state = WANDERING; GameScene.flash(0, false); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java index c5f7181dc..7d7dd10de 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java @@ -84,18 +84,18 @@ public class RatKing extends NPC { @Override protected boolean act() { if (Dungeon.depth < 5){ - if (pos == Dungeon.level.exit){ + if (pos == Dungeon.level.exit()){ destroy(); sprite.killAndErase(); } else { - target = Dungeon.level.exit; + target = Dungeon.level.exit(); } } else if (Dungeon.depth > 5){ - if (pos == Dungeon.level.entrance){ + if (pos == Dungeon.level.entrance()){ destroy(); sprite.killAndErase(); } else { - target = Dungeon.level.entrance; + target = Dungeon.level.entrance(); } } return super.act(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Wandmaker.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Wandmaker.java index e5617c40f..457ceb362 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Wandmaker.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Wandmaker.java @@ -285,7 +285,7 @@ public class Wandmaker extends NPC { do { validPos = true; npc.pos = level.pointToCell(room.random()); - if (npc.pos == level.entrance){ + if (npc.pos == level.entrance()){ validPos = false; } for (Point door : room.connected.values()){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPassage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPassage.java index 7aa8a82c1..06f17fa57 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPassage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPassage.java @@ -57,6 +57,7 @@ public class ScrollOfPassage extends ExoticScroll { InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1 - (Dungeon.depth-2)%5)); + InterlevelScene.returnBranch = 0; InterlevelScene.returnPos = -1; Game.switchScene( InterlevelScene.class ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java index 6ec2495c6..c5688e4ee 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java @@ -51,6 +51,7 @@ public class BeaconOfReturning extends Spell { } public int returnDepth = -1; + public int returnBranch = 0; public int returnPos; @Override @@ -94,6 +95,7 @@ public class BeaconOfReturning extends Spell { private void setBeacon(Hero hero ){ returnDepth = Dungeon.depth; + returnBranch = Dungeon.branch; returnPos = hero.pos; 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]){ - returnPos = Dungeon.level.entrance; + returnPos = Dungeon.level.entrance(); } ScrollOfTeleportation.appear( hero, returnPos ); for(Mob m : Dungeon.level.mobs){ @@ -149,6 +151,7 @@ public class BeaconOfReturning extends Spell { InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.returnDepth = returnDepth; + InterlevelScene.returnBranch = returnBranch; InterlevelScene.returnPos = returnPos; Game.switchScene( InterlevelScene.class ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java index f720d01d6..34e92164b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java @@ -309,6 +309,7 @@ public class CursedWand { InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.returnDepth = depth; + InterlevelScene.returnBranch = 0; InterlevelScene.returnPos = -1; Game.switchScene(InterlevelScene.class); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java index 65a05e368..0d8e50be7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java @@ -331,8 +331,8 @@ public class WandOfRegrowth extends Wand { ArrayList candidates = new ArrayList<>(); for (int i : PathFinder.NEIGHBOURS8){ if (Dungeon.level.passable[pos+i] - && pos+i != Dungeon.level.entrance - && pos+i != Dungeon.level.exit){ + && pos+i != Dungeon.level.entrance() + && pos+i != Dungeon.level.exit()){ candidates.add(pos+i); } } @@ -371,8 +371,8 @@ public class WandOfRegrowth extends Wand { ArrayList candidates = new ArrayList<>(); for (int i : PathFinder.NEIGHBOURS8){ if (Dungeon.level.passable[pos+i] - && pos+i != Dungeon.level.entrance - && pos+i != Dungeon.level.exit){ + && pos+i != Dungeon.level.entrance() + && pos+i != Dungeon.level.exit()){ candidates.add(pos+i); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java index 05dc210a2..e255bbf7d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java @@ -40,6 +40,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.BlastParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; 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.Painter; 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, 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(); customVisuals.setRect(0, 0, width(), 11); @@ -173,6 +177,13 @@ public class CavesBossLevel extends Level { public void restoreFromBundle(Bundle 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){ if (c instanceof ArenaVisuals){ customArenaVisuals = (ArenaVisuals) c; @@ -201,7 +212,7 @@ public class CavesBossLevel extends Level { int pos; do { pos = randomRespawnCell(null); - } while (pos == entrance); + } while (pos == entrance()); drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; } } @@ -209,12 +220,12 @@ public class CavesBossLevel extends Level { @Override public int randomRespawnCell( Char ch ) { //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; } int cell; do { - cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; + cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)]; } while (!passable[cell] || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || Actor.findChar(cell) != null); @@ -252,6 +263,7 @@ public class CavesBossLevel extends Level { public void seal() { super.seal(); + int entrance = entrance(); set( entrance, Terrain.WALL ); Heap heap = Dungeon.level.heaps.get( entrance ); @@ -302,7 +314,7 @@ public class CavesBossLevel extends Level { blobs.get(PylonEnergy.class).fullyClear(); - set( entrance, Terrain.ENTRANCE ); + set( entrance(), Terrain.ENTRANCE ); int i = 14 + 13*width(); for (int j = 0; j < 5; j++){ set( i+j, Terrain.EMPTY ); @@ -480,7 +492,7 @@ public class CavesBossLevel extends Level { }; private void buildEntrance(){ - entrance = 16 + 25*width(); + int entrance = 16 + 25*width(); //entrance area int NW = entrance - 7 - 7*width(); @@ -502,6 +514,7 @@ public class CavesBossLevel extends Level { } Painter.set(this, entrance, Terrain.ENTRANCE); + transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE)); } private static short[] corner1 = { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java index 243b3cb56..e9205906e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java @@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; 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.Painter; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ImpShopRoom; @@ -119,6 +120,12 @@ public class CityBossLevel extends Level { @Override public void restoreFromBundle( Bundle 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 ); if (map[topDoor] != Terrain.LOCKED_DOOR && Imp.Quest.isCompleted() && !impShop.shopSpawned()){ spawnShop(); @@ -147,8 +154,9 @@ public class CityBossLevel extends Level { 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); + transitions.add(new LevelTransition(this, entrance, LevelTransition.Type.REGULAR_ENTRANCE)); //DK's throne room 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.left+4, end.top+5, 7, 18, Terrain.EMPTY); 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.set(end.left+3, end.top+12, end.left+11, end.top+20); @@ -255,7 +267,7 @@ public class CityBossLevel extends Level { int pos; do { pos = randomRespawnCell(null); - } while (pos == entrance); + } while (pos == entrance()); drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; } } @@ -264,7 +276,7 @@ public class CityBossLevel extends Level { public int randomRespawnCell( Char ch ) { int cell; do { - cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; + cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)]; } while (!passable[cell] || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || Actor.findChar(cell) != null); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/DeadEndLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/DeadEndLevel.java index a1ad2bc49..7da11d74a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/DeadEndLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/DeadEndLevel.java @@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition; public class DeadEndLevel extends Level { @@ -64,11 +65,10 @@ public class DeadEndLevel extends Level { 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; - exit = 0; - return true; } @@ -91,7 +91,7 @@ public class DeadEndLevel extends Level { @Override public int randomRespawnCell( Char ch ) { - return entrance-width(); + return entrance()-width(); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java index 64dabd50d..23efe83a4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsBossLevel.java @@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; @@ -68,7 +69,7 @@ public class HallsBossLevel extends Level { if (locked){ Music.INSTANCE.play(Assets.Music.HALLS_BOSS, true); //if exit isn't unlocked - } else if (map[exit] != Terrain.EXIT){ + } else if (map[exit()] != Terrain.EXIT){ Music.INSTANCE.end(); } else { 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); 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 ); @@ -149,7 +151,12 @@ public class HallsBossLevel extends Level { 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(); vis.pos(ROOM_LEFT, ROOM_TOP+1); @@ -165,7 +172,7 @@ public class HallsBossLevel extends Level { } //ensures a path to the exit exists - return (PathFinder.getStep(entrance, exit, passable) != -1); + return (PathFinder.getStep(entrance(), exit(), passable) != -1); } @Override @@ -183,14 +190,14 @@ public class HallsBossLevel extends Level { int pos; do { pos = randomRespawnCell(null); - } while (pos == entrance); + } while (pos == entrance()); drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; } } @Override public int randomRespawnCell( Char ch ) { - int pos = entrance; + int pos = entrance(); int cell; do { cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)]; @@ -204,8 +211,8 @@ public class HallsBossLevel extends Level { public void occupyCell( Char ch ) { super.occupyCell( ch ); - if (map[entrance] == Terrain.ENTRANCE && map[exit] != Terrain.EXIT - && ch == Dungeon.hero && Dungeon.level.distance(ch.pos, entrance) >= 2) { + if (map[entrance()] == Terrain.ENTRANCE && map[exit()] != Terrain.EXIT + && ch == Dungeon.hero && Dungeon.level.distance(ch.pos, entrance()) >= 2) { seal(); } } @@ -213,6 +220,7 @@ public class HallsBossLevel extends Level { @Override public void seal() { super.seal(); + int entrance = entrance(); set( entrance, Terrain.EMPTY_SP ); GameScene.updateMap( entrance ); CellEmitter.get( entrance ).start( FlameParticle.FACTORY, 0.1f, 10 ); @@ -220,22 +228,22 @@ public class HallsBossLevel extends Level { Dungeon.observe(); YogDzewa boss = new YogDzewa(); - boss.pos = exit + width*3; + boss.pos = exit() + width*3; GameScene.add( boss ); } @Override public void unseal() { super.unseal(); - set( entrance, Terrain.ENTRANCE ); - GameScene.updateMap( entrance ); + set( entrance(), Terrain.ENTRANCE ); + GameScene.updateMap( entrance() ); - set( exit, Terrain.EXIT ); - GameScene.updateMap( exit ); + set( exit(), Terrain.EXIT ); + GameScene.updateMap( exit() ); - CellEmitter.get(exit-1).burst(ShadowParticle.UP, 25); - CellEmitter.get(exit).burst(ShadowParticle.UP, 100); - CellEmitter.get(exit+1).burst(ShadowParticle.UP, 25); + CellEmitter.get(exit()-1).burst(ShadowParticle.UP, 25); + CellEmitter.get(exit()).burst(ShadowParticle.UP, 100); + CellEmitter.get(exit()+1).burst(ShadowParticle.UP, 25); for( CustomTilemap t : customTiles){ if (t instanceof CenterPieceVisuals){ ((CenterPieceVisuals) t).updateState(); @@ -336,7 +344,7 @@ public class HallsBossLevel extends Level { private void updateState(){ if (vis != null){ 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[12] = data[14] = 31; } @@ -375,7 +383,7 @@ public class HallsBossLevel extends Level { private void updateState(){ if (vis != null){ 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[4] = 0; data[5] = 2; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java index 3cb972c55..27f081e17 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastLevel.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.items.Amulet; +import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; 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 WIDTH = 16; + private static final int MID = WIDTH/2; + public static int AMULET_POS = 12*WIDTH + MID; @Override 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 - 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); map[entrance] = 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, MID-1, height - ROOM_TOP + 2, 3, 1, Terrain.ENTRANCE); - exit = 12*(width()) + MID; - for (int i=0; i < length(); i++) { if (map[i] == Terrain.EMPTY && Random.Int( 5 ) == 0) { map[i] = Terrain.EMPTY_DECO; @@ -154,14 +161,14 @@ public class LastLevel extends Level { @Override protected void createItems() { - drop( new Amulet(), exit ); + drop( new Amulet(), AMULET_POS ); } @Override public int randomRespawnCell( Char ch ) { int cell; do { - cell = entrance + PathFinder.NEIGHBOURS8[Random.Int(8)]; + cell = entrance() + PathFinder.NEIGHBOURS8[Random.Int(8)]; } while (!passable[cell] || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) || Actor.findChar(cell) != null); @@ -209,6 +216,9 @@ public class LastLevel extends Level { @Override public void restoreFromBundle(Bundle bundle) { + //pre-1.3.0 saves, deletes unneeded exit + if (bundle.contains("exit")) bundle.remove("exit"); + super.restoreFromBundle(bundle); for (int i=0; i < length(); i++) { int flags = Terrain.flags[map[i]]; @@ -250,7 +260,7 @@ public class LastLevel extends Level { public Tilemap 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[] map = Dungeon.level.map; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastShopLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastShopLevel.java index 96c8c3b47..ba73ffdf6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastShopLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LastShopLevel.java @@ -121,7 +121,7 @@ public class LastShopLevel extends RegularLevel { int pos; do { pos = pointToCell(roomEntrance.random()); - } while (pos == entrance); + } while (pos == entrance()); drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java index b625af78d..580ceeccf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java @@ -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.Door; 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.traps.Trap; import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster; @@ -143,6 +144,8 @@ public abstract class Level implements Bundlable { public int entrance; public int exit; + public ArrayList transitions; + //when a boss level has become locked. public boolean locked = false; @@ -167,8 +170,7 @@ public abstract class Level implements Bundlable { private static final String MAP = "map"; private static final String VISITED = "visited"; private static final String MAPPED = "mapped"; - private static final String ENTRANCE = "entrance"; - private static final String EXIT = "exit"; + private static final String TRANSITIONS = "transitions"; private static final String LOCKED = "locked"; private static final String HEAPS = "heaps"; private static final String PLANTS = "plants"; @@ -249,6 +251,8 @@ public abstract class Level implements Bundlable { do { width = height = length = 0; + transitions = new ArrayList<>(); + mobs = new HashSet<>(); heaps = new SparseArray<>(); blobs = new HashMap<>(); @@ -334,9 +338,24 @@ public abstract class Level implements Bundlable { visited = bundle.getBooleanArray( VISITED ); mapped = bundle.getBooleanArray( MAPPED ); - - entrance = bundle.getInt( ENTRANCE ); - exit = bundle.getInt( EXIT ); + + transitions = new ArrayList<>(); + 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 ); @@ -412,8 +431,7 @@ public abstract class Level implements Bundlable { bundle.put( MAP, map ); bundle.put( VISITED, visited ); bundle.put( MAPPED, mapped ); - bundle.put( ENTRANCE, entrance ); - bundle.put( EXIT, exit ); + bundle.put( TRANSITIONS, transitions ); bundle.put( LOCKED, locked ); bundle.put( HEAPS, heaps.valueList() ); bundle.put( PLANTS, plants.valueList() ); @@ -471,6 +489,44 @@ public abstract class Level implements Bundlable { 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(){ if (!locked) { locked = true; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java index 0d34e9aeb..be6f1fcf1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java @@ -39,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey; 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.traps.TenguDartTrap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap; @@ -132,6 +133,20 @@ public class PrisonBossLevel extends Level { public void restoreFromBundle( Bundle bundle ) { super.restoreFromBundle(bundle); 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. if (state == State.START || state == State.FIGHT_PAUSE) { @@ -177,15 +192,14 @@ public class PrisonBossLevel extends Level { new Point(8, 23), new Point(12, 23)}; private void setMapStart(){ - entrance = ENTRANCE_POS; - exit = 0; + transitions.add(new LevelTransition(this, ENTRANCE_POS, LevelTransition.Type.REGULAR_ENTRANCE)); Painter.fill(this, 0, 0, 32, 32, Terrain.WALL); //Start Painter.fill(this, entranceRoom, Terrain.WALL); 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, 1, Terrain.EMPTY); @@ -217,8 +231,7 @@ public class PrisonBossLevel extends Level { private void setMapPause(){ setMapStart(); - - exit = entrance = 0; + transitions.clear(); Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR); @@ -234,8 +247,8 @@ public class PrisonBossLevel extends Level { private static final Rect arena = new Rect(3, 1, 18, 16); private void setMapArena(){ - exit = entrance = 0; - + transitions.clear(); + Painter.fill(this, 0, 0, 32, 32, Terrain.WALL); Painter.fill(this, arena, Terrain.WALL); @@ -250,7 +263,7 @@ public class PrisonBossLevel extends Level { private static int C = Terrain.CHASM; 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[]{ 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, @@ -308,8 +321,11 @@ public class PrisonBossLevel extends Level { i += 14; 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. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java index fc733df92..5644f3469 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java @@ -224,7 +224,7 @@ public abstract class RegularLevel extends Level { do { mob.pos = pointToCell(roomToSpawn.random()); 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)))); if (tries >= 0) { @@ -239,7 +239,7 @@ public abstract class RegularLevel extends Level { do { mob.pos = pointToCell(roomToSpawn.random()); 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)))); if (tries >= 0) { @@ -283,7 +283,7 @@ public abstract class RegularLevel extends Level { && !solid[cell] && (!Char.hasProp(ch, Char.Property.LARGE) || openSpace[cell]) && room.canPlaceCharacter(cellToPoint(cell), this) - && cell != exit) { + && cell != exit()) { return cell; } @@ -530,7 +530,7 @@ public abstract class RegularLevel extends Level { if (room != roomEntrance) { int pos = pointToCell(room.random()); if (passable[pos] && !solid[pos] - && pos != exit + && pos != exit() && heaps.get(pos) == null && findMob(pos) == null) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java index 30a9c3ab8..7496c385e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/SewerBossLevel.java @@ -56,8 +56,6 @@ public class SewerBossLevel extends SewerLevel { color2 = 0x59994a; } - private int stairs = 0; - @Override public void playLevelMusic() { if (locked){ @@ -147,7 +145,7 @@ public class SewerBossLevel extends SewerLevel { int pos; do { pos = pointToCell(roomEntrance.random()); - } while (pos == entrance || solid[pos]); + } while (pos == entrance() || solid[pos]); drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS; } } @@ -157,7 +155,7 @@ public class SewerBossLevel extends SewerLevel { int pos; do { pos = pointToCell(roomEntrance.random()); - } while (pos == entrance + } while (pos == entrance() || !passable[pos] || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[pos]) || Actor.findChar(pos) != null); @@ -166,16 +164,13 @@ public class SewerBossLevel extends SewerLevel { public void seal() { - if (entrance != 0) { + if (!locked) { super.seal(); - - set( entrance, Terrain.WATER ); - GameScene.updateMap( entrance ); - GameScene.ripple( entrance ); - - stairs = entrance; - entrance = 0; + + set( entrance(), Terrain.WATER ); + GameScene.updateMap( entrance() ); + GameScene.ripple( entrance() ); Game.runOnRenderThread(new Callback() { @Override @@ -187,15 +182,12 @@ public class SewerBossLevel extends SewerLevel { } public void unseal() { - if (stairs != 0) { + if (locked) { super.unseal(); - - entrance = stairs; - stairs = 0; - - set( entrance, Terrain.ENTRANCE ); - GameScene.updateMap( entrance ); + + set( entrance(), Terrain.ENTRANCE ); + GameScene.updateMap( entrance() ); Game.runOnRenderThread(new Callback() { @Override @@ -209,23 +201,19 @@ public class SewerBossLevel extends SewerLevel { @Override public Group 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; } - private static final String STAIRS = "stairs"; - - @Override - public void storeInBundle( Bundle bundle ) { - super.storeInBundle( bundle ); - bundle.put( STAIRS, stairs ); - } - @Override 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 ); - stairs = bundle.getInt( STAIRS ); roomExit = roomEntrance; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/features/LevelTransition.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/features/LevelTransition.java new file mode 100644 index 000000000..28e11de5f --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/features/LevelTransition.java @@ -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 + */ + +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); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossEntranceRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossEntranceRoom.java index e02410722..bbbf4db5b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossEntranceRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossEntranceRoom.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; 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.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRoom; @@ -46,12 +47,14 @@ public class SewerBossEntranceRoom extends EntranceRoom { 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); - + + int entrance; do { - level.entrance = level.pointToCell(random(3)); - } while (level.findMob(level.entrance) != null); - Painter.set( level, level.entrance, Terrain.ENTRANCE ); - + entrance = level.pointToCell(random(3)); + } while (level.findMob(entrance) != null); + Painter.set( level, entrance, Terrain.ENTRANCE ); + level.transitions.add(new LevelTransition(level, entrance, LevelTransition.Type.REGULAR_ENTRANCE)); + for (Room.Door door : connected.values()) { door.set( Room.Door.Type.REGULAR ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossExitRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossExitRoom.java index 2a8c68df0..dff4561b3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossExitRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/sewerboss/SewerBossExitRoom.java @@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; 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.rooms.Room; 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, 1, Terrain.EMPTY_SP ); - level.exit = level.pointToCell(c); - Painter.set( level, level.exit, Terrain.LOCKED_EXIT ); + int exitCell = level.pointToCell(c); + 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(); vis.pos(c.x-1, c.y); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EntranceRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EntranceRoom.java index 03708ed08..061841cbc 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EntranceRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EntranceRoom.java @@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.journal.Guidebook; import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; 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.rooms.Room; import com.watabou.utils.Point; @@ -58,10 +59,17 @@ public class EntranceRoom extends StandardRoom { door.set( Room.Door.Type.REGULAR ); } + int entrance; do { - level.entrance = level.pointToCell(random(2)); - } while (level.findMob(level.entrance) != null); - Painter.set( level, level.entrance, Terrain.ENTRANCE ); + entrance = level.pointToCell(random(2)); + } while (level.findMob(entrance) != null); + 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 Random.pushGenerator(); @@ -73,7 +81,7 @@ public class EntranceRoom extends StandardRoom { //can't be on bottom row of tiles pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ), 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 ); } @@ -84,7 +92,7 @@ public class EntranceRoom extends StandardRoom { //can't be on bottom row of tiles pos = level.pointToCell(new Point( Random.IntRange( left + 1, right - 1 ), 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(); p.page(Document.GUIDE_SEARCHING); level.drop( p, pos ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/ExitRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/ExitRoom.java index c5cae04c8..500a9e063 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/ExitRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/ExitRoom.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; 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.rooms.Room; import com.watabou.utils.Point; @@ -48,13 +49,14 @@ public class ExitRoom extends StandardRoom { door.set( Room.Door.Type.REGULAR ); } - level.exit = level.pointToCell(random( 2 )); - Painter.set( level, level.exit, Terrain.EXIT ); + int exit = level.pointToCell(random( 2 )); + Painter.set( level, exit, Terrain.EXIT ); + level.transitions.add(new LevelTransition(level, exit, LevelTransition.Type.REGULAR_EXIT)); } @Override 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 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/plants/Fadeleaf.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/plants/Fadeleaf.java index 850a02229..c893a3913 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/plants/Fadeleaf.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/plants/Fadeleaf.java @@ -66,6 +66,7 @@ public class Fadeleaf extends Plant { InterlevelScene.mode = InterlevelScene.Mode.RETURN; InterlevelScene.returnDepth = Math.max(1, (Dungeon.depth - 1)); + InterlevelScene.returnBranch = 0; InterlevelScene.returnPos = -2; Game.switchScene( InterlevelScene.class ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java index 4ab9dac4b..a571ef7c4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java @@ -35,6 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.LostBackpack; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; 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.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; @@ -75,8 +76,10 @@ public class InterlevelScene extends PixelScene { DESCEND, ASCEND, CONTINUE, RESURRECT, RETURN, FALL, RESET, NONE } public static Mode mode; - + + public static LevelTransition curTransition = null; public static int returnDepth; + public static int returnBranch; public static int returnPos; public static boolean noStory = false; @@ -123,7 +126,7 @@ public class InterlevelScene extends PixelScene { loadingDepth = 1; fadeTime = SLOW_FADE; } else { - loadingDepth = Dungeon.depth+1; + loadingDepth = curTransition.destDepth; if (!(Statistics.deepestFloor < loadingDepth)) { fadeTime = FAST_FADE; } else if (loadingDepth == 6 || loadingDepth == 11 @@ -139,7 +142,7 @@ public class InterlevelScene extends PixelScene { break; case ASCEND: fadeTime = FAST_FADE; - loadingDepth = Dungeon.depth-1; + loadingDepth = curTransition.destDepth; scrollSpeed = -5; break; case RETURN: @@ -376,21 +379,31 @@ public class InterlevelScene extends PixelScene { noStory = false; } GameLog.wipe(); + + Level level = Dungeon.newLevel(); + Dungeon.switchLevel( level, -1 ); } else { Mob.holdAllies( Dungeon.level ); 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 { Mob.holdAllies( Dungeon.level ); @@ -413,9 +426,13 @@ public class InterlevelScene extends PixelScene { Mob.holdAllies( Dungeon.level ); Dungeon.saveAll(); - Dungeon.depth--; + Dungeon.depth = curTransition.destDepth; + Dungeon.branch = curTransition.destBranch; 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 { @@ -424,6 +441,7 @@ public class InterlevelScene extends PixelScene { Dungeon.saveAll(); Dungeon.depth = returnDepth; + Dungeon.branch = returnBranch; Level level = Dungeon.loadLevel( GamesInProgress.curSlot ); Dungeon.switchLevel( level, returnPos ); } @@ -453,7 +471,6 @@ public class InterlevelScene extends PixelScene { ArrayList preservedItems = Dungeon.level.getItemsToPreserveFromSealedResurrect(); Dungeon.hero.resurrect(); - Dungeon.depth--; level = Dungeon.newLevel(); Dungeon.hero.pos = level.randomRespawnCell(Dungeon.hero); @@ -495,9 +512,8 @@ public class InterlevelScene extends PixelScene { SpecialRoom.resetPitRoom(Dungeon.depth+1); - Dungeon.depth--; Level level = Dungeon.newLevel(); - Dungeon.switchLevel( level, level.entrance ); + Dungeon.switchLevel( level, level.entrance() ); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 4b67c7060..a23e0cd2c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -115,7 +115,7 @@ public class StatusPane extends Component { 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 ); if (large) rawShielding = new Image(asset, 0, 112, 128, 9);