v1.2.0: added crystal doors, with a placeholder sprite

This commit is contained in:
Evan Debenham 2022-03-04 01:07:17 -05:00
parent a1344eb898
commit 49385a9bae
17 changed files with 78 additions and 46 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -186,6 +186,7 @@ levels.level.exit_name=Depth exit
levels.level.embers_name=Embers
levels.level.furrowed_grass_name=Furrowed vegetation
levels.level.locked_door_name=Locked door
levels.level.crystal_door_name=Crystal door
levels.level.pedestal_name=Pedestal
levels.level.barricade_name=Barricade
levels.level.high_grass_name=High grass
@ -206,6 +207,7 @@ levels.level.exit_desc=Stairs lead down to the lower depth.
levels.level.embers_desc=Embers cover the floor.
levels.level.high_grass_desc=Dense vegetation blocks the view.
levels.level.locked_door_desc=This door is locked, you need a matching key to unlock it.
levels.level.crystal_door_desc=This locked door is made of magical crystal. You can see through, but you'll need a crystal key to open it.
levels.level.locked_exit_desc=Heavy bars block the stairs leading down.
levels.level.barricade_desc=The wooden barricade is firmly set but has dried over the years. Might it burn?
levels.level.sign_desc=You can't read the text from here.

View File

@ -59,7 +59,9 @@ 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.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.CheckedCell;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.effects.SpellSprite;
import com.shatteredpixel.shatteredpixeldungeon.items.Amulet;
import com.shatteredpixel.shatteredpixeldungeon.items.Ankh;
@ -965,6 +967,11 @@ public class Hero extends Char {
hasKey = true;
} else if (door == Terrain.CRYSTAL_DOOR
&& Notes.keyCount(new CrystalKey(Dungeon.depth)) > 0) {
hasKey = true;
} else if (door == Terrain.LOCKED_EXIT
&& Notes.keyCount(new SkeletonKey(Dungeon.depth)) > 0) {
@ -1470,7 +1477,7 @@ public class Hero extends Char {
curAction = new HeroAction.OpenChest( cell );
}
} else if (Dungeon.level.map[cell] == Terrain.LOCKED_DOOR || Dungeon.level.map[cell] == Terrain.LOCKED_EXIT) {
} else if (Dungeon.level.map[cell] == Terrain.LOCKED_DOOR || Dungeon.level.map[cell] == Terrain.CRYSTAL_DOOR || Dungeon.level.map[cell] == Terrain.LOCKED_EXIT) {
curAction = new HeroAction.Unlock( cell );
@ -1834,6 +1841,13 @@ public class Hero extends Char {
if (door == Terrain.LOCKED_DOOR) {
hasKey = Notes.remove(new IronKey(Dungeon.depth));
if (hasKey) Level.set(doorCell, Terrain.DOOR);
} else if (door == Terrain.CRYSTAL_DOOR) {
hasKey = Notes.remove(new CrystalKey(Dungeon.depth));
if (hasKey) {
Level.set(doorCell, Terrain.EMPTY);
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
CellEmitter.get( doorCell ).start( Speck.factory( Speck.DISCOVER ), 0.025f, 20 );
}
} else {
hasKey = Notes.remove(new SkeletonKey(Dungeon.depth));
if (hasKey) Level.set(doorCell, Terrain.UNLOCKED_EXIT);
@ -1841,7 +1855,6 @@ public class Hero extends Char {
if (hasKey) {
GameScene.updateKeyDisplay();
Level.set(doorCell, door == Terrain.LOCKED_DOOR ? Terrain.DOOR : Terrain.UNLOCKED_EXIT);
GameScene.updateMap(doorCell);
spend(Key.TIME_TO_UNLOCK);
}

View File

@ -145,7 +145,7 @@ public class ScrollOfTeleportation extends Scroll {
boolean locked = false;
for (Point p : r.getPoints()){
terr = level.map[level.pointToCell(p)];
if (terr == Terrain.LOCKED_DOOR || terr == Terrain.BARRICADE){
if (terr == Terrain.LOCKED_DOOR || terr == Terrain.CRYSTAL_DOOR || terr == Terrain.BARRICADE){
locked = true;
break;
}

View File

@ -1308,6 +1308,8 @@ public abstract class Level implements Bundlable {
return Messages.get(Level.class, "furrowed_grass_name");
case Terrain.LOCKED_DOOR:
return Messages.get(Level.class, "locked_door_name");
case Terrain.CRYSTAL_DOOR:
return Messages.get(Level.class, "crystal_door_name");
case Terrain.PEDESTAL:
return Messages.get(Level.class, "pedestal_name");
case Terrain.BARRICADE:
@ -1357,6 +1359,8 @@ public abstract class Level implements Bundlable {
return Messages.get(Level.class, "high_grass_desc");
case Terrain.LOCKED_DOOR:
return Messages.get(Level.class, "locked_door_desc");
case Terrain.CRYSTAL_DOOR:
return Messages.get(Level.class, "crystal_door_desc");
case Terrain.LOCKED_EXIT:
return Messages.get(Level.class, "locked_exit_desc");
case Terrain.BARRICADE:

View File

@ -34,6 +34,7 @@ public class Terrain {
public static final int EXIT = 8;
public static final int EMBERS = 9;
public static final int LOCKED_DOOR = 10;
public static final int CRYSTAL_DOOR = 31;
public static final int PEDESTAL = 11;
public static final int WALL_DECO = 12;
public static final int BARRICADE = 13;
@ -81,6 +82,7 @@ public class Terrain {
flags[EXIT] = PASSABLE;
flags[EMBERS] = PASSABLE;
flags[LOCKED_DOOR] = LOS_BLOCKING | SOLID;
flags[CRYSTAL_DOOR] = SOLID;
flags[PEDESTAL] = PASSABLE;
flags[WALL_DECO] = flags[WALL];
flags[BARRICADE] = FLAMABLE | SOLID | LOS_BLOCKING;

View File

@ -244,6 +244,9 @@ public abstract class RegularPainter extends Painter {
case LOCKED:
l.map[door] = Terrain.LOCKED_DOOR;
break;
case CRYSTAL:
l.map[door] = Terrain.CRYSTAL_DOOR;
break;
}
}
}

View File

@ -405,7 +405,7 @@ public abstract class Room extends Rect implements Graph.Node, Bundlable {
public static class Door extends Point implements Bundlable {
public enum Type {
EMPTY, TUNNEL, WATER, REGULAR, UNLOCKED, HIDDEN, BARRICADE, LOCKED
EMPTY, TUNNEL, WATER, REGULAR, UNLOCKED, HIDDEN, BARRICADE, LOCKED, CRYSTAL
}
public Type type = Type.EMPTY;

View File

@ -117,12 +117,8 @@ public class LaboratoryRoom extends SpecialRoom {
}
}
if (level instanceof RegularLevel && ((RegularLevel)level).hasPitRoom()){
entrance.set( Door.Type.REGULAR );
} else {
entrance.set( Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
}

View File

@ -26,6 +26,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.CrystalKey;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
@ -37,9 +38,11 @@ public class PitRoom extends SpecialRoom {
@Override //increase min size slightly to prevent tiny 3x3 wraith fights
public int minWidth() { return 6; }
public int minHeight() {
return 6;
}
public int minHeight() { return 6; }
@Override //reduce max size to ensure well is visible in normal circumstances
public int maxWidth() { return 9; }
public int maxHeight() { return 9; }
public void paint( Level level ) {
@ -47,7 +50,7 @@ public class PitRoom extends SpecialRoom {
Painter.fill( level, this, 1, Terrain.EMPTY );
Door entrance = entrance();
entrance.set( Door.Type.LOCKED );
entrance.set( Door.Type.CRYSTAL );
Point well = null;
if (entrance.x == left) {
@ -61,12 +64,9 @@ public class PitRoom extends SpecialRoom {
}
Painter.set( level, well, Terrain.EMPTY_WELL );
int remains = level.pointToCell(random());
while (level.map[remains] == Terrain.EMPTY_WELL) {
remains = level.pointToCell(random());
}
int remains = level.pointToCell(center());
level.drop( new IronKey( Dungeon.depth ), remains ).type = Heap.Type.SKELETON;
level.drop( new CrystalKey( Dungeon.depth ), remains ).type = Heap.Type.SKELETON;
Item mainLoot = null;
do {
switch (Random.Int(3)){
@ -92,13 +92,6 @@ public class PitRoom extends SpecialRoom {
}
private static Item prize( Level level ) {
if (Random.Int(2) != 0){
Item prize = level.findPrizeItem();
if (prize != null)
return prize;
}
return Generator.random( Random.oneOf(
Generator.Category.POTION,
Generator.Category.SCROLL,
@ -113,4 +106,9 @@ public class PitRoom extends SpecialRoom {
//having traps here just seems unfair
return false;
}
@Override
public boolean canPlaceGrass(Point p) {
return false; //We want the player to be able to see the well through the door
}
}

View File

@ -90,6 +90,11 @@ public abstract class SpecialRoom extends Room {
RunestoneRoom.class, GardenRoom.class, LibraryRoom.class, StorageRoom.class, TreasuryRoom.class, MagicWellRoom.class
) );
//only one special that uses crystal keys per floor
private static final ArrayList<Class<? extends SpecialRoom>> CRYSTAL_KEY_SPECIALS = new ArrayList<>( Arrays.asList(
PitRoom.class, VaultRoom.class
) );
public static ArrayList<Class<? extends Room>> runSpecials = new ArrayList<>();
public static ArrayList<Class<? extends Room>> floorSpecials = new ArrayList<>();
@ -114,6 +119,8 @@ public abstract class SpecialRoom extends Room {
if (!runConsSpecials.isEmpty()) runSpecials.add(runConsSpecials.remove(0));
}
runSpecials.add(0, WeakFloorRoom.class);
pitNeededDepth = -1;
}
@ -128,6 +135,9 @@ public abstract class SpecialRoom extends Room {
private static void useType( Class<?extends Room> type ) {
floorSpecials.remove( type );
if (CRYSTAL_KEY_SPECIALS.contains(type)){
floorSpecials.removeAll(CRYSTAL_KEY_SPECIALS);
}
if (runSpecials.remove( type )) {
runSpecials.add( type );
}
@ -141,15 +151,7 @@ public abstract class SpecialRoom extends Room {
if (Dungeon.depth == pitNeededDepth){
pitNeededDepth = -1;
floorSpecials.remove( ArmoryRoom.class );
floorSpecials.remove( CryptRoom.class );
floorSpecials.remove( LibraryRoom.class );
floorSpecials.remove( RunestoneRoom.class );
floorSpecials.remove( StatueRoom.class );
floorSpecials.remove( TreasuryRoom.class );
floorSpecials.remove( VaultRoom.class );
floorSpecials.remove( WeakFloorRoom.class );
useType( PitRoom.class );
return new PitRoom();
} else if (floorSpecials.contains(LaboratoryRoom.class)) {

View File

@ -83,7 +83,7 @@ public class DungeonTileSheet {
Terrain.BARRICADE, Terrain.HIGH_GRASS, Terrain.FURROWED_GRASS, Terrain.SECRET_TRAP,
Terrain.TRAP, Terrain.INACTIVE_TRAP, Terrain.EMPTY_DECO,
Terrain.SIGN, Terrain.WELL, Terrain.STATUE, Terrain.ALCHEMY,
Terrain.DOOR, Terrain.OPEN_DOOR, Terrain.LOCKED_DOOR
Terrain.DOOR, Terrain.OPEN_DOOR, Terrain.LOCKED_DOOR, Terrain.CRYSTAL_DOOR
));
//+1 for ground above, +2 for ground right, +4 for ground below, +8 for ground left.
@ -172,8 +172,9 @@ public class DungeonTileSheet {
public static final int FLAT_DOOR = FLAT_DOORS+0;
public static final int FLAT_DOOR_OPEN = FLAT_DOORS+1;
public static final int FLAT_DOOR_LOCKED = FLAT_DOORS+2;
public static final int UNLOCKED_EXIT = FLAT_DOORS+3;
public static final int LOCKED_EXIT = FLAT_DOORS+4;
public static final int FLAT_DOOR_CRYSTAL = FLAT_DOORS+3;
public static final int UNLOCKED_EXIT = FLAT_DOORS+4;
public static final int LOCKED_EXIT = FLAT_DOORS+5;
public static final int FLAT_OTHER = xy(1, 7); //16 slots
public static final int FLAT_SIGN = FLAT_OTHER+0;
@ -241,8 +242,9 @@ public class DungeonTileSheet {
public static final int RAISED_DOOR = RAISED_DOORS+0;
public static final int RAISED_DOOR_OPEN = RAISED_DOORS+1;
public static final int RAISED_DOOR_LOCKED = RAISED_DOORS+2;
public static final int RAISED_DOOR_CRYSTAL = RAISED_DOORS+3;
//floor tile that appears on a top/bottom doorway
public static final int RAISED_DOOR_SIDEWAYS = RAISED_DOORS+3;
public static final int RAISED_DOOR_SIDEWAYS = RAISED_DOORS+4;
public static int getRaisedDoorTile(int tile, int below){
@ -250,11 +252,12 @@ public class DungeonTileSheet {
else if (tile == Terrain.DOOR) return DungeonTileSheet.RAISED_DOOR;
else if (tile == Terrain.OPEN_DOOR) return DungeonTileSheet.RAISED_DOOR_OPEN;
else if (tile == Terrain.LOCKED_DOOR) return DungeonTileSheet.RAISED_DOOR_LOCKED;
else if (tile == Terrain.CRYSTAL_DOOR) return DungeonTileSheet.RAISED_DOOR_CRYSTAL;
else return -1;
}
private static int[] doorTiles = new int[]{
Terrain.DOOR, Terrain.LOCKED_DOOR, Terrain.OPEN_DOOR
Terrain.DOOR, Terrain.LOCKED_DOOR, Terrain.CRYSTAL_DOOR, Terrain.OPEN_DOOR
};
public static boolean doorTile(int tile){
@ -306,13 +309,15 @@ public class DungeonTileSheet {
public static final int DOOR_SIDEWAYS_OVERHANG = WALLS_OVERHANG+4;
public static final int DOOR_SIDEWAYS_OVERHANG_OPEN = WALLS_OVERHANG+8;
public static final int DOOR_SIDEWAYS_OVERHANG_LOCKED = WALLS_OVERHANG+12;
public static final int WALL_OVERHANG_WOODEN = WALLS_OVERHANG+16;
public static final int DOOR_SIDEWAYS_OVERHANG_CRYSTAL = WALLS_OVERHANG+16;
public static final int WALL_OVERHANG_WOODEN = WALLS_OVERHANG+20;
public static int stitchWallOverhangTile(int tile, int rightBelow, int below, int leftBelow){
int visual;
if (tile == Terrain.DOOR) visual = DOOR_SIDEWAYS_OVERHANG;
else if (tile == Terrain.OPEN_DOOR) visual = DOOR_SIDEWAYS_OVERHANG_OPEN;
else if (tile == Terrain.LOCKED_DOOR) visual = DOOR_SIDEWAYS_OVERHANG_LOCKED;
else if (tile == Terrain.CRYSTAL_DOOR) visual = DOOR_SIDEWAYS_OVERHANG_CRYSTAL;
else if (below == Terrain.BOOKSHELF) visual = WALL_OVERHANG_WOODEN;
else visual = WALL_OVERHANG;
@ -323,10 +328,12 @@ public class DungeonTileSheet {
}
//no attachment to adjacent walls
public static final int DOOR_OVERHANG = WALL_OVERHANG+21;
public static final int DOOR_OVERHANG_OPEN = WALL_OVERHANG+22;
public static final int DOOR_SIDEWAYS = WALL_OVERHANG+23;
public static final int DOOR_SIDEWAYS_LOCKED = WALL_OVERHANG+24;
public static final int DOOR_OVERHANG = WALL_OVERHANG+25;
public static final int DOOR_OVERHANG_OPEN = WALL_OVERHANG+26;
public static final int DOOR_OVERHANG_CRYSTAL = WALL_OVERHANG+27;
public static final int DOOR_SIDEWAYS = WALL_OVERHANG+28;
public static final int DOOR_SIDEWAYS_LOCKED = WALL_OVERHANG+29;
public static final int DOOR_SIDEWAYS_CRYSTAL = WALL_OVERHANG+30;
public static final int STATUE_OVERHANG = WALL_OVERHANG+32;
public static final int ALCHEMY_POT_OVERHANG = WALL_OVERHANG+33;
@ -371,6 +378,7 @@ public class DungeonTileSheet {
directFlatVisuals.put(Terrain.DOOR, FLAT_DOOR);
directFlatVisuals.put(Terrain.OPEN_DOOR, FLAT_DOOR_OPEN);
directFlatVisuals.put(Terrain.LOCKED_DOOR, FLAT_DOOR_LOCKED);
directFlatVisuals.put(Terrain.CRYSTAL_DOOR, FLAT_DOOR_CRYSTAL);
directFlatVisuals.put(Terrain.WALL_DECO, FLAT_WALL_DECO);
directFlatVisuals.put(Terrain.BOOKSHELF, FLAT_BOOKSHELF);
directFlatVisuals.put(Terrain.SIGN, FLAT_SIGN);

View File

@ -43,6 +43,8 @@ public class DungeonWallsTilemap extends DungeonTilemap {
return DungeonTileSheet.DOOR_SIDEWAYS;
} else if (map[pos + mapWidth] == Terrain.LOCKED_DOOR){
return DungeonTileSheet.DOOR_SIDEWAYS_LOCKED;
} else if (map[pos + mapWidth] == Terrain.CRYSTAL_DOOR){
return DungeonTileSheet.DOOR_SIDEWAYS_CRYSTAL;
} else if (map[pos + mapWidth] == Terrain.OPEN_DOOR){
return DungeonTileSheet.NULL_TILE;
}
@ -73,6 +75,8 @@ public class DungeonWallsTilemap extends DungeonTilemap {
return DungeonTileSheet.DOOR_OVERHANG;
} else if (Dungeon.level.insideMap(pos) && map[pos+mapWidth] == Terrain.OPEN_DOOR ) {
return DungeonTileSheet.DOOR_OVERHANG_OPEN;
} else if (Dungeon.level.insideMap(pos) && map[pos+mapWidth] == Terrain.CRYSTAL_DOOR ) {
return DungeonTileSheet.DOOR_OVERHANG_CRYSTAL;
} else if (pos + mapWidth < size && (map[pos+mapWidth] == Terrain.STATUE || map[pos+mapWidth] == Terrain.STATUE_SP)){
return DungeonTileSheet.STATUE_OVERHANG;
} else if (pos + mapWidth < size && map[pos+mapWidth] == Terrain.ALCHEMY){