V0.1.0 Partial Commit

changed package and application names to differentiate from main PD
release
This commit is contained in:
Evan Debenham
2014-08-03 14:46:22 -04:00
parent 65dd9c2dc0
commit aed303672a
474 changed files with 3468 additions and 3458 deletions
@@ -0,0 +1,299 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Camera;
import com.watabou.noosa.Scene;
import com.watabou.noosa.audio.Sample;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
public class CavesBossLevel extends Level {
{
color1 = 0x534f3e;
color2 = 0xb9d661;
viewDistance = 6;
}
private static final int ROOM_LEFT = WIDTH / 2 - 2;
private static final int ROOM_RIGHT = WIDTH / 2 + 2;
private static final int ROOM_TOP = HEIGHT / 2 - 2;
private static final int ROOM_BOTTOM = HEIGHT / 2 + 2;
private int arenaDoor;
private boolean enteredArena = false;
private boolean keyDropped = false;
@Override
public String tilesTex() {
return Assets.TILES_CAVES;
}
@Override
public String waterTex() {
return Assets.WATER_CAVES;
}
private static final String DOOR = "door";
private static final String ENTERED = "entered";
private static final String DROPPED = "droppped";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( DOOR, arenaDoor );
bundle.put( ENTERED, enteredArena );
bundle.put( DROPPED, keyDropped );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
arenaDoor = bundle.getInt( DOOR );
enteredArena = bundle.getBoolean( ENTERED );
keyDropped = bundle.getBoolean( DROPPED );
}
@Override
protected boolean build() {
int topMost = Integer.MAX_VALUE;
for (int i=0; i < 8; i++) {
int left, right, top, bottom;
if (Random.Int( 2 ) == 0) {
left = Random.Int( 1, ROOM_LEFT - 3 );
right = ROOM_RIGHT + 3;
} else {
left = ROOM_LEFT - 3;
right = Random.Int( ROOM_RIGHT + 3, WIDTH - 1 );
}
if (Random.Int( 2 ) == 0) {
top = Random.Int( 2, ROOM_TOP - 3 );
bottom = ROOM_BOTTOM + 3;
} else {
top = ROOM_LEFT - 3;
bottom = Random.Int( ROOM_TOP + 3, HEIGHT - 1 );
}
Painter.fill( this, left, top, right - left + 1, bottom - top + 1, Terrain.EMPTY );
if (top < topMost) {
topMost = top;
exit = Random.Int( left, right ) + (top - 1) * WIDTH;
}
}
map[exit] = Terrain.LOCKED_EXIT;
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 6 ) == 0) {
map[i] = Terrain.INACTIVE_TRAP;
}
}
Painter.fill( this, ROOM_LEFT - 1, ROOM_TOP - 1,
ROOM_RIGHT - ROOM_LEFT + 3, ROOM_BOTTOM - ROOM_TOP + 3, Terrain.WALL );
Painter.fill( this, ROOM_LEFT, ROOM_TOP + 1,
ROOM_RIGHT - ROOM_LEFT + 1, ROOM_BOTTOM - ROOM_TOP, Terrain.EMPTY );
Painter.fill( this, ROOM_LEFT, ROOM_TOP,
ROOM_RIGHT - ROOM_LEFT + 1, 1, Terrain.TOXIC_TRAP );
arenaDoor = Random.Int( ROOM_LEFT, ROOM_RIGHT ) + (ROOM_BOTTOM + 1) * WIDTH;
map[arenaDoor] = Terrain.DOOR;
entrance = Random.Int( ROOM_LEFT + 1, ROOM_RIGHT - 1 ) +
Random.Int( ROOM_TOP + 1, ROOM_BOTTOM - 1 ) * WIDTH;
map[entrance] = Terrain.ENTRANCE;
boolean[] patch = Patch.generate( 0.45f, 6 );
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && patch[i]) {
map[i] = Terrain.WATER;
}
}
return true;
}
@Override
protected void decorate() {
for (int i=WIDTH + 1; i < LENGTH - WIDTH; i++) {
if (map[i] == Terrain.EMPTY) {
int n = 0;
if (map[i+1] == Terrain.WALL) {
n++;
}
if (map[i-1] == Terrain.WALL) {
n++;
}
if (map[i+WIDTH] == Terrain.WALL) {
n++;
}
if (map[i-WIDTH] == Terrain.WALL) {
n++;
}
if (Random.Int( 8 ) <= n) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
int sign;
do {
sign = Random.Int( ROOM_LEFT, ROOM_RIGHT ) + Random.Int( ROOM_TOP, ROOM_BOTTOM ) * WIDTH;
} while (sign == entrance);
map[sign] = Terrain.SIGN;
}
@Override
protected void createMobs() {
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos = Random.IntRange( ROOM_LEFT, ROOM_RIGHT ) + Random.IntRange( ROOM_TOP + 1, ROOM_BOTTOM ) * WIDTH;
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public void press( int cell, Char hero ) {
super.press( cell, hero );
if (!enteredArena && outsideEntraceRoom( cell ) && hero == Dungeon.hero) {
enteredArena = true;
Mob boss = Bestiary.mob( Dungeon.depth );
boss.state = Mob.State.HUNTING;
do {
boss.pos = Random.Int( LENGTH );
} while (
!passable[boss.pos] ||
!outsideEntraceRoom( boss.pos ) ||
Dungeon.visible[boss.pos]);
GameScene.add( boss );
set( arenaDoor, Terrain.WALL );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
CellEmitter.get( arenaDoor ).start( Speck.factory( Speck.ROCK ), 0.07f, 10 );
Camera.main.shake( 3, 0.7f );
Sample.INSTANCE.play( Assets.SND_ROCKS );
}
}
@Override
public Heap drop( Item item, int cell ) {
if (!keyDropped && item instanceof SkeletonKey) {
keyDropped = true;
CellEmitter.get( arenaDoor ).start( Speck.factory( Speck.ROCK ), 0.07f, 10 );
set( arenaDoor, Terrain.EMPTY_DECO );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
}
return super.drop( item, cell );
}
private boolean outsideEntraceRoom( int cell ) {
int cx = cell % WIDTH;
int cy = cell / WIDTH;
return cx < ROOM_LEFT-1 || cx > ROOM_RIGHT+1 || cy < ROOM_TOP-1 || cy > ROOM_BOTTOM+1;
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.GRASS:
return "Fluorescent moss";
case Terrain.HIGH_GRASS:
return "Fluorescent mushrooms";
case Terrain.WATER:
return "Freezing cold water.";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc( int tile ) {
switch (tile) {
case Terrain.ENTRANCE:
return "The ladder leads up to the upper depth.";
case Terrain.EXIT:
return "The ladder leads down to the lower depth.";
case Terrain.HIGH_GRASS:
return "Huge mushrooms block the view.";
case Terrain.WALL_DECO:
return "A vein of some ore is visible on the wall. Gold?";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
CavesLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,284 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Game;
import com.watabou.noosa.Group;
import com.watabou.noosa.Scene;
import com.watabou.noosa.particles.PixelParticle;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
import com.watabou.utils.Rect;
public class CavesLevel extends RegularLevel {
{
color1 = 0x534f3e;
color2 = 0xb9d661;
viewDistance = 6;
}
@Override
public String tilesTex() {
return Assets.TILES_CAVES;
}
@Override
public String waterTex() {
return Assets.WATER_CAVES;
}
protected boolean[] water() {
return Patch.generate( feeling == Feeling.WATER ? 0.60f : 0.45f, 6 );
}
protected boolean[] grass() {
return Patch.generate( feeling == Feeling.GRASS ? 0.55f : 0.35f, 3 );
}
@Override
protected void assignRoomType() {
super.assignRoomType();
Blacksmith.Quest.spawn( rooms );
}
@Override
protected void decorate() {
for (Room room : rooms) {
if (room.type != Room.Type.STANDARD) {
continue;
}
if (room.width() <= 3 || room.height() <= 3) {
continue;
}
int s = room.square();
if (Random.Int( s ) > 8) {
int corner = (room.left + 1) + (room.top + 1) * WIDTH;
if (map[corner - 1] == Terrain.WALL && map[corner - WIDTH] == Terrain.WALL) {
map[corner] = Terrain.WALL;
}
}
if (Random.Int( s ) > 8) {
int corner = (room.right - 1) + (room.top + 1) * WIDTH;
if (map[corner + 1] == Terrain.WALL && map[corner - WIDTH] == Terrain.WALL) {
map[corner] = Terrain.WALL;
}
}
if (Random.Int( s ) > 8) {
int corner = (room.left + 1) + (room.bottom - 1) * WIDTH;
if (map[corner - 1] == Terrain.WALL && map[corner + WIDTH] == Terrain.WALL) {
map[corner] = Terrain.WALL;
}
}
if (Random.Int( s ) > 8) {
int corner = (room.right - 1) + (room.bottom - 1) * WIDTH;
if (map[corner + 1] == Terrain.WALL && map[corner + WIDTH] == Terrain.WALL) {
map[corner] = Terrain.WALL;
}
}
for (Room n : room.connected.keySet()) {
if ((n.type == Room.Type.STANDARD || n.type == Room.Type.TUNNEL) && Random.Int( 3 ) == 0) {
Painter.set( this, room.connected.get( n ), Terrain.EMPTY_DECO );
}
}
}
for (int i=WIDTH + 1; i < LENGTH - WIDTH; i++) {
if (map[i] == Terrain.EMPTY) {
int n = 0;
if (map[i+1] == Terrain.WALL) {
n++;
}
if (map[i-1] == Terrain.WALL) {
n++;
}
if (map[i+WIDTH] == Terrain.WALL) {
n++;
}
if (map[i-WIDTH] == Terrain.WALL) {
n++;
}
if (Random.Int( 6 ) <= n) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.WALL && Random.Int( 12 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
if (Dungeon.bossLevel( Dungeon.depth + 1 )) {
return;
}
for (Room r : rooms) {
if (r.type == Type.STANDARD) {
for (Room n : r.neigbours) {
if (n.type == Type.STANDARD && !r.connected.containsKey( n )/* && Random.Int( 2 ) == 0*/) {
Rect w = r.intersect( n );
if (w.left == w.right && w.bottom - w.top >= 5) {
w.top += 2;
w.bottom -= 1;
w.right++;
Painter.fill( this, w.left, w.top, 1, w.height(), Terrain.CHASM );
} else if (w.top == w.bottom && w.right - w.left >= 5) {
w.left += 2;
w.right -= 1;
w.bottom++;
Painter.fill( this, w.left, w.top, w.width(), 1, Terrain.CHASM );
}
}
}
}
}
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.GRASS:
return "Fluorescent moss";
case Terrain.HIGH_GRASS:
return "Fluorescent mushrooms";
case Terrain.WATER:
return "Freezing cold water.";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc( int tile ) {
switch (tile) {
case Terrain.ENTRANCE:
return "The ladder leads up to the upper depth.";
case Terrain.EXIT:
return "The ladder leads down to the lower depth.";
case Terrain.HIGH_GRASS:
return "Huge mushrooms block the view.";
case Terrain.WALL_DECO:
return "A vein of some ore is visible on the wall. Gold?";
case Terrain.BOOKSHELF:
return "Who would need a bookshelf in a cave?";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
super.addVisuals( scene );
addVisuals( this, scene );
}
public static void addVisuals( Level level, Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (level.map[i] == Terrain.WALL_DECO) {
scene.add( new Vein( i ) );
}
}
}
private static class Vein extends Group {
private int pos;
private float delay;
public Vein( int pos ) {
super();
this.pos = pos;
delay = Random.Float( 2 );
}
@Override
public void update() {
if (visible = Dungeon.visible[pos]) {
super.update();
if ((delay -= Game.elapsed) <= 0) {
delay = Random.Float();
PointF p = DungeonTilemap.tileToWorld( pos );
((Sparkle)recycle( Sparkle.class )).reset(
p.x + Random.Float( DungeonTilemap.SIZE ),
p.y + Random.Float( DungeonTilemap.SIZE ) );
}
}
}
}
public static final class Sparkle extends PixelParticle {
public void reset( float x, float y ) {
revive();
this.x = x;
this.y = y;
left = lifespan = 0.5f;
}
@Override
public void update() {
super.update();
float p = left / lifespan;
size( (am = p < 0.5f ? p * 2 : (1 - p) * 2) * 2 );
}
}
}
@@ -0,0 +1,253 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
public class CityBossLevel extends Level {
{
color1 = 0x4b6636;
color2 = 0xf2f2f2;
}
private static final int TOP = 2;
private static final int HALL_WIDTH = 7;
private static final int HALL_HEIGHT = 15;
private static final int CHAMBER_HEIGHT = 3;
private static final int LEFT = (WIDTH - HALL_WIDTH) / 2;
private static final int CENTER = LEFT + HALL_WIDTH / 2;
private int arenaDoor;
private boolean enteredArena = false;
private boolean keyDropped = false;
@Override
public String tilesTex() {
return Assets.TILES_CITY;
}
@Override
public String waterTex() {
return Assets.WATER_CITY;
}
private static final String DOOR = "door";
private static final String ENTERED = "entered";
private static final String DROPPED = "droppped";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( DOOR, arenaDoor );
bundle.put( ENTERED, enteredArena );
bundle.put( DROPPED, keyDropped );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
arenaDoor = bundle.getInt( DOOR );
enteredArena = bundle.getBoolean( ENTERED );
keyDropped = bundle.getBoolean( DROPPED );
}
@Override
protected boolean build() {
Painter.fill( this, LEFT, TOP, HALL_WIDTH, HALL_HEIGHT, Terrain.EMPTY );
Painter.fill( this, CENTER, TOP, 1, HALL_HEIGHT, Terrain.EMPTY_SP );
int y = TOP + 1;
while (y < TOP + HALL_HEIGHT) {
map[y * WIDTH + CENTER - 2] = Terrain.STATUE_SP;
map[y * WIDTH + CENTER + 2] = Terrain.STATUE_SP;
y += 2;
}
int left = pedestal( true );
int right = pedestal( false );
map[left] = map[right] = Terrain.PEDESTAL;
for (int i=left+1; i < right; i++) {
map[i] = Terrain.EMPTY_SP;
}
exit = (TOP - 1) * WIDTH + CENTER;
map[exit] = Terrain.LOCKED_EXIT;
arenaDoor = (TOP + HALL_HEIGHT) * WIDTH + CENTER;
map[arenaDoor] = Terrain.DOOR;
Painter.fill( this, LEFT, TOP + HALL_HEIGHT + 1, HALL_WIDTH, CHAMBER_HEIGHT, Terrain.EMPTY );
Painter.fill( this, LEFT, TOP + HALL_HEIGHT + 1, 1, CHAMBER_HEIGHT, Terrain.BOOKSHELF );
Painter.fill( this, LEFT + HALL_WIDTH - 1, TOP + HALL_HEIGHT + 1, 1, CHAMBER_HEIGHT, Terrain.BOOKSHELF );
entrance = (TOP + HALL_HEIGHT + 2 + Random.Int( CHAMBER_HEIGHT - 1 )) * WIDTH + LEFT + (/*1 +*/ Random.Int( HALL_WIDTH-2 ));
map[entrance] = Terrain.ENTRANCE;
return true;
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
} else if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
int sign = arenaDoor + WIDTH + 1;
map[sign] = Terrain.SIGN;
}
public static int pedestal( boolean left ) {
if (left) {
return (TOP + HALL_HEIGHT / 2) * WIDTH + CENTER - 2;
} else {
return (TOP + HALL_HEIGHT / 2) * WIDTH + CENTER + 2;
}
}
@Override
protected void createMobs() {
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos =
Random.IntRange( LEFT + 1, LEFT + HALL_WIDTH - 2 ) +
Random.IntRange( TOP + HALL_HEIGHT + 1, TOP + HALL_HEIGHT + CHAMBER_HEIGHT ) * WIDTH;
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public void press( int cell, Char hero ) {
super.press( cell, hero );
if (!enteredArena && outsideEntraceRoom( cell ) && hero == Dungeon.hero) {
enteredArena = true;
Mob boss = Bestiary.mob( Dungeon.depth );
boss.state = Mob.State.HUNTING;
do {
boss.pos = Random.Int( LENGTH );
} while (
!passable[boss.pos] ||
!outsideEntraceRoom( boss.pos ) ||
Dungeon.visible[boss.pos]);
GameScene.add( boss );
set( arenaDoor, Terrain.LOCKED_DOOR );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
}
}
@Override
public Heap drop( Item item, int cell ) {
if (!keyDropped && item instanceof SkeletonKey) {
keyDropped = true;
set( arenaDoor, Terrain.DOOR );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
}
return super.drop( item, cell );
}
private boolean outsideEntraceRoom( int cell ) {
return cell / WIDTH < arenaDoor / WIDTH;
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Suspiciously colored water";
case Terrain.HIGH_GRASS:
return "High blooming flowers";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.ENTRANCE:
return "A ramp leads up to the upper depth.";
case Terrain.EXIT:
return "A ramp leads down to the lower depth.";
case Terrain.WALL_DECO:
case Terrain.EMPTY_DECO:
return "Several tiles are missing here.";
case Terrain.EMPTY_SP:
return "Thick carpet covers the floor.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "The statue depicts some dwarf standing in a heroic stance.";
case Terrain.BOOKSHELF:
return "The rows of books on different disciplines fill the bookshelf.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
CityLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,200 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Scene;
import com.watabou.noosa.particles.Emitter;
import com.watabou.noosa.particles.PixelParticle;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class CityLevel extends RegularLevel {
{
color1 = 0x4b6636;
color2 = 0xf2f2f2;
}
@Override
public String tilesTex() {
return Assets.TILES_CITY;
}
@Override
public String waterTex() {
return Assets.WATER_CITY;
}
protected boolean[] water() {
return Patch.generate( feeling == Feeling.WATER ? 0.65f : 0.45f, 4 );
}
protected boolean[] grass() {
return Patch.generate( feeling == Feeling.GRASS ? 0.60f : 0.40f, 3 );
}
@Override
protected void assignRoomType() {
super.assignRoomType();
for (Room r : rooms) {
if (r.type == Type.TUNNEL) {
r.type = Type.PASSAGE;
}
}
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
} else if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
@Override
protected void createItems() {
super.createItems();
Imp.Quest.spawn( this, roomEntrance );
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Suspiciously colored water";
case Terrain.HIGH_GRASS:
return "High blooming flowers";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.ENTRANCE:
return "A ramp leads up to the upper depth.";
case Terrain.EXIT:
return "A ramp leads down to the lower depth.";
case Terrain.WALL_DECO:
case Terrain.EMPTY_DECO:
return "Several tiles are missing here.";
case Terrain.EMPTY_SP:
return "Thick carpet covers the floor.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "The statue depicts some dwarf standing in a heroic stance.";
case Terrain.BOOKSHELF:
return "The rows of books on different disciplines fill the bookshelf.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
super.addVisuals( scene );
addVisuals( this, scene );
}
public static void addVisuals( Level level, Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (level.map[i] == Terrain.WALL_DECO) {
scene.add( new Smoke( i ) );
}
}
}
private static class Smoke extends Emitter {
private int pos;
private static final Emitter.Factory factory = new Factory() {
@Override
public void emit( Emitter emitter, int index, float x, float y ) {
SmokeParticle p = (SmokeParticle)emitter.recycle( SmokeParticle.class );
p.reset( x, y );
}
};
public Smoke( int pos ) {
super();
this.pos = pos;
PointF p = DungeonTilemap.tileCenterToWorld( pos );
pos( p.x - 4, p.y - 2, 4, 0 );
pour( factory, 0.2f );
}
@Override
public void update() {
if (visible = Dungeon.visible[pos]) {
super.update();
}
}
}
public static final class SmokeParticle extends PixelParticle {
public SmokeParticle() {
super();
color( 0x000000 );
speed.set( Random.Float( 8 ), -Random.Float( 8 ) );
}
public void reset( float x, float y ) {
revive();
this.x = x;
this.y = y;
left = lifespan = 2f;
}
@Override
public void update() {
super.update();
float p = left / lifespan;
am = p > 0.8f ? 1 - p : p * 0.25f;
size( 8 - p * 4 );
}
}
}
@@ -0,0 +1,97 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.Arrays;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.watabou.utils.Random;
public class DeadEndLevel extends Level {
private static final int SIZE = 5;
{
color1 = 0x534f3e;
color2 = 0xb9d661;
}
@Override
public String tilesTex() {
return Assets.TILES_CAVES;
}
@Override
public String waterTex() {
return Assets.WATER_HALLS;
}
@Override
protected boolean build() {
Arrays.fill( map, Terrain.WALL );
for (int i=2; i < SIZE; i++) {
for (int j=2; j < SIZE; j++) {
map[i * WIDTH + j] = Terrain.EMPTY;
}
}
for (int i=1; i <= SIZE; i++) {
map[WIDTH + i] =
map[WIDTH * SIZE + i] =
map[WIDTH * i + 1] =
map[WIDTH * i + SIZE] =
Terrain.WATER;
}
entrance = SIZE * WIDTH + SIZE / 2 + 1;
map[entrance] = Terrain.ENTRANCE;
exit = -1;
map[(SIZE / 2 + 1) * (WIDTH + 1)] = Terrain.SIGN;
return true;
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
} else if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
}
@Override
protected void createMobs() {
}
@Override
protected void createItems() {
}
@Override
public int randomRespawnCell() {
return -1;
}
}
@@ -0,0 +1,253 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
public class HallsBossLevel extends Level {
{
color1 = 0x801500;
color2 = 0xa68521;
viewDistance = 3;
}
private static final int ROOM_LEFT = WIDTH / 2 - 1;
private static final int ROOM_RIGHT = WIDTH / 2 + 1;
private static final int ROOM_TOP = HEIGHT / 2 - 1;
private static final int ROOM_BOTTOM = HEIGHT / 2 + 1;
private int stairs = -1;
private boolean enteredArena = false;
private boolean keyDropped = false;
@Override
public String tilesTex() {
return Assets.TILES_HALLS;
}
@Override
public String waterTex() {
return Assets.WATER_HALLS;
}
private static final String STAIRS = "stairs";
private static final String ENTERED = "entered";
private static final String DROPPED = "droppped";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( STAIRS, stairs );
bundle.put( ENTERED, enteredArena );
bundle.put( DROPPED, keyDropped );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
stairs = bundle.getInt( STAIRS );
enteredArena = bundle.getBoolean( ENTERED );
keyDropped = bundle.getBoolean( DROPPED );
}
@Override
protected boolean build() {
for (int i=0; i < 5; i++) {
int top = Random.IntRange( 2, ROOM_TOP - 1 );
int bottom = Random.IntRange( ROOM_BOTTOM + 1, 22 );
Painter.fill( this, 2 + i * 4, top, 4, bottom - top + 1, Terrain.EMPTY );
if (i == 2) {
exit = (i * 4 + 3) + (top - 1) * WIDTH ;
}
for (int j=0; j < 4; j++) {
if (Random.Int( 2 ) == 0) {
int y = Random.IntRange( top + 1, bottom - 1 );
map[i*4+j + y*WIDTH] = Terrain.WALL_DECO;
}
}
}
map[exit] = Terrain.LOCKED_EXIT;
Painter.fill( this, ROOM_LEFT - 1, ROOM_TOP - 1,
ROOM_RIGHT - ROOM_LEFT + 3, ROOM_BOTTOM - ROOM_TOP + 3, Terrain.WALL );
Painter.fill( this, ROOM_LEFT, ROOM_TOP,
ROOM_RIGHT - ROOM_LEFT + 1, ROOM_BOTTOM - ROOM_TOP + 1, Terrain.EMPTY );
entrance = Random.Int( ROOM_LEFT + 1, ROOM_RIGHT - 1 ) +
Random.Int( ROOM_TOP + 1, ROOM_BOTTOM - 1 ) * WIDTH;
map[entrance] = Terrain.ENTRANCE;
boolean[] patch = Patch.generate( 0.45f, 6 );
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && patch[i]) {
map[i] = Terrain.WATER;
}
}
return true;
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
@Override
protected void createMobs() {
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos = Random.IntRange( ROOM_LEFT, ROOM_RIGHT ) + Random.IntRange( ROOM_TOP + 1, ROOM_BOTTOM ) * WIDTH;
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public void press( int cell, Char hero ) {
super.press( cell, hero );
if (!enteredArena && hero == Dungeon.hero && cell != entrance) {
enteredArena = true;
for (int i=ROOM_LEFT-1; i <= ROOM_RIGHT + 1; i++) {
doMagic( (ROOM_TOP - 1) * WIDTH + i );
doMagic( (ROOM_BOTTOM + 1) * WIDTH + i );
}
for (int i=ROOM_TOP; i < ROOM_BOTTOM + 1; i++) {
doMagic( i * WIDTH + ROOM_LEFT - 1 );
doMagic( i * WIDTH + ROOM_RIGHT + 1 );
}
doMagic( entrance );
GameScene.updateMap();
Dungeon.observe();
Yog boss = new Yog();
do {
boss.pos = Random.Int( LENGTH );
} while (
!passable[boss.pos] ||
Dungeon.visible[boss.pos]);
GameScene.add( boss );
boss.spawnFists();
stairs = entrance;
entrance = -1;
}
}
private void doMagic( int cell ) {
set( cell, Terrain.EMPTY_SP );
CellEmitter.get( cell ).start( FlameParticle.FACTORY, 0.1f, 3 );
}
@Override
public Heap drop( Item item, int cell ) {
if (!keyDropped && item instanceof SkeletonKey) {
keyDropped = true;
entrance = stairs;
set( entrance, Terrain.ENTRANCE );
GameScene.updateMap( entrance );
}
return super.drop( item, cell );
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Cold lava";
case Terrain.GRASS:
return "Embermoss";
case Terrain.HIGH_GRASS:
return "Emberfungi";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "Pillar";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.WATER:
return "It looks like lava, but it's cold and probably safe to touch.";
case Terrain.EMPTY_DECO:
return "Candles on the floor are probably remains of some ritual that took place here.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "The pillar is made of real humanoid skulls. Awesome.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
HallsLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,232 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import com.watabou.noosa.Game;
import com.watabou.noosa.Group;
import com.watabou.noosa.Scene;
import com.watabou.noosa.particles.PixelParticle;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.items.Torch;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class HallsLevel extends RegularLevel {
{
minRoomSize = 6;
viewDistance = Math.max( 25 - Dungeon.depth, 1 );
color1 = 0x801500;
color2 = 0xa68521;
}
@Override
public void create() {
addItemToSpawn( new Torch() );
super.create();
}
@Override
public String tilesTex() {
return Assets.TILES_HALLS;
}
@Override
public String waterTex() {
return Assets.WATER_HALLS;
}
protected boolean[] water() {
return Patch.generate( feeling == Feeling.WATER ? 0.55f : 0.40f, 6 );
}
protected boolean[] grass() {
return Patch.generate( feeling == Feeling.GRASS ? 0.55f : 0.30f, 3 );
}
@Override
protected void decorate() {
for (int i=WIDTH + 1; i < LENGTH - WIDTH - 1; i++) {
if (map[i] == Terrain.EMPTY) {
int count = 0;
for (int j=0; j < NEIGHBOURS8.length; j++) {
if ((Terrain.flags[map[i + NEIGHBOURS8[j]]] & Terrain.PASSABLE) > 0) {
count++;
}
}
if (Random.Int( 80 ) < count) {
map[i] = Terrain.EMPTY_DECO;
}
} else
if (map[i] == Terrain.WALL) {
int count = 0;
for (int j=0; j < NEIGHBOURS4.length; j++) {
if (map[i + NEIGHBOURS4[j]] == Terrain.WATER) {
count++;
}
}
if (Random.Int( 4 ) < count) {
map[i] = Terrain.WALL_DECO;
}
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Cold lava";
case Terrain.GRASS:
return "Embermoss";
case Terrain.HIGH_GRASS:
return "Emberfungi";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "Pillar";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.WATER:
return "It looks like lava, but it's cold and probably safe to touch.";
case Terrain.EMPTY_DECO:
return "Candles on the floor are probably remains of some ritual that took place here.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "The pillar is made of real humanoid skulls. Awesome.";
case Terrain.BOOKSHELF:
return "Books in ancient languages smoulder in the bookshelf.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
super.addVisuals( scene );
addVisuals( this, scene );
}
public static void addVisuals( Level level, Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (level.map[i] == 63) {
scene.add( new Stream( i ) );
}
}
}
private static class Stream extends Group {
private int pos;
private float delay;
public Stream( int pos ) {
super();
this.pos = pos;
delay = Random.Float( 2 );
}
@Override
public void update() {
if (visible = Dungeon.visible[pos]) {
super.update();
if ((delay -= Game.elapsed) <= 0) {
delay = Random.Float( 2 );
PointF p = DungeonTilemap.tileToWorld( pos );
((FireParticle)recycle( FireParticle.class )).reset(
p.x + Random.Float( DungeonTilemap.SIZE ),
p.y + Random.Float( DungeonTilemap.SIZE ) );
}
}
}
@Override
public void draw() {
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE );
super.draw();
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
}
}
public static class FireParticle extends PixelParticle.Shrinking {
public FireParticle() {
super();
color( 0xEE7722 );
lifespan = 1f;
acc.set( 0, +80 );
}
public void reset( float x, float y ) {
revive();
this.x = x;
this.y = y;
left = lifespan;
speed.set( 0, -40 );
size = 4;
}
@Override
public void update() {
super.update();
float p = left / lifespan;
am = p > 0.8f ? (1 - p) * 5 : 1;
}
}
}
@@ -0,0 +1,131 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.Arrays;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.items.Amulet;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.watabou.utils.Random;
public class LastLevel extends Level {
private static final int SIZE = 7;
{
color1 = 0x801500;
color2 = 0xa68521;
}
private int pedestal;
@Override
public String tilesTex() {
return Assets.TILES_HALLS;
}
@Override
public String waterTex() {
return Assets.WATER_HALLS;
}
@Override
protected boolean build() {
Arrays.fill( map, Terrain.WALL );
Painter.fill( this, 1, 1, SIZE, SIZE, Terrain.WATER );
Painter.fill( this, 2, 2, SIZE-2, SIZE-2, Terrain.EMPTY );
Painter.fill( this, SIZE/2, SIZE/2, 3, 3, Terrain.EMPTY_SP );
entrance = SIZE * WIDTH + SIZE / 2 + 1;
map[entrance] = Terrain.ENTRANCE;
exit = entrance - WIDTH * SIZE;
map[exit] = Terrain.LOCKED_EXIT;
pedestal = (SIZE / 2 + 1) * (WIDTH + 1);
map[pedestal] = Terrain.PEDESTAL;
map[pedestal-1] = map[pedestal+1] = Terrain.STATUE_SP;
feeling = Feeling.NONE;
return true;
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
@Override
protected void createMobs() {
}
@Override
protected void createItems() {
drop( new Amulet(), pedestal );
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Cold lava";
case Terrain.GRASS:
return "Embermoss";
case Terrain.HIGH_GRASS:
return "Emberfungi";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "Pillar";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.WATER:
return "It looks like lava, but it's cold and probably safe to touch.";
case Terrain.EMPTY_DECO:
return "Candles on the floor are probably remains of some ritual that took place here.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "The pillar is made of real humanoid skulls. Awesome.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
HallsLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,225 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.List;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
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.Room.Type;
import com.watabou.utils.Graph;
import com.watabou.utils.Random;
public class LastShopLevel extends RegularLevel {
{
color1 = 0x4b6636;
color2 = 0xf2f2f2;
}
@Override
public String tilesTex() {
return Assets.TILES_CITY;
}
@Override
public String waterTex() {
return Assets.WATER_CITY;
}
@Override
protected boolean build() {
initRooms();
int distance;
int retry = 0;
int minDistance = (int)Math.sqrt( rooms.size() );
do {
int innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomEntrance = Random.element( rooms );
} while (roomEntrance.width() < 4 || roomEntrance.height() < 4);
innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomExit = Random.element( rooms );
} while (roomExit == roomEntrance || roomExit.width() < 6 || roomExit.height() < 6 || roomExit.top == 0);
Graph.buildDistanceMap( rooms, roomExit );
distance = Graph.buildPath( rooms, roomEntrance, roomExit ).size();
if (retry++ > 10) {
return false;
}
} while (distance < minDistance);
roomEntrance.type = Type.ENTRANCE;
roomExit.type = Type.EXIT;
Graph.buildDistanceMap( rooms, roomExit );
List<Room> path = Graph.buildPath( rooms, roomEntrance, roomExit );
Graph.setPrice( path, roomEntrance.distance );
Graph.buildDistanceMap( rooms, roomExit );
path = Graph.buildPath( rooms, roomEntrance, roomExit );
Room room = roomEntrance;
for (Room next : path) {
room.connect( next );
room = next;
}
Room roomShop = null;
int shopSquare = 0;
for (Room r : rooms) {
if (r.type == Type.NULL && r.connected.size() > 0) {
r.type = Type.PASSAGE;
if (r.square() > shopSquare) {
roomShop = r;
shopSquare = r.square();
}
}
}
if (roomShop == null || shopSquare < 30) {
return false;
} else {
roomShop.type = Imp.Quest.isCompleted() ? Room.Type.SHOP : Room.Type.STANDARD;
}
paint();
paintWater();
paintGrass();
return true;
}
@Override
protected void decorate() {
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && Random.Int( 10 ) == 0) {
map[i] = Terrain.EMPTY_DECO;
} else if (map[i] == Terrain.WALL && Random.Int( 8 ) == 0) {
map[i] = Terrain.WALL_DECO;
} else if (map[i] == Terrain.SECRET_DOOR) {
map[i] = Terrain.DOOR;
}
}
if (Imp.Quest.isCompleted()) {
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
}
@Override
protected void createMobs() {
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos = roomEntrance.random();
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Suspiciously colored water";
case Terrain.HIGH_GRASS:
return "High blooming flowers";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.ENTRANCE:
return "A ramp leads up to the upper depth.";
case Terrain.EXIT:
return "A ramp leads down to the Inferno.";
case Terrain.WALL_DECO:
case Terrain.EMPTY_DECO:
return "Several tiles are missing here.";
case Terrain.EMPTY_SP:
return "Thick carpet covers the floor.";
default:
return super.tileDesc( tile );
}
}
@Override
protected boolean[] water() {
return Patch.generate( 0.35f, 4 );
}
@Override
protected boolean[] grass() {
return Patch.generate( 0.30f, 3 );
}
@Override
public void addVisuals( Scene scene ) {
CityLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,975 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import com.watabou.noosa.Scene;
import com.watabou.noosa.audio.Sample;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
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.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WellWater;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Awareness;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Shadows;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlowParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.WindParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Stylus;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
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.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.*;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ShadowCaster;
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
import com.watabou.utils.SparseArray;
public abstract class Level implements Bundlable {
public static enum Feeling {
NONE,
CHASM,
WATER,
GRASS
};
public static final int WIDTH = 32;
public static final int HEIGHT = 32;
public static final int LENGTH = WIDTH * HEIGHT;
public static final int[] NEIGHBOURS4 = {-WIDTH, +1, +WIDTH, -1};
public static final int[] NEIGHBOURS8 = {+1, -1, +WIDTH, -WIDTH, +1+WIDTH, +1-WIDTH, -1+WIDTH, -1-WIDTH};
public static final int[] NEIGHBOURS9 = {0, +1, -1, +WIDTH, -WIDTH, +1+WIDTH, +1-WIDTH, -1+WIDTH, -1-WIDTH};
protected static final float TIME_TO_RESPAWN = 50;
private static final String TXT_HIDDEN_PLATE_CLICKS = "A hidden pressure plate clicks!";
public static boolean resizingNeeded;
// This one can be different from resizingNeeded if the level
// was created in the older version of the game
public static int loadedMapSize;
public int[] map;
public boolean[] visited;
public boolean[] mapped;
public int viewDistance = 8;
public static boolean[] fieldOfView = new boolean[LENGTH];
public static boolean[] passable = new boolean[LENGTH];
public static boolean[] losBlocking = new boolean[LENGTH];
public static boolean[] flamable = new boolean[LENGTH];
public static boolean[] secret = new boolean[LENGTH];
public static boolean[] solid = new boolean[LENGTH];
public static boolean[] avoid = new boolean[LENGTH];
public static boolean[] water = new boolean[LENGTH];
public static boolean[] pit = new boolean[LENGTH];
public static boolean[] discoverable = new boolean[LENGTH];
public Feeling feeling = Feeling.NONE;
public int entrance;
public int exit;
public HashSet<Mob> mobs;
public SparseArray<Heap> heaps;
public HashMap<Class<? extends Blob>,Blob> blobs;
public SparseArray<Plant> plants;
protected ArrayList<Item> itemsToSpawn = new ArrayList<Item>();
public int color1 = 0x004400;
public int color2 = 0x88CC44;
protected static boolean pitRoomNeeded = false;
protected static boolean weakFloorCreated = false;
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 HEAPS = "heaps";
private static final String PLANTS = "plants";
private static final String MOBS = "mobs";
private static final String BLOBS = "blobs";
public void create() {
resizingNeeded = false;
map = new int[LENGTH];
visited = new boolean[LENGTH];
Arrays.fill( visited, false );
mapped = new boolean[LENGTH];
Arrays.fill( mapped, false );
mobs = new HashSet<Mob>();
heaps = new SparseArray<Heap>();
blobs = new HashMap<Class<? extends Blob>,Blob>();
plants = new SparseArray<Plant>();
if (!Dungeon.bossLevel()) {
addItemToSpawn( Generator.random( Generator.Category.FOOD ) );
if (Dungeon.posNeeded()) {
addItemToSpawn( new PotionOfStrength() );
Dungeon.potionOfStrength++;
}
if (Dungeon.soeNeeded()) {
addItemToSpawn( new ScrollOfUpgrade() );
Dungeon.scrollsOfUpgrade++;
}
if (Dungeon.asNeeded()) {
addItemToSpawn( new Stylus() );
Dungeon.arcaneStyli++;
}
if (Dungeon.depth > 1) {
switch (Random.Int( 10 )) {
case 0:
if (!Dungeon.bossLevel( Dungeon.depth + 1 )) {
feeling = Feeling.CHASM;
}
break;
case 1:
feeling = Feeling.WATER;
break;
case 2:
feeling = Feeling.GRASS;
break;
}
}
}
boolean pitNeeded = Dungeon.depth > 1 && weakFloorCreated;
do {
Arrays.fill( map, feeling == Feeling.CHASM ? Terrain.CHASM : Terrain.WALL );
pitRoomNeeded = pitNeeded;
weakFloorCreated = false;
} while (!build());
decorate();
buildFlagMaps();
cleanWalls();
createMobs();
createItems();
}
public void reset() {
for (Mob mob : mobs.toArray( new Mob[0] )) {
if (!mob.reset()) {
mobs.remove( mob );
}
}
createMobs();
}
@Override
public void restoreFromBundle( Bundle bundle ) {
mobs = new HashSet<Mob>();
heaps = new SparseArray<Heap>();
blobs = new HashMap<Class<? extends Blob>, Blob>();
plants = new SparseArray<Plant>();
map = bundle.getIntArray( MAP );
visited = bundle.getBooleanArray( VISITED );
mapped = bundle.getBooleanArray( MAPPED );
entrance = bundle.getInt( ENTRANCE );
exit = bundle.getInt( EXIT );
weakFloorCreated = false;
adjustMapSize();
Collection<Bundlable> collection = bundle.getCollection( HEAPS );
for (Bundlable h : collection) {
Heap heap = (Heap)h;
if (resizingNeeded) {
heap.pos = adjustPos( heap.pos );
}
heaps.put( heap.pos, heap );
}
collection = bundle.getCollection( PLANTS );
for (Bundlable p : collection) {
Plant plant = (Plant)p;
if (resizingNeeded) {
plant.pos = adjustPos( plant.pos );
}
plants.put( plant.pos, plant );
}
collection = bundle.getCollection( MOBS );
for (Bundlable m : collection) {
Mob mob = (Mob)m;
if (mob != null) {
if (resizingNeeded) {
mob.pos = adjustPos( mob.pos );
}
mobs.add( mob );
}
}
collection = bundle.getCollection( BLOBS );
for (Bundlable b : collection) {
Blob blob = (Blob)b;
blobs.put( blob.getClass(), blob );
}
buildFlagMaps();
cleanWalls();
}
@Override
public void storeInBundle( Bundle bundle ) {
bundle.put( MAP, map );
bundle.put( VISITED, visited );
bundle.put( MAPPED, mapped );
bundle.put( ENTRANCE, entrance );
bundle.put( EXIT, exit );
bundle.put( HEAPS, heaps.values() );
bundle.put( PLANTS, plants.values() );
bundle.put( MOBS, mobs );
bundle.put( BLOBS, blobs.values() );
}
public int tunnelTile() {
return feeling == Feeling.CHASM ? Terrain.EMPTY_SP : Terrain.EMPTY;
}
private void adjustMapSize() {
// For levels from older saves
if (map.length < LENGTH) {
resizingNeeded = true;
loadedMapSize = (int)Math.sqrt( map.length );
int[] map = new int[LENGTH];
Arrays.fill( map, Terrain.WALL );
boolean[] visited = new boolean[LENGTH];
Arrays.fill( visited, false );
boolean[] mapped = new boolean[LENGTH];
Arrays.fill( mapped, false );
for (int i=0; i < loadedMapSize; i++) {
System.arraycopy( this.map, i * loadedMapSize, map, i * WIDTH, loadedMapSize );
System.arraycopy( this.visited, i * loadedMapSize, visited, i * WIDTH, loadedMapSize );
System.arraycopy( this.mapped, i * loadedMapSize, mapped, i * WIDTH, loadedMapSize );
}
this.map = map;
this.visited = visited;
this.mapped = mapped;
entrance = adjustPos( entrance );
exit = adjustPos( exit );
} else {
resizingNeeded = false;
}
}
public int adjustPos( int pos ) {
return (pos / loadedMapSize) * WIDTH + (pos % loadedMapSize);
}
public String tilesTex() {
return null;
}
public String waterTex() {
return null;
}
abstract protected boolean build();
abstract protected void decorate();
abstract protected void createMobs();
abstract protected void createItems();
public void addVisuals( Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (pit[i]) {
scene.add( new WindParticle.Wind( i ) );
if (i >= WIDTH && water[i-WIDTH]) {
scene.add( new FlowParticle.Flow( i - WIDTH ) );
}
}
}
}
public int nMobs() {
return 0;
}
public Actor respawner() {
return new Actor() {
@Override
protected boolean act() {
if (mobs.size() < nMobs()) {
Mob mob = Bestiary.mutable( Dungeon.depth );
mob.state = Mob.State.WANDERING;
mob.pos = randomRespawnCell();
if (Dungeon.hero.isAlive() && mob.pos != -1) {
GameScene.add( mob );
if (Statistics.amuletObtained) {
mob.beckon( Dungeon.hero.pos );
}
}
}
spend( Dungeon.nightMode || Statistics.amuletObtained ? TIME_TO_RESPAWN / 2 : TIME_TO_RESPAWN );
return true;
}
};
}
public int randomRespawnCell() {
int cell;
do {
cell = Random.Int( LENGTH );
} while (!passable[cell] || Dungeon.visible[cell] || Actor.findChar( cell ) != null);
return cell;
}
public int randomDestination() {
int cell;
do {
cell = Random.Int( LENGTH );
} while (!passable[cell]);
return cell;
}
public void addItemToSpawn( Item item ) {
if (item != null) {
itemsToSpawn.add( item );
}
}
public Item itemToSpanAsPrize() {
if (Random.Int( itemsToSpawn.size() + 1 ) > 0) {
Item item = Random.element( itemsToSpawn );
itemsToSpawn.remove( item );
return item;
} else {
return null;
}
}
private void buildFlagMaps() {
for (int i=0; i < LENGTH; i++) {
int flags = Terrain.flags[map[i]];
passable[i] = (flags & Terrain.PASSABLE) != 0;
losBlocking[i] = (flags & Terrain.LOS_BLOCKING) != 0;
flamable[i] = (flags & Terrain.FLAMABLE) != 0;
secret[i] = (flags & Terrain.SECRET) != 0;
solid[i] = (flags & Terrain.SOLID) != 0;
avoid[i] = (flags & Terrain.AVOID) != 0;
water[i] = (flags & Terrain.LIQUID) != 0;
pit[i] = (flags & Terrain.PIT) != 0;
}
int lastRow = LENGTH - WIDTH;
for (int i=0; i < WIDTH; i++) {
passable[i] = avoid[i] = false;
passable[lastRow + i] = avoid[lastRow + i] = false;
}
for (int i=WIDTH; i < lastRow; i += WIDTH) {
passable[i] = avoid[i] = false;
passable[i + WIDTH-1] = avoid[i + WIDTH-1] = false;
}
for (int i=WIDTH; i < LENGTH - WIDTH; i++) {
if (water[i]) {
int t = Terrain.WATER_TILES;
for (int j=0; j < NEIGHBOURS4.length; j++) {
if ((Terrain.flags[map[i + NEIGHBOURS4[j]]] & Terrain.UNSTITCHABLE) != 0) {
t += 1 << j;
}
}
map[i] = t;
}
if (pit[i]) {
if (!pit[i - WIDTH]) {
int c = map[i - WIDTH];
if (c == Terrain.EMPTY_SP || c == Terrain.STATUE_SP) {
map[i] = Terrain.CHASM_FLOOR_SP;
} else if (water[i - WIDTH]) {
map[i] = Terrain.CHASM_WATER;
} else if ((Terrain.flags[c] & Terrain.UNSTITCHABLE) != 0) {
map[i] = Terrain.CHASM_WALL;
} else {
map[i] = Terrain.CHASM_FLOOR;
}
}
}
}
}
private void cleanWalls() {
for (int i=0; i < LENGTH; i++) {
boolean d = false;
for (int j=0; j < NEIGHBOURS9.length; j++) {
int n = i + NEIGHBOURS9[j];
if (n >= 0 && n < LENGTH && map[n] != Terrain.WALL && map[n] != Terrain.WALL_DECO) {
d = true;
break;
}
}
if (d) {
d = false;
for (int j=0; j < NEIGHBOURS9.length; j++) {
int n = i + NEIGHBOURS9[j];
if (n >= 0 && n < LENGTH && !pit[n]) {
d = true;
break;
}
}
}
discoverable[i] = d;
}
}
public static void set( int cell, int terrain ) {
Painter.set( Dungeon.level, cell, terrain );
int flags = Terrain.flags[terrain];
passable[cell] = (flags & Terrain.PASSABLE) != 0;
losBlocking[cell] = (flags & Terrain.LOS_BLOCKING) != 0;
flamable[cell] = (flags & Terrain.FLAMABLE) != 0;
secret[cell] = (flags & Terrain.SECRET) != 0;
solid[cell] = (flags & Terrain.SOLID) != 0;
avoid[cell] = (flags & Terrain.AVOID) != 0;
pit[cell] = (flags & Terrain.PIT) != 0;
water[cell] = terrain == Terrain.WATER || terrain >= Terrain.WATER_TILES;
}
public Heap drop( Item item, int cell ) {
if ((map[cell] == Terrain.ALCHEMY) && !(item instanceof Plant.Seed)) {
int n;
do {
n = cell + NEIGHBOURS8[Random.Int( 8 )];
} while (map[n] != Terrain.EMPTY_SP);
cell = n;
}
Heap heap = heaps.get( cell );
if (heap == null) {
heap = new Heap();
heap.pos = cell;
if (map[cell] == Terrain.CHASM || (Dungeon.level != null && pit[cell])) {
GameScene.discard( heap );
} else {
heaps.put( cell, heap );
GameScene.add( heap );
}
} else if (heap.type == Heap.Type.LOCKED_CHEST || heap.type == Heap.Type.CRYSTAL_CHEST) {
int n;
do {
n = cell + Level.NEIGHBOURS8[Random.Int( 8 )];
} while (!Level.passable[n] && !Level.avoid[n]);
return drop( item, n );
}
heap.drop( item );
if (Dungeon.level != null) {
press( cell, null );
}
return heap;
}
public Plant plant( Plant.Seed seed, int pos ) {
Plant plant = plants.get( pos );
if (plant != null) {
plant.wither();
}
plant = seed.couch( pos );
plants.put( pos, plant );
GameScene.add( plant );
return plant;
}
public void uproot( int pos ) {
plants.delete( pos );
}
public int pitCell() {
return randomRespawnCell();
}
public void press( int cell, Char ch ) {
if (pit[cell] && ch == Dungeon.hero) {
Chasm.heroFall( cell );
return;
}
boolean trap = false;
switch (map[cell]) {
case Terrain.SECRET_TOXIC_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.TOXIC_TRAP:
trap = true;
ToxicTrap.trigger( cell, ch );
break;
case Terrain.SECRET_FIRE_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.FIRE_TRAP:
trap = true;
FireTrap.trigger( cell, ch );
break;
case Terrain.SECRET_PARALYTIC_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.PARALYTIC_TRAP:
trap = true;
ParalyticTrap.trigger( cell, ch );
break;
case Terrain.SECRET_POISON_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.POISON_TRAP:
trap = true;
PoisonTrap.trigger( cell, ch );
break;
case Terrain.SECRET_ALARM_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.ALARM_TRAP:
trap = true;
AlarmTrap.trigger( cell, ch );
break;
case Terrain.SECRET_LIGHTNING_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.LIGHTNING_TRAP:
trap = true;
LightningTrap.trigger( cell, ch );
break;
case Terrain.SECRET_GRIPPING_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.GRIPPING_TRAP:
trap = true;
GrippingTrap.trigger( cell, ch );
break;
case Terrain.SECRET_SUMMONING_TRAP:
GLog.i( TXT_HIDDEN_PLATE_CLICKS );
case Terrain.SUMMONING_TRAP:
trap = true;
SummoningTrap.trigger( cell, ch );
break;
case Terrain.HIGH_GRASS:
HighGrass.trample( this, cell, ch );
break;
case Terrain.WELL:
WellWater.affectCell( cell );
break;
case Terrain.ALCHEMY:
if (ch == null) {
Alchemy.transmute( cell );
}
break;
case Terrain.DOOR:
Door.enter( cell );
break;
}
if (trap) {
Sample.INSTANCE.play( Assets.SND_TRAP );
if (ch == Dungeon.hero) {
Dungeon.hero.interrupt();
}
set( cell, Terrain.INACTIVE_TRAP );
GameScene.updateMap( cell );
}
Plant plant = plants.get( cell );
if (plant != null) {
plant.activate( ch );
}
}
public void mobPress( Mob mob ) {
int cell = mob.pos;
if (pit[cell] && !mob.flying) {
Chasm.mobFall( mob );
return;
}
boolean trap = true;
switch (map[cell]) {
case Terrain.TOXIC_TRAP:
ToxicTrap.trigger( cell, mob );
break;
case Terrain.FIRE_TRAP:
FireTrap.trigger( cell, mob );
break;
case Terrain.PARALYTIC_TRAP:
ParalyticTrap.trigger( cell, mob );
break;
case Terrain.POISON_TRAP:
PoisonTrap.trigger( cell, mob );
break;
case Terrain.ALARM_TRAP:
AlarmTrap.trigger( cell, mob );
break;
case Terrain.LIGHTNING_TRAP:
LightningTrap.trigger( cell, mob );
break;
case Terrain.GRIPPING_TRAP:
GrippingTrap.trigger( cell, mob );
break;
case Terrain.SUMMONING_TRAP:
SummoningTrap.trigger( cell, mob );
break;
case Terrain.DOOR:
Door.enter( cell );
default:
trap = false;
}
if (trap) {
if (Dungeon.visible[cell]) {
Sample.INSTANCE.play( Assets.SND_TRAP );
}
set( cell, Terrain.INACTIVE_TRAP );
GameScene.updateMap( cell );
}
Plant plant = plants.get( cell );
if (plant != null) {
plant.activate( mob );
}
}
public boolean[] updateFieldOfView( Char c ) {
int cx = c.pos % WIDTH;
int cy = c.pos / WIDTH;
boolean sighted = c.buff( Blindness.class ) == null && c.buff( Shadows.class ) == null && c.isAlive();
if (sighted) {
ShadowCaster.castShadow( cx, cy, fieldOfView, c.viewDistance );
} else {
Arrays.fill( fieldOfView, false );
}
int sense = 1;
if (c.isAlive()) {
for (Buff b : c.buffs( MindVision.class )) {
sense = Math.max( ((MindVision)b).distance, sense );
}
}
if ((sighted && sense > 1) || !sighted) {
int ax = Math.max( 0, cx - sense );
int bx = Math.min( cx + sense, WIDTH - 1 );
int ay = Math.max( 0, cy - sense );
int by = Math.min( cy + sense, HEIGHT - 1 );
int len = bx - ax + 1;
int pos = ax + ay * WIDTH;
for (int y = ay; y <= by; y++, pos+=WIDTH) {
Arrays.fill( fieldOfView, pos, pos + len, true );
}
for (int i=0; i < LENGTH; i++) {
fieldOfView[i] &= discoverable[i];
}
}
if (c.isAlive()) {
if (c.buff( MindVision.class ) != null) {
for (Mob mob : mobs) {
int p = mob.pos;
fieldOfView[p] = true;
fieldOfView[p + 1] = true;
fieldOfView[p - 1] = true;
fieldOfView[p + WIDTH + 1] = true;
fieldOfView[p + WIDTH - 1] = true;
fieldOfView[p - WIDTH + 1] = true;
fieldOfView[p - WIDTH - 1] = true;
fieldOfView[p + WIDTH] = true;
fieldOfView[p - WIDTH] = true;
}
} else if (c == Dungeon.hero && ((Hero)c).heroClass == HeroClass.HUNTRESS) {
for (Mob mob : mobs) {
int p = mob.pos;
if (distance( c.pos, p) == 2) {
fieldOfView[p] = true;
fieldOfView[p + 1] = true;
fieldOfView[p - 1] = true;
fieldOfView[p + WIDTH + 1] = true;
fieldOfView[p + WIDTH - 1] = true;
fieldOfView[p - WIDTH + 1] = true;
fieldOfView[p - WIDTH - 1] = true;
fieldOfView[p + WIDTH] = true;
fieldOfView[p - WIDTH] = true;
}
}
}
if (c.buff( Awareness.class ) != null) {
for (Heap heap : heaps.values()) {
int p = heap.pos;
fieldOfView[p] = true;
fieldOfView[p + 1] = true;
fieldOfView[p - 1] = true;
fieldOfView[p + WIDTH + 1] = true;
fieldOfView[p + WIDTH - 1] = true;
fieldOfView[p - WIDTH + 1] = true;
fieldOfView[p - WIDTH - 1] = true;
fieldOfView[p + WIDTH] = true;
fieldOfView[p - WIDTH] = true;
}
}
}
return fieldOfView;
}
public static int distance( int a, int b ) {
int ax = a % WIDTH;
int ay = a / WIDTH;
int bx = b % WIDTH;
int by = b / WIDTH;
return Math.max( Math.abs( ax - bx ), Math.abs( ay - by ) );
}
public static boolean adjacent( int a, int b ) {
int diff = Math.abs( a - b );
return diff == 1 || diff == WIDTH || diff == WIDTH + 1 || diff == WIDTH - 1;
}
public String tileName( int tile ) {
if (tile >= Terrain.WATER_TILES) {
return tileName( Terrain.WATER );
}
if (tile != Terrain.CHASM && (Terrain.flags[tile] & Terrain.PIT) != 0) {
return tileName( Terrain.CHASM );
}
switch (tile) {
case Terrain.CHASM:
return "Chasm";
case Terrain.EMPTY:
case Terrain.EMPTY_SP:
case Terrain.EMPTY_DECO:
case Terrain.SECRET_TOXIC_TRAP:
case Terrain.SECRET_FIRE_TRAP:
case Terrain.SECRET_PARALYTIC_TRAP:
case Terrain.SECRET_POISON_TRAP:
case Terrain.SECRET_ALARM_TRAP:
case Terrain.SECRET_LIGHTNING_TRAP:
return "Floor";
case Terrain.GRASS:
return "Grass";
case Terrain.WATER:
return "Water";
case Terrain.WALL:
case Terrain.WALL_DECO:
case Terrain.SECRET_DOOR:
return "Wall";
case Terrain.DOOR:
return "Closed door";
case Terrain.OPEN_DOOR:
return "Open door";
case Terrain.ENTRANCE:
return "Depth entrance";
case Terrain.EXIT:
return "Depth exit";
case Terrain.EMBERS:
return "Embers";
case Terrain.LOCKED_DOOR:
return "Locked door";
case Terrain.PEDESTAL:
return "Pedestal";
case Terrain.BARRICADE:
return "Barricade";
case Terrain.HIGH_GRASS:
return "High grass";
case Terrain.LOCKED_EXIT:
return "Locked depth exit";
case Terrain.UNLOCKED_EXIT:
return "Unlocked depth exit";
case Terrain.SIGN:
return "Sign";
case Terrain.WELL:
return "Well";
case Terrain.EMPTY_WELL:
return "Empty well";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "Statue";
case Terrain.TOXIC_TRAP:
return "Toxic gas trap";
case Terrain.FIRE_TRAP:
return "Fire trap";
case Terrain.PARALYTIC_TRAP:
return "Paralytic gas trap";
case Terrain.POISON_TRAP:
return "Poison dart trap";
case Terrain.ALARM_TRAP:
return "Alarm trap";
case Terrain.LIGHTNING_TRAP:
return "Lightning trap";
case Terrain.GRIPPING_TRAP:
return "Gripping trap";
case Terrain.SUMMONING_TRAP:
return "Summoning trap";
case Terrain.INACTIVE_TRAP:
return "Triggered trap";
case Terrain.BOOKSHELF:
return "Bookshelf";
case Terrain.ALCHEMY:
return "Alchemy pot";
default:
return "???";
}
}
public String tileDesc( int tile ) {
switch (tile) {
case Terrain.CHASM:
return "You can't see the bottom.";
case Terrain.WATER:
return "In case of burning step into the water to extinguish the fire.";
case Terrain.ENTRANCE:
return "Stairs lead up to the upper depth.";
case Terrain.EXIT:
case Terrain.UNLOCKED_EXIT:
return "Stairs lead down to the lower depth.";
case Terrain.EMBERS:
return "Embers cover the floor.";
case Terrain.HIGH_GRASS:
return "Dense vegetation blocks the view.";
case Terrain.LOCKED_DOOR:
return "This door is locked, you need a matching key to unlock it.";
case Terrain.LOCKED_EXIT:
return "Heavy bars block the stairs leading down.";
case Terrain.BARRICADE:
return "The wooden barricade is firmly set but has dried over the years. Might it burn?";
case Terrain.SIGN:
return "You can't read the text from here.";
case Terrain.TOXIC_TRAP:
case Terrain.FIRE_TRAP:
case Terrain.PARALYTIC_TRAP:
case Terrain.POISON_TRAP:
case Terrain.ALARM_TRAP:
case Terrain.LIGHTNING_TRAP:
case Terrain.GRIPPING_TRAP:
case Terrain.SUMMONING_TRAP:
return "Stepping onto a hidden pressure plate will activate the trap.";
case Terrain.INACTIVE_TRAP:
return "The trap has been triggered before and it's not dangerous anymore.";
case Terrain.STATUE:
case Terrain.STATUE_SP:
return "Someone wanted to adorn this place, but failed, obviously.";
case Terrain.ALCHEMY:
return "Drop some seeds here to cook a potion.";
case Terrain.EMPTY_WELL:
return "The well has run dry.";
default:
if (tile >= Terrain.WATER_TILES) {
return tileDesc( Terrain.WATER );
}
if ((Terrain.flags[tile] & Terrain.PIT) != 0) {
return tileDesc( Terrain.CHASM );
}
return "";
}
}
}
@@ -0,0 +1,85 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.utils.Random;
public class Patch {
private static boolean[] cur = new boolean[Level.LENGTH];
private static boolean[] off = new boolean[Level.LENGTH];
public static boolean[] generate( float seed, int nGen ) {
int w = Level.WIDTH;
int h = Level.HEIGHT;
for (int i=0; i < Level.LENGTH; i++) {
off[i] = Random.Float() < seed;
}
for (int i=0; i < nGen; i++) {
for (int y=1; y < h-1; y++) {
for (int x=1; x < w-1; x++) {
int pos = x + y * w;
int count = 0;
if (off[pos-w-1]) {
count++;
}
if (off[pos-w]) {
count++;
}
if (off[pos-w+1]) {
count++;
}
if (off[pos-1]) {
count++;
}
if (off[pos+1]) {
count++;
}
if (off[pos+w-1]) {
count++;
}
if (off[pos+w]) {
count++;
}
if (off[pos+w+1]) {
count++;
}
if (!off[pos] && count >= 5) {
cur[pos] = true;
} else if (off[pos] && count >= 4) {
cur[pos] = true;
} else {
cur[pos] = false;
}
}
}
boolean[] tmp = cur;
cur = off;
off = tmp;
}
return off;
}
}
@@ -0,0 +1,376 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.List;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Bundle;
import com.watabou.utils.Graph;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class PrisonBossLevel extends RegularLevel {
{
color1 = 0x6a723d;
color2 = 0x88924c;
}
private Room anteroom;
private int arenaDoor;
private boolean enteredArena = false;
private boolean keyDropped = false;
@Override
public String tilesTex() {
return Assets.TILES_PRISON;
}
@Override
public String waterTex() {
return Assets.WATER_PRISON;
}
private static final String ARENA = "arena";
private static final String DOOR = "door";
private static final String ENTERED = "entered";
private static final String DROPPED = "droppped";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( ARENA, roomExit );
bundle.put( DOOR, arenaDoor );
bundle.put( ENTERED, enteredArena );
bundle.put( DROPPED, keyDropped );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
roomExit = (Room)bundle.get( ARENA );
arenaDoor = bundle.getInt( DOOR );
enteredArena = bundle.getBoolean( ENTERED );
keyDropped = bundle.getBoolean( DROPPED );
}
@Override
protected boolean build() {
initRooms();
int distance;
int retry = 0;
do {
if (retry++ > 10) {
return false;
}
int innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomEntrance = Random.element( rooms );
} while (roomEntrance.width() < 4 || roomEntrance.height() < 4);
innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomExit = Random.element( rooms );
} while (
roomExit == roomEntrance ||
roomExit.width() < 7 ||
roomExit.height() < 7 ||
roomExit.top == 0);
Graph.buildDistanceMap( rooms, roomExit );
distance = Graph.buildPath( rooms, roomEntrance, roomExit ).size();
} while (distance < 3);
roomEntrance.type = Type.ENTRANCE;
roomExit.type = Type.BOSS_EXIT;
List<Room> path = Graph.buildPath( rooms, roomEntrance, roomExit );
Graph.setPrice( path, roomEntrance.distance );
Graph.buildDistanceMap( rooms, roomExit );
path = Graph.buildPath( rooms, roomEntrance, roomExit );
anteroom = path.get( path.size() - 2 );
anteroom.type = Type.STANDARD;
Room room = roomEntrance;
for (Room next : path) {
room.connect( next );
room = next;
}
for (Room r : rooms) {
if (r.type == Type.NULL && r.connected.size() > 0) {
r.type = Type.PASSAGE;
}
}
paint();
Room r = (Room)roomExit.connected.keySet().toArray()[0];
if (roomExit.connected.get( r ).y == roomExit.top) {
return false;
}
paintWater();
paintGrass();
placeTraps();
return true;
}
protected boolean[] water() {
return Patch.generate( 0.45f, 5 );
}
protected boolean[] grass() {
return Patch.generate( 0.30f, 4 );
}
protected void paintDoors( Room r ) {
for (Room n : r.connected.keySet()) {
if (r.type == Type.NULL) {
continue;
}
Point door = r.connected.get( n );
if (r.type == Room.Type.PASSAGE && n.type == Room.Type.PASSAGE) {
Painter.set( this, door, Terrain.EMPTY );
} else {
Painter.set( this, door, Terrain.DOOR );
}
}
}
@Override
protected void placeTraps() {
int nTraps = nTraps();
for (int i=0; i < nTraps; i++) {
int trapPos = Random.Int( LENGTH );
if (map[trapPos] == Terrain.EMPTY) {
map[trapPos] = Terrain.POISON_TRAP;
}
}
}
@Override
protected void decorate() {
for (int i=WIDTH + 1; i < LENGTH - WIDTH - 1; i++) {
if (map[i] == Terrain.EMPTY) {
float c = 0.15f;
if (map[i + 1] == Terrain.WALL && map[i + WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i - 1] == Terrain.WALL && map[i + WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i + 1] == Terrain.WALL && map[i - WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i - 1] == Terrain.WALL && map[i - WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (Random.Float() < c) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
for (int i=0; i < WIDTH; i++) {
if (map[i] == Terrain.WALL &&
(map[i + WIDTH] == Terrain.EMPTY || map[i + WIDTH] == Terrain.EMPTY_SP) &&
Random.Int( 4 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
for (int i=WIDTH; i < LENGTH - WIDTH; i++) {
if (map[i] == Terrain.WALL &&
map[i - WIDTH] == Terrain.WALL &&
(map[i + WIDTH] == Terrain.EMPTY || map[i + WIDTH] == Terrain.EMPTY_SP) &&
Random.Int( 2 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
Point door = roomExit.entrance();
arenaDoor = door.x + door.y * WIDTH;
Painter.set( this, arenaDoor, Terrain.LOCKED_DOOR );
Painter.fill( this,
roomExit.left + 2,
roomExit.top + 2,
roomExit.width() - 3,
roomExit.height() - 3,
Terrain.INACTIVE_TRAP );
}
@Override
protected void createMobs() {
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
int keyPos = anteroom.random();
while (!passable[keyPos]) {
keyPos = anteroom.random();
}
drop( new IronKey( Dungeon.depth ), keyPos ).type = Heap.Type.CHEST;
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos = roomEntrance.random();
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
@Override
public void press( int cell, Char ch ) {
super.press( cell, ch );
if (ch == Dungeon.hero && !enteredArena && roomExit.inside( cell )) {
enteredArena = true;
int pos;
do {
pos = roomExit.random();
} while (pos == cell || Actor.findChar( pos ) != null);
Mob boss = Bestiary.mob( Dungeon.depth );
boss.state = Mob.State.HUNTING;
boss.pos = pos;
GameScene.add( boss );
boss.notice();
mobPress( boss );
set( arenaDoor, Terrain.LOCKED_DOOR );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
}
}
@Override
public Heap drop( Item item, int cell ) {
if (!keyDropped && item instanceof SkeletonKey) {
keyDropped = true;
set( arenaDoor, Terrain.DOOR );
GameScene.updateMap( arenaDoor );
Dungeon.observe();
}
return super.drop( item, cell );
}
@Override
public int randomRespawnCell() {
return -1;
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Dark cold water.";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.EMPTY_DECO:
return "There are old blood stains on the floor.";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
PrisonLevel.addVisuals( this, scene );
}
}
@@ -0,0 +1,189 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Scene;
import com.watabou.noosa.particles.Emitter;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Wandmaker;
import com.shatteredpixel.shatteredpixeldungeon.effects.Halo;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class PrisonLevel extends RegularLevel {
{
color1 = 0x6a723d;
color2 = 0x88924c;
}
@Override
public String tilesTex() {
return Assets.TILES_PRISON;
}
@Override
public String waterTex() {
return Assets.WATER_PRISON;
}
protected boolean[] water() {
return Patch.generate( feeling == Feeling.WATER ? 0.65f : 0.45f, 4 );
}
protected boolean[] grass() {
return Patch.generate( feeling == Feeling.GRASS ? 0.60f : 0.40f, 3 );
}
@Override
protected void assignRoomType() {
super.assignRoomType();
for (Room r : rooms) {
if (r.type == Type.TUNNEL) {
r.type = Type.PASSAGE;
}
}
}
@Override
protected void createMobs() {
super.createMobs();
Wandmaker.Quest.spawn( this, roomEntrance );
}
@Override
protected void decorate() {
for (int i=WIDTH + 1; i < LENGTH - WIDTH - 1; i++) {
if (map[i] == Terrain.EMPTY) {
float c = 0.05f;
if (map[i + 1] == Terrain.WALL && map[i + WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i - 1] == Terrain.WALL && map[i + WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i + 1] == Terrain.WALL && map[i - WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (map[i - 1] == Terrain.WALL && map[i - WIDTH] == Terrain.WALL) {
c += 0.2f;
}
if (Random.Float() < c) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
for (int i=0; i < WIDTH; i++) {
if (map[i] == Terrain.WALL &&
(map[i + WIDTH] == Terrain.EMPTY || map[i + WIDTH] == Terrain.EMPTY_SP) &&
Random.Int( 6 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
for (int i=WIDTH; i < LENGTH - WIDTH; i++) {
if (map[i] == Terrain.WALL &&
map[i - WIDTH] == Terrain.WALL &&
(map[i + WIDTH] == Terrain.EMPTY || map[i + WIDTH] == Terrain.EMPTY_SP) &&
Random.Int( 3 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Dark cold water.";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.EMPTY_DECO:
return "There are old blood stains on the floor.";
case Terrain.BOOKSHELF:
return "This is probably a vestige of a prison library. Might it burn?";
default:
return super.tileDesc( tile );
}
}
@Override
public void addVisuals( Scene scene ) {
super.addVisuals( scene );
addVisuals( this, scene );
}
public static void addVisuals( Level level, Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (level.map[i] == Terrain.WALL_DECO) {
scene.add( new Torch( i ) );
}
}
}
private static class Torch extends Emitter {
private int pos;
public Torch( int pos ) {
super();
this.pos = pos;
PointF p = DungeonTilemap.tileCenterToWorld( pos );
pos( p.x - 1, p.y + 3, 2, 0 );
pour( FlameParticle.FACTORY, 0.15f );
add( new Halo( 16, 0xFFFFCC, 0.2f ).point( p.x, p.y ) );
}
@Override
public void update() {
if (visible = Dungeon.visible[pos]) {
super.update();
}
}
}
}
@@ -0,0 +1,694 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.*;
import com.watabou.utils.Bundle;
import com.watabou.utils.Graph;
import com.watabou.utils.Random;
import com.watabou.utils.Rect;
public abstract class RegularLevel extends Level {
protected HashSet<Room> rooms;
protected Room roomEntrance;
protected Room roomExit;
protected ArrayList<Room.Type> specials;
public int secretDoors;
@Override
protected boolean build() {
if (!initRooms()) {
return false;
}
int distance;
int retry = 0;
int minDistance = (int)Math.sqrt( rooms.size() );
do {
do {
roomEntrance = Random.element( rooms );
} while (roomEntrance.width() < 4 || roomEntrance.height() < 4);
do {
roomExit = Random.element( rooms );
} while (roomExit == roomEntrance || roomExit.width() < 4 || roomExit.height() < 4);
Graph.buildDistanceMap( rooms, roomExit );
distance = roomEntrance.distance();
if (retry++ > 10) {
return false;
}
} while (distance < minDistance);
roomEntrance.type = Type.ENTRANCE;
roomExit.type = Type.EXIT;
HashSet<Room> connected = new HashSet<Room>();
connected.add( roomEntrance );
Graph.buildDistanceMap( rooms, roomExit );
List<Room> path = Graph.buildPath( rooms, roomEntrance, roomExit );
Room room = roomEntrance;
for (Room next : path) {
room.connect( next );
room = next;
connected.add( room );
}
Graph.setPrice( path, roomEntrance.distance );
Graph.buildDistanceMap( rooms, roomExit );
path = Graph.buildPath( rooms, roomEntrance, roomExit );
room = roomEntrance;
for (Room next : path) {
room.connect( next );
room = next;
connected.add( room );
}
int nConnected = (int)(rooms.size() * Random.Float( 0.5f, 0.7f ));
while (connected.size() < nConnected) {
Room cr = Random.element( connected );
Room or = Random.element( cr.neigbours );
if (!connected.contains( or )) {
cr.connect( or );
connected.add( or );
}
}
if (Dungeon.shopOnLevel()) {
Room shop = null;
for (Room r : roomEntrance.connected.keySet()) {
if (r.connected.size() == 1 && r.width() >= 5 && r.height() >= 5) {
shop = r;
break;
}
}
if (shop == null) {
return false;
} else {
shop.type = Room.Type.SHOP;
}
}
specials = new ArrayList<Room.Type>( Room.SPECIALS );
if (Dungeon.bossLevel( Dungeon.depth + 1 )) {
specials.remove( Room.Type.WEAK_FLOOR );
}
assignRoomType();
paint();
paintWater();
paintGrass();
placeTraps();
return true;
}
protected boolean initRooms() {
rooms = new HashSet<Room>();
split( new Rect( 0, 0, WIDTH - 1, HEIGHT - 1 ) );
if (rooms.size() < 8) {
return false;
}
Room[] ra = rooms.toArray( new Room[0] );
for (int i=0; i < ra.length-1; i++) {
for (int j=i+1; j < ra.length; j++) {
ra[i].addNeigbour( ra[j] );
}
}
return true;
}
protected void assignRoomType() {
int specialRooms = 0;
for (Room r : rooms) {
if (r.type == Type.NULL &&
r.connected.size() == 1) {
if (specials.size() > 0 &&
r.width() > 3 && r.height() > 3 &&
Random.Int( specialRooms * specialRooms + 2 ) == 0) {
if (pitRoomNeeded) {
r.type = Type.PIT;
pitRoomNeeded = false;
specials.remove( Type.ARMORY );
specials.remove( Type.CRYPT );
specials.remove( Type.LABORATORY );
specials.remove( Type.LIBRARY );
specials.remove( Type.STATUE );
specials.remove( Type.TREASURY );
specials.remove( Type.VAULT );
specials.remove( Type.WEAK_FLOOR );
} else if (Dungeon.depth % 5 == 2 && specials.contains( Type.LABORATORY )) {
r.type = Type.LABORATORY;
} else if (Dungeon.depth >= Dungeon.transmutation && specials.contains( Type.MAGIC_WELL )) {
r.type = Type.MAGIC_WELL;
} else {
int n = specials.size();
r.type = specials.get( Math.min( Random.Int( n ), Random.Int( n ) ) );
if (r.type == Type.WEAK_FLOOR) {
weakFloorCreated = true;
}
}
Room.useType( r.type );
specials.remove( r.type );
specialRooms++;
} else if (Random.Int( 2 ) == 0){
HashSet<Room> neigbours = new HashSet<Room>();
for (Room n : r.neigbours) {
if (!r.connected.containsKey( n ) &&
!Room.SPECIALS.contains( n.type ) &&
n.type != Type.PIT) {
neigbours.add( n );
}
}
if (neigbours.size() > 1) {
r.connect( Random.element( neigbours ) );
}
}
}
}
int count = 0;
for (Room r : rooms) {
if (r.type == Type.NULL) {
int connections = r.connected.size();
if (connections == 0) {
} else if (Random.Int( connections * connections ) == 0) {
r.type = Type.STANDARD;
count++;
} else {
r.type = Type.TUNNEL;
}
}
}
while (count < 4) {
Room r = randomRoom( Type.TUNNEL, 1 );
if (r != null) {
r.type = Type.STANDARD;
count++;
}
}
}
protected void paintWater() {
boolean[] lake = water();
for (int i=0; i < LENGTH; i++) {
if (map[i] == Terrain.EMPTY && lake[i]) {
map[i] = Terrain.WATER;
}
}
}
protected void paintGrass() {
boolean[] grass = grass();
if (feeling == Feeling.GRASS) {
for (Room room : rooms) {
if (room.type != Type.NULL && room.type != Type.PASSAGE && room.type != Type.TUNNEL) {
grass[(room.left + 1) + (room.top + 1) * WIDTH] = true;
grass[(room.right - 1) + (room.top + 1) * WIDTH] = true;
grass[(room.left + 1) + (room.bottom - 1) * WIDTH] = true;
grass[(room.right - 1) + (room.bottom - 1) * WIDTH] = true;
}
}
}
for (int i=WIDTH+1; i < LENGTH-WIDTH-1; i++) {
if (map[i] == Terrain.EMPTY && grass[i]) {
int count = 1;
for (int n : NEIGHBOURS8) {
if (grass[i + n]) {
count++;
}
}
map[i] = (Random.Float() < count / 12f) ? Terrain.HIGH_GRASS : Terrain.GRASS;
}
}
}
protected abstract boolean[] water();
protected abstract boolean[] grass();
protected void placeTraps() {
int nTraps = nTraps();
float[] trapChances = trapChances();
for (int i=0; i < nTraps; i++) {
int trapPos = Random.Int( LENGTH );
if (map[trapPos] == Terrain.EMPTY) {
switch (Random.chances( trapChances )) {
case 0:
map[trapPos] = Terrain.SECRET_TOXIC_TRAP;
break;
case 1:
map[trapPos] = Terrain.SECRET_FIRE_TRAP;
break;
case 2:
map[trapPos] = Terrain.SECRET_PARALYTIC_TRAP;
break;
case 3:
map[trapPos] = Terrain.SECRET_POISON_TRAP;
break;
case 4:
map[trapPos] = Terrain.SECRET_ALARM_TRAP;
break;
case 5:
map[trapPos] = Terrain.SECRET_LIGHTNING_TRAP;
break;
case 6:
map[trapPos] = Terrain.SECRET_GRIPPING_TRAP;
break;
case 7:
map[trapPos] = Terrain.SECRET_SUMMONING_TRAP;
break;
}
}
}
}
protected int nTraps() {
return Dungeon.depth <= 1 ? 0 : Random.Int( 1, rooms.size() + Dungeon.depth );
}
protected float[] trapChances() {
float[] chances = { 1, 1, 1, 1, 1, 1, 1, 1 };
return chances;
}
protected int minRoomSize = 7;
protected int maxRoomSize = 9;
protected void split( Rect rect ) {
int w = rect.width();
int h = rect.height();
if (w > maxRoomSize && h < minRoomSize) {
int vw = Random.Int( rect.left + 3, rect.right - 3 );
split( new Rect( rect.left, rect.top, vw, rect.bottom ) );
split( new Rect( vw, rect.top, rect.right, rect.bottom ) );
} else
if (h > maxRoomSize && w < minRoomSize) {
int vh = Random.Int( rect.top + 3, rect.bottom - 3 );
split( new Rect( rect.left, rect.top, rect.right, vh ) );
split( new Rect( rect.left, vh, rect.right, rect.bottom ) );
} else
if ((Math.random() <= (minRoomSize * minRoomSize / rect.square()) && w <= maxRoomSize && h <= maxRoomSize) || w < minRoomSize || h < minRoomSize) {
rooms.add( (Room)new Room().set( rect ) );
} else {
if (Random.Float() < (float)(w - 2) / (w + h - 4)) {
int vw = Random.Int( rect.left + 3, rect.right - 3 );
split( new Rect( rect.left, rect.top, vw, rect.bottom ) );
split( new Rect( vw, rect.top, rect.right, rect.bottom ) );
} else {
int vh = Random.Int( rect.top + 3, rect.bottom - 3 );
split( new Rect( rect.left, rect.top, rect.right, vh ) );
split( new Rect( rect.left, vh, rect.right, rect.bottom ) );
}
}
}
protected void paint() {
for (Room r : rooms) {
if (r.type != Type.NULL) {
placeDoors( r );
r.type.paint( this, r );
} else {
if (feeling == Feeling.CHASM && Random.Int( 2 ) == 0) {
Painter.fill( this, r, Terrain.WALL );
}
}
}
for (Room r : rooms) {
paintDoors( r );
}
}
private void placeDoors( Room r ) {
for (Room n : r.connected.keySet()) {
Room.Door door = r.connected.get( n );
if (door == null) {
Rect i = r.intersect( n );
if (i.width() == 0) {
door = new Room.Door(
i.left,
Random.Int( i.top + 1, i.bottom ) );
} else {
door = new Room.Door(
Random.Int( i.left + 1, i.right ),
i.top);
}
r.connected.put( n, door );
n.connected.put( r, door );
}
}
}
protected void paintDoors( Room r ) {
for (Room n : r.connected.keySet()) {
if (joinRooms( r, n )) {
continue;
}
Room.Door d = r.connected.get( n );
int door = d.x + d.y * WIDTH;
switch (d.type) {
case EMPTY:
map[door] = Terrain.EMPTY;
break;
case TUNNEL:
map[door] = tunnelTile();
break;
case REGULAR:
if (Dungeon.depth <= 1) {
map[door] = Terrain.DOOR;
} else {
boolean secret = (Dungeon.depth < 6 ? Random.Int( 12 - Dungeon.depth ) : Random.Int( 6 )) == 0;
map[door] = secret ? Terrain.SECRET_DOOR : Terrain.DOOR;
if (secret) {
secretDoors++;
}
}
break;
case UNLOCKED:
map[door] = Terrain.DOOR;
break;
case HIDDEN:
map[door] = Terrain.SECRET_DOOR;
break;
case BARRICADE:
map[door] = Random.Int( 3 ) == 0 ? Terrain.BOOKSHELF : Terrain.BARRICADE;
break;
case LOCKED:
map[door] = Terrain.LOCKED_DOOR;
break;
}
}
}
protected boolean joinRooms( Room r, Room n ) {
if (r.type != Room.Type.STANDARD || n.type != Room.Type.STANDARD) {
return false;
}
Rect w = r.intersect( n );
if (w.left == w.right) {
if (w.bottom - w.top < 3) {
return false;
}
if (w.height() == Math.max( r.height(), n.height() )) {
return false;
}
if (r.width() + n.width() > maxRoomSize) {
return false;
}
w.top += 1;
w.bottom -= 0;
w.right++;
Painter.fill( this, w.left, w.top, 1, w.height(), Terrain.EMPTY );
} else {
if (w.right - w.left < 3) {
return false;
}
if (w.width() == Math.max( r.width(), n.width() )) {
return false;
}
if (r.height() + n.height() > maxRoomSize) {
return false;
}
w.left += 1;
w.right -= 0;
w.bottom++;
Painter.fill( this, w.left, w.top, w.width(), 1, Terrain.EMPTY );
}
return true;
}
@Override
public int nMobs() {
return 2 + Dungeon.depth % 5 + Random.Int( 3 );
}
@Override
protected void createMobs() {
int nMobs = nMobs();
for (int i=0; i < nMobs; i++) {
Mob mob = Bestiary.mob( Dungeon.depth );
do {
mob.pos = randomRespawnCell();
} while (mob.pos == -1);
mobs.add( mob );
Actor.occupyCell( mob );
}
}
@Override
public int randomRespawnCell() {
int count = 0;
int cell = -1;
while (true) {
if (++count > 10) {
return -1;
}
Room room = randomRoom( Room.Type.STANDARD, 10 );
if (room == null) {
continue;
}
cell = room.random();
if (!Dungeon.visible[cell] && Actor.findChar( cell ) == null && Level.passable[cell]) {
return cell;
}
}
}
@Override
public int randomDestination() {
int cell = -1;
while (true) {
Room room = Random.element( rooms );
if (room == null) {
continue;
}
cell = room.random();
if (Level.passable[cell]) {
return cell;
}
}
}
@Override
protected void createItems() {
int nItems = 3;
while (Random.Float() < 0.3f) {
nItems++;
}
for (int i=0; i < nItems; i++) {
Heap.Type type = null;
switch (Random.Int( 20 )) {
case 0:
type = Heap.Type.SKELETON;
break;
case 1:
case 2:
case 3:
case 4:
type = Heap.Type.CHEST;
break;
default:
type = Heap.Type.HEAP;
}
drop( Generator.random(), randomDropCell() ).type = type;
}
for (Item item : itemsToSpawn) {
int cell = randomDropCell();
if (item instanceof ScrollOfUpgrade) {
while (map[cell] == Terrain.FIRE_TRAP || map[cell] == Terrain.SECRET_FIRE_TRAP) {
cell = randomDropCell();
}
}
drop( item, cell ).type = Heap.Type.HEAP;
}
Item item = Bones.get();
if (item != null) {
drop( item, randomDropCell() ).type = Heap.Type.SKELETON;
}
}
protected Room randomRoom( Room.Type type, int tries ) {
for (int i=0; i < tries; i++) {
Room room = Random.element( rooms );
if (room.type == type) {
return room;
}
}
return null;
}
public Room room( int pos ) {
for (Room room : rooms) {
if (room.type != Type.NULL && room.inside( pos )) {
return room;
}
}
return null;
}
protected int randomDropCell() {
while (true) {
Room room = randomRoom( Room.Type.STANDARD, 1 );
if (room != null) {
int pos = room.random();
if (passable[pos]) {
return pos;
}
}
}
}
@Override
public int pitCell() {
for (Room room : rooms) {
if (room.type == Type.PIT) {
return room.random();
}
}
return super.pitCell();
}
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( "rooms", rooms );
}
@SuppressWarnings("unchecked")
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
rooms = new HashSet<Room>( (Collection<? extends Room>) bundle.getCollection( "rooms" ) );
for (Room r : rooms) {
if (r.type == Type.WEAK_FLOOR) {
weakFloorCreated = true;
break;
}
}
}
}
@@ -0,0 +1,255 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.*;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
import com.watabou.utils.Graph;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
import com.watabou.utils.Rect;
public class Room extends Rect implements Graph.Node, Bundlable {
public HashSet<Room> neigbours = new HashSet<Room>();
public HashMap<Room, Door> connected = new HashMap<Room, Door>();
public int distance;
public int price = 1;
public static enum Type {
NULL( null ),
STANDARD ( StandardPainter.class ),
ENTRANCE ( EntrancePainter.class ),
EXIT ( ExitPainter.class ),
BOSS_EXIT ( BossExitPainter.class ),
TUNNEL ( TunnelPainter.class ),
PASSAGE ( PassagePainter.class ),
SHOP ( ShopPainter.class ),
BLACKSMITH ( BlacksmithPainter.class ),
TREASURY ( TreasuryPainter.class ),
ARMORY ( ArmoryPainter.class ),
LIBRARY ( LibraryPainter.class ),
LABORATORY ( LaboratoryPainter.class ),
VAULT ( VaultPainter.class ),
TRAPS ( TrapsPainter.class ),
STORAGE ( StoragePainter.class ),
MAGIC_WELL ( MagicWellPainter.class ),
GARDEN ( GardenPainter.class ),
CRYPT ( CryptPainter.class ),
STATUE ( StatuePainter.class ),
POOL ( PoolPainter.class ),
RAT_KING ( RatKingPainter.class ),
WEAK_FLOOR ( WeakFloorPainter.class ),
PIT ( PitPainter.class );
private Method paint;
private Type( Class<? extends Painter> painter ) {
try {
paint = painter.getMethod( "paint", Level.class, Room.class );
} catch (Exception e) {
paint = null;
}
}
public void paint( Level level, Room room ) {
try {
paint.invoke( null, level, room );
} catch (Exception e) {
ShatteredPixelDungeon.reportException(e);
}
}
};
public static final ArrayList<Type> SPECIALS = new ArrayList<Type>( Arrays.asList(
Type.WEAK_FLOOR, Type.MAGIC_WELL, Type.CRYPT, Type.POOL, Type.GARDEN, Type.LIBRARY, Type.ARMORY,
Type.TREASURY, Type.TRAPS, Type.STORAGE, Type.STATUE, Type.LABORATORY, Type.VAULT
) );
public Type type = Type.NULL;
public int random() {
return random( 0 );
}
public int random( int m ) {
int x = Random.Int( left + 1 + m, right - m );
int y = Random.Int( top + 1 + m, bottom - m );
return x + y * Level.WIDTH;
}
public void addNeigbour( Room other ) {
Rect i = intersect( other );
if ((i.width() == 0 && i.height() >= 3) ||
(i.height() == 0 && i.width() >= 3)) {
neigbours.add( other );
other.neigbours.add( this );
}
}
public void connect( Room room ) {
if (!connected.containsKey( room )) {
connected.put( room, null );
room.connected.put( this, null );
}
}
public Door entrance() {
return connected.values().iterator().next();
}
public boolean inside( int p ) {
int x = p % Level.WIDTH;
int y = p / Level.WIDTH;
return x > left && y > top && x < right && y < bottom;
}
public Point center() {
return new Point(
(left + right) / 2 + (((right - left) & 1) == 1 ? Random.Int( 2 ) : 0),
(top + bottom) / 2 + (((bottom - top) & 1) == 1 ? Random.Int( 2 ) : 0) );
}
// **** Graph.Node interface ****
@Override
public int distance() {
return distance;
}
@Override
public void distance( int value ) {
distance = value;
}
@Override
public int price() {
return price;
}
@Override
public void price( int value ) {
price = value;
}
@Override
public Collection<Room> edges() {
return neigbours;
}
@Override
public void storeInBundle( Bundle bundle ) {
bundle.put( "left", left );
bundle.put( "top", top );
bundle.put( "right", right );
bundle.put( "bottom", bottom );
bundle.put( "type", type.toString() );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
left = bundle.getInt( "left" );
top = bundle.getInt( "top" );
right = bundle.getInt( "right" );
bottom = bundle.getInt( "bottom" );
type = Type.valueOf( bundle.getString( "type" ) );
}
public static void shuffleTypes() {
int size = SPECIALS.size();
for (int i=0; i < size - 1; i++) {
int j = Random.Int( i, size );
if (j != i) {
Type t = SPECIALS.get( i );
SPECIALS.set( i, SPECIALS.get( j ) );
SPECIALS.set( j, t );
}
}
}
public static void useType( Type type ) {
if (SPECIALS.remove( type )) {
SPECIALS.add( type );
}
}
private static final String ROOMS = "rooms";
public static void restoreRoomsFromBundle( Bundle bundle ) {
if (bundle.contains( ROOMS )) {
SPECIALS.clear();
for (String type : bundle.getStringArray( ROOMS )) {
SPECIALS.add( Type.valueOf( type ));
}
} else {
shuffleTypes();
}
}
public static void storeRoomsInBundle( Bundle bundle ) {
String[] array = new String[SPECIALS.size()];
for (int i=0; i < array.length; i++) {
array[i] = SPECIALS.get( i ).toString();
}
bundle.put( ROOMS, array );
}
public static class Door extends Point {
public static enum Type {
EMPTY, TUNNEL, REGULAR, UNLOCKED, HIDDEN, BARRICADE, LOCKED
}
public Type type = Type.EMPTY;
public Door( int x, int y ) {
super( x, y );
}
public void set( Type type ) {
if (type.compareTo( this.type ) > 0) {
this.type = type;
}
}
}
}
@@ -0,0 +1,257 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import java.util.ArrayList;
import java.util.List;
import com.watabou.noosa.Scene;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Bundle;
import com.watabou.utils.Graph;
import com.watabou.utils.Random;
public class SewerBossLevel extends RegularLevel {
{
color1 = 0x48763c;
color2 = 0x59994a;
}
private int stairs = 0;
@Override
public String tilesTex() {
return Assets.TILES_SEWERS;
}
@Override
public String waterTex() {
return Assets.WATER_SEWERS;
}
@Override
protected boolean build() {
initRooms();
int distance;
int retry = 0;
int minDistance = (int)Math.sqrt( rooms.size() );
do {
int innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomEntrance = Random.element( rooms );
} while (roomEntrance.width() < 4 || roomEntrance.height() < 4);
innerRetry = 0;
do {
if (innerRetry++ > 10) {
return false;
}
roomExit = Random.element( rooms );
} while (roomExit == roomEntrance || roomExit.width() < 6 || roomExit.height() < 6 || roomExit.top == 0);
Graph.buildDistanceMap( rooms, roomExit );
distance = roomEntrance.distance();
if (retry++ > 10) {
return false;
}
} while (distance < minDistance);
roomEntrance.type = Type.ENTRANCE;
roomExit.type = Type.BOSS_EXIT;
Graph.buildDistanceMap( rooms, roomExit );
List<Room> path = Graph.buildPath( rooms, roomEntrance, roomExit );
Graph.setPrice( path, roomEntrance.distance );
Graph.buildDistanceMap( rooms, roomExit );
path = Graph.buildPath( rooms, roomEntrance, roomExit );
Room room = roomEntrance;
for (Room next : path) {
room.connect( next );
room = next;
}
room = (Room)roomExit.connected.keySet().toArray()[0];
if (roomExit.top == room.bottom) {
return false;
}
for (Room r : rooms) {
if (r.type == Type.NULL && r.connected.size() > 0) {
r.type = Type.TUNNEL;
}
}
ArrayList<Room> candidates = new ArrayList<Room>();
for (Room r : roomExit.neigbours) {
if (!roomExit.connected.containsKey( r ) &&
(roomExit.left == r.right || roomExit.right == r.left || roomExit.bottom == r.top)) {
candidates.add( r );
}
}
if (candidates.size() > 0) {
Room kingsRoom = Random.element( candidates );
kingsRoom.connect( roomExit );
kingsRoom.type = Room.Type.RAT_KING;
}
paint();
paintWater();
paintGrass();
placeTraps();
return true;
}
protected boolean[] water() {
return Patch.generate( 0.5f, 5 );
}
protected boolean[] grass() {
return Patch.generate( 0.40f, 4 );
}
@Override
protected void decorate() {
int start = roomExit.top * WIDTH + roomExit.left + 1;
int end = start + roomExit.width() - 1;
for (int i=start; i < end; i++) {
if (i != exit) {
map[i] = Terrain.WALL_DECO;
map[i + WIDTH] = Terrain.WATER;
} else {
map[i + WIDTH] = Terrain.EMPTY;
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
@Override
public void addVisuals( Scene scene ) {
SewerLevel.addVisuals( this, scene );
}
@Override
protected void createMobs() {
Mob mob = Bestiary.mob( Dungeon.depth );
mob.pos = roomExit.random();
mobs.add( mob );
}
public Actor respawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
int pos;
do {
pos = roomEntrance.random();
} while (pos == entrance || map[pos] == Terrain.SIGN);
drop( item, pos ).type = Heap.Type.SKELETON;
}
}
public void seal() {
if (entrance != 0) {
set( entrance, Terrain.WATER_TILES );
GameScene.updateMap( entrance );
GameScene.ripple( entrance );
stairs = entrance;
entrance = 0;
}
}
public void unseal() {
if (stairs != 0) {
entrance = stairs;
stairs = 0;
set( entrance, Terrain.ENTRANCE );
GameScene.updateMap( entrance );
}
}
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 ) {
super.restoreFromBundle( bundle );
stairs = bundle.getInt( STAIRS );
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Murky water";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc( int tile ) {
switch (tile) {
case Terrain.EMPTY_DECO:
return "Wet yellowish moss covers the floor.";
default:
return super.tileDesc( tile );
}
}
}
@@ -0,0 +1,220 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
import com.watabou.noosa.Game;
import com.watabou.noosa.Scene;
import com.watabou.noosa.particles.Emitter;
import com.watabou.noosa.particles.PixelParticle;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost;
import com.shatteredpixel.shatteredpixeldungeon.items.DewVial;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.ColorMath;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class SewerLevel extends RegularLevel {
{
color1 = 0x48763c;
color2 = 0x59994a;
}
@Override
public String tilesTex() {
return Assets.TILES_SEWERS;
}
@Override
public String waterTex() {
return Assets.WATER_SEWERS;
}
protected boolean[] water() {
return Patch.generate( feeling == Feeling.WATER ? 0.60f : 0.45f, 5 );
}
protected boolean[] grass() {
return Patch.generate( feeling == Feeling.GRASS ? 0.60f : 0.40f, 4 );
}
@Override
protected void decorate() {
for (int i=0; i < WIDTH; i++) {
if (map[i] == Terrain.WALL &&
map[i + WIDTH] == Terrain.WATER &&
Random.Int( 4 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
for (int i=WIDTH; i < LENGTH - WIDTH; i++) {
if (map[i] == Terrain.WALL &&
map[i - WIDTH] == Terrain.WALL &&
map[i + WIDTH] == Terrain.WATER &&
Random.Int( 2 ) == 0) {
map[i] = Terrain.WALL_DECO;
}
}
for (int i=WIDTH + 1; i < LENGTH - WIDTH - 1; i++) {
if (map[i] == Terrain.EMPTY) {
int count =
(map[i + 1] == Terrain.WALL ? 1 : 0) +
(map[i - 1] == Terrain.WALL ? 1 : 0) +
(map[i + WIDTH] == Terrain.WALL ? 1 : 0) +
(map[i - WIDTH] == Terrain.WALL ? 1 : 0);
if (Random.Int( 16 ) < count * count) {
map[i] = Terrain.EMPTY_DECO;
}
}
}
while (true) {
int pos = roomEntrance.random();
if (pos != entrance) {
map[pos] = Terrain.SIGN;
break;
}
}
}
@Override
protected void createMobs() {
super.createMobs();
Ghost.Quest.spawn( this );
}
@Override
protected void createItems() {
if (Dungeon.dewVial && Random.Int( 4 - Dungeon.depth ) == 0) {
addItemToSpawn( new DewVial() );
Dungeon.dewVial = false;
}
super.createItems();
}
@Override
public void addVisuals( Scene scene ) {
super.addVisuals( scene );
addVisuals( this, scene );
}
public static void addVisuals( Level level, Scene scene ) {
for (int i=0; i < LENGTH; i++) {
if (level.map[i] == Terrain.WALL_DECO) {
scene.add( new Sink( i ) );
}
}
}
@Override
public String tileName( int tile ) {
switch (tile) {
case Terrain.WATER:
return "Murky water";
default:
return super.tileName( tile );
}
}
@Override
public String tileDesc(int tile) {
switch (tile) {
case Terrain.EMPTY_DECO:
return "Wet yellowish moss covers the floor.";
case Terrain.BOOKSHELF:
return "The bookshelf is packed with cheap useless books. Might it burn?";
default:
return super.tileDesc( tile );
}
}
private static class Sink extends Emitter {
private int pos;
private float rippleDelay = 0;
private static final Emitter.Factory factory = new Factory() {
@Override
public void emit( Emitter emitter, int index, float x, float y ) {
WaterParticle p = (WaterParticle)emitter.recycle( WaterParticle.class );
p.reset( x, y );
}
};
public Sink( int pos ) {
super();
this.pos = pos;
PointF p = DungeonTilemap.tileCenterToWorld( pos );
pos( p.x - 2, p.y + 1, 4, 0 );
pour( factory, 0.05f );
}
@Override
public void update() {
if (visible = Dungeon.visible[pos]) {
super.update();
if ((rippleDelay -= Game.elapsed) <= 0) {
GameScene.ripple( pos + WIDTH ).y -= DungeonTilemap.SIZE / 2;
rippleDelay = Random.Float( 0.2f, 0.3f );
}
}
}
}
public static final class WaterParticle extends PixelParticle {
public WaterParticle() {
super();
acc.y = 50;
am = 0.5f;
color( ColorMath.random( 0xb6ccc2, 0x3b6653 ) );
size( 2 );
}
public void reset( float x, float y ) {
revive();
this.x = x;
this.y = y;
speed.set( Random.Float( -2, +2 ), 0 );
left = lifespan = 0.5f;
}
}
}
@@ -0,0 +1,167 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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;
public class Terrain {
public static final int CHASM = 0;
public static final int EMPTY = 1;
public static final int GRASS = 2;
public static final int EMPTY_WELL = 3;
public static final int WALL = 4;
public static final int DOOR = 5;
public static final int OPEN_DOOR = 6;
public static final int ENTRANCE = 7;
public static final int EXIT = 8;
public static final int EMBERS = 9;
public static final int LOCKED_DOOR = 10;
public static final int PEDESTAL = 11;
public static final int WALL_DECO = 12;
public static final int BARRICADE = 13;
public static final int EMPTY_SP = 14;
public static final int HIGH_GRASS = 15;
public static final int EMPTY_DECO = 24;
public static final int LOCKED_EXIT = 25;
public static final int UNLOCKED_EXIT = 26;
public static final int SIGN = 29;
public static final int WELL = 34;
public static final int STATUE = 35;
public static final int STATUE_SP = 36;
public static final int BOOKSHELF = 41;
public static final int ALCHEMY = 42;
public static final int CHASM_FLOOR = 43;
public static final int CHASM_FLOOR_SP = 44;
public static final int CHASM_WALL = 45;
public static final int CHASM_WATER = 46;
public static final int SECRET_DOOR = 16;
public static final int TOXIC_TRAP = 17;
public static final int SECRET_TOXIC_TRAP = 18;
public static final int FIRE_TRAP = 19;
public static final int SECRET_FIRE_TRAP = 20;
public static final int PARALYTIC_TRAP = 21;
public static final int SECRET_PARALYTIC_TRAP = 22;
public static final int INACTIVE_TRAP = 23;
public static final int POISON_TRAP = 27;
public static final int SECRET_POISON_TRAP = 28;
public static final int ALARM_TRAP = 30;
public static final int SECRET_ALARM_TRAP = 31;
public static final int LIGHTNING_TRAP = 32;
public static final int SECRET_LIGHTNING_TRAP = 33;
public static final int GRIPPING_TRAP = 37;
public static final int SECRET_GRIPPING_TRAP = 38;
public static final int SUMMONING_TRAP = 39;
public static final int SECRET_SUMMONING_TRAP = 40;
public static final int WATER_TILES = 48;
public static final int WATER = 63;
public static final int PASSABLE = 0x01;
public static final int LOS_BLOCKING = 0x02;
public static final int FLAMABLE = 0x04;
public static final int SECRET = 0x08;
public static final int SOLID = 0x10;
public static final int AVOID = 0x20;
public static final int LIQUID = 0x40;
public static final int PIT = 0x80;
public static final int UNSTITCHABLE = 0x100;
public static final int[] flags = new int[256];
static {
flags[CHASM] = AVOID | PIT | UNSTITCHABLE;
flags[EMPTY] = PASSABLE;
flags[GRASS] = PASSABLE | FLAMABLE;
flags[EMPTY_WELL] = PASSABLE;
flags[WATER] = PASSABLE | LIQUID | UNSTITCHABLE;
flags[WALL] = LOS_BLOCKING | SOLID | UNSTITCHABLE;
flags[DOOR] = PASSABLE | LOS_BLOCKING | FLAMABLE | SOLID | UNSTITCHABLE;
flags[OPEN_DOOR] = PASSABLE | FLAMABLE | UNSTITCHABLE;
flags[ENTRANCE] = PASSABLE;
flags[EXIT] = PASSABLE;
flags[EMBERS] = PASSABLE;
flags[LOCKED_DOOR] = LOS_BLOCKING | SOLID | UNSTITCHABLE;
flags[PEDESTAL] = PASSABLE | UNSTITCHABLE;
flags[WALL_DECO] = flags[WALL];
flags[BARRICADE] = FLAMABLE | SOLID | LOS_BLOCKING;
flags[EMPTY_SP] = flags[EMPTY] | UNSTITCHABLE;
flags[HIGH_GRASS] = PASSABLE | LOS_BLOCKING | FLAMABLE;
flags[EMPTY_DECO] = flags[EMPTY];
flags[LOCKED_EXIT] = SOLID;
flags[UNLOCKED_EXIT]= PASSABLE;
flags[SIGN] = PASSABLE | FLAMABLE;
flags[WELL] = AVOID;
flags[STATUE] = SOLID;
flags[STATUE_SP] = flags[STATUE] | UNSTITCHABLE;
flags[BOOKSHELF] = flags[BARRICADE] | UNSTITCHABLE;
flags[ALCHEMY] = PASSABLE;
flags[CHASM_WALL] = flags[CHASM];
flags[CHASM_FLOOR] = flags[CHASM];
flags[CHASM_FLOOR_SP] = flags[CHASM];
flags[CHASM_WATER] = flags[CHASM];
flags[SECRET_DOOR] = flags[WALL] | SECRET | UNSTITCHABLE;
flags[TOXIC_TRAP] = AVOID;
flags[SECRET_TOXIC_TRAP] = flags[EMPTY] | SECRET;
flags[FIRE_TRAP] = AVOID;
flags[SECRET_FIRE_TRAP] = flags[EMPTY] | SECRET;
flags[PARALYTIC_TRAP] = AVOID;
flags[SECRET_PARALYTIC_TRAP] = flags[EMPTY] | SECRET;
flags[POISON_TRAP] = AVOID;
flags[SECRET_POISON_TRAP] = flags[EMPTY] | SECRET;
flags[ALARM_TRAP] = AVOID;
flags[SECRET_ALARM_TRAP] = flags[EMPTY] | SECRET;
flags[LIGHTNING_TRAP] = AVOID;
flags[SECRET_LIGHTNING_TRAP] = flags[EMPTY] | SECRET;
flags[GRIPPING_TRAP] = AVOID;
flags[SECRET_GRIPPING_TRAP] = flags[EMPTY] | SECRET;
flags[SUMMONING_TRAP] = AVOID;
flags[SECRET_SUMMONING_TRAP] = flags[EMPTY] | SECRET;
flags[INACTIVE_TRAP] = flags[EMPTY];
for (int i=WATER_TILES; i < WATER_TILES + 16; i++) {
flags[i] = flags[WATER];
}
};
public static int discover( int terr ) {
switch (terr) {
case SECRET_DOOR:
return DOOR;
case SECRET_FIRE_TRAP:
return FIRE_TRAP;
case SECRET_PARALYTIC_TRAP:
return PARALYTIC_TRAP;
case SECRET_TOXIC_TRAP:
return TOXIC_TRAP;
case SECRET_POISON_TRAP:
return POISON_TRAP;
case SECRET_ALARM_TRAP:
return ALARM_TRAP;
case SECRET_LIGHTNING_TRAP:
return LIGHTNING_TRAP;
case SECRET_GRIPPING_TRAP:
return GRIPPING_TRAP;
case SECRET_SUMMONING_TRAP:
return SUMMONING_TRAP;
default:
return terr;
}
}
}
@@ -0,0 +1,48 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
public class AlchemyPot {
private static final String TXT_SELECT_SEED = "Select a seed to throw";
private static Hero hero;
private static int pos;
public static void operate( Hero hero, int pos ) {
AlchemyPot.hero = hero;
AlchemyPot.pos = pos;
GameScene.selectItem( itemSelector, WndBag.Mode.SEED, TXT_SELECT_SEED );
}
private static final WndBag.Listener itemSelector = new WndBag.Listener() {
@Override
public void onSelect( Item item ) {
if (item != null) {
item.cast( hero, pos );
}
}
};
}
@@ -0,0 +1,111 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.watabou.noosa.Camera;
import com.watabou.noosa.Game;
import com.watabou.noosa.audio.Sample;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.scenes.InterlevelScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.MobSprite;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.watabou.utils.Random;
public class Chasm {
private static final String TXT_CHASM = "Chasm";
private static final String TXT_YES = "Yes, I know what I'm doing";
private static final String TXT_NO = "No, I changed my mind";
private static final String TXT_JUMP =
"Do you really want to jump into the chasm? You can probably die.";
public static boolean jumpConfirmed = false;
public static void heroJump( final Hero hero ) {
GameScene.show(
new WndOptions( TXT_CHASM, TXT_JUMP, TXT_YES, TXT_NO ) {
@Override
protected void onSelect( int index ) {
if (index == 0) {
jumpConfirmed = true;
hero.resume();
}
};
}
);
}
public static void heroFall( int pos ) {
jumpConfirmed = false;
Sample.INSTANCE.play( Assets.SND_FALLING );
if (Dungeon.hero.isAlive()) {
Dungeon.hero.interrupt();
InterlevelScene.mode = InterlevelScene.Mode.FALL;
if (Dungeon.level instanceof RegularLevel) {
Room room = ((RegularLevel)Dungeon.level).room( pos );
InterlevelScene.fallIntoPit = room != null && room.type == Room.Type.WEAK_FLOOR;
} else {
InterlevelScene.fallIntoPit = false;
}
Game.switchScene( InterlevelScene.class );
} else {
Dungeon.hero.sprite.visible = false;
}
}
public static void heroLand() {
Hero hero = Dungeon.hero;
hero.sprite.burst( hero.sprite.blood(), 10 );
Camera.main.shake( 4, 0.2f );
Buff.prolong( hero, Cripple.class, Cripple.DURATION );
hero.damage( Random.IntRange( hero.HT / 3, hero.HT / 2 ), new Hero.Doom() {
@Override
public void onDeath() {
Badges.validateDeathFromFalling();
Dungeon.fail( Utils.format( ResultDescriptions.FALL, Dungeon.depth ) );
GLog.n( "You fell to death..." );
}
} );
}
public static void mobFall( Mob mob ) {
// Destroy instead of kill to prevent dropping loot
mob.destroy();
((MobSprite)mob.sprite).fall();
}
}
@@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.watabou.noosa.audio.Sample;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
public class Door {
public static void enter( int pos ) {
Level.set( pos, Terrain.OPEN_DOOR );
GameScene.updateMap( pos );
Dungeon.observe();
if (Dungeon.visible[pos]) {
Sample.INSTANCE.play( Assets.SND_OPEN );
}
}
public static void leave( int pos ) {
if (Dungeon.level.heaps.get( pos ) == null) {
Level.set( pos, Terrain.DOOR );
GameScene.updateMap( pos );
Dungeon.observe();
}
}
}
@@ -0,0 +1,72 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barkskin;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfHerbalism.Herbalism;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Random;
public class HighGrass {
public static void trample( Level level, int pos, Char ch ) {
Level.set( pos, Terrain.GRASS );
GameScene.updateMap( pos );
int herbalismLevel = 0;
if (ch != null) {
Herbalism herbalism = ch.buff( Herbalism.class );
if (herbalism != null) {
herbalismLevel = herbalism.level;
}
}
// Seed
if (herbalismLevel >= 0 && Random.Int( 18 ) <= Random.Int( herbalismLevel + 1 )) {
level.drop( Generator.random( Generator.Category.SEED ), pos ).sprite.drop();
}
// Dew
if (herbalismLevel >= 0 && Random.Int( 6 ) <= Random.Int( herbalismLevel + 1 )) {
level.drop( new Dewdrop(), pos ).sprite.drop();
}
int leaves = 4;
// Barkskin
if (ch instanceof Hero && ((Hero)ch).subClass == HeroSubClass.WARDEN) {
Buff.affect( ch, Barkskin.class ).level( ch.HT / 3 );
leaves = 8;
}
CellEmitter.get( pos ).burst( LeafParticle.LEVEL_SPECIFIC, leaves );
Dungeon.observe();
}
}
@@ -0,0 +1,71 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class ArmoryPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Room.Door entrance = room.entrance();
Point statue = null;
if (entrance.x == room.left) {
statue = new Point( room.right-1, Random.Int( 2 ) == 0 ? room.top+1 : room.bottom-1 );
} else if (entrance.x == room.right) {
statue = new Point( room.left+1, Random.Int( 2 ) == 0 ? room.top+1 : room.bottom-1 );
} else if (entrance.y == room.top) {
statue = new Point( Random.Int( 2 ) == 0 ? room.left+1 : room.right-1, room.bottom-1 );
} else if (entrance.y == room.bottom) {
statue = new Point( Random.Int( 2 ) == 0 ? room.left+1 : room.right-1, room.top+1 );
}
if (statue != null) {
set( level, statue, Terrain.STATUE );
}
int n = Random.IntRange( 2, 3 );
for (int i=0; i < n; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != Terrain.EMPTY || level.heaps.get( pos ) != null);
level.drop( prize( level ), pos );
}
entrance.set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
private static Item prize( Level level ) {
return Generator.random( Random.oneOf(
Generator.Category.ARMOR,
Generator.Category.WEAPON
) );
}
}
@@ -0,0 +1,60 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class BlacksmithPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.FIRE_TRAP );
fill( level, room, 2, Terrain.EMPTY_SP );
for (int i=0; i < 2; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != Terrain.EMPTY_SP);
level.drop(
Generator.random( Random.oneOf(
Generator.Category.ARMOR,
Generator.Category.WEAPON
) ), pos );
}
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.UNLOCKED );
drawInside( level, room, door, 1, Terrain.EMPTY );
}
Blacksmith npc = new Blacksmith();
do {
npc.pos = room.random( 1 );
} while (level.heaps.get( npc.pos ) != null);
level.mobs.add( npc );
Actor.occupyCell( npc );
}
}
@@ -0,0 +1,39 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
public class BossExitPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.REGULAR );
}
level.exit = room.top * Level.WIDTH + (room.left + room.right) / 2;
set( level, level.exit, Terrain.LOCKED_EXIT );
}
}
@@ -0,0 +1,80 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap.Type;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
public class CryptPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Point c = room.center();
int cx = c.x;
int cy = c.y;
Room.Door entrance = room.entrance();
entrance.set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
if (entrance.x == room.left) {
set( level, new Point( room.right-1, room.top+1 ), Terrain.STATUE );
set( level, new Point( room.right-1, room.bottom-1 ), Terrain.STATUE );
cx = room.right - 2;
} else if (entrance.x == room.right) {
set( level, new Point( room.left+1, room.top+1 ), Terrain.STATUE );
set( level, new Point( room.left+1, room.bottom-1 ), Terrain.STATUE );
cx = room.left + 2;
} else if (entrance.y == room.top) {
set( level, new Point( room.left+1, room.bottom-1 ), Terrain.STATUE );
set( level, new Point( room.right-1, room.bottom-1 ), Terrain.STATUE );
cy = room.bottom - 2;
} else if (entrance.y == room.bottom) {
set( level, new Point( room.left+1, room.top+1 ), Terrain.STATUE );
set( level, new Point( room.right-1, room.top+1 ), Terrain.STATUE );
cy = room.top + 2;
}
level.drop( prize( level ), cx + cy * Level.WIDTH ).type = Type.TOMB;
}
private static Item prize( Level level ) {
Item prize = Generator.random( Generator.Category.ARMOR );
for (int i=0; i < 3; i++) {
Item another = Generator.random( Generator.Category.ARMOR );
if (another.level > prize.level) {
prize = another;
}
}
return prize;
}
}
@@ -0,0 +1,39 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
public class EntrancePainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.REGULAR );
}
level.entrance = room.random( 1 );
set( level, level.entrance, Terrain.ENTRANCE );
}
}
@@ -0,0 +1,39 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
public class ExitPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.REGULAR );
}
level.exit = room.random( 1 );
set( level, level.exit, Terrain.EXIT );
}
}
@@ -0,0 +1,53 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Foliage;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.plants.Sungrass;
import com.watabou.utils.Random;
public class GardenPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.HIGH_GRASS );
fill( level, room, 2, Terrain.GRASS );
room.entrance().set( Room.Door.Type.REGULAR );
int bushes = Random.Int( 3 ) == 0 ? (Random.Int( 5 ) == 0 ? 2 : 1) : 0;
for (int i=0; i < bushes; i++) {
level.plant( new Sungrass.Seed(), room.random() );
}
Foliage light = (Foliage)level.blobs.get( Foliage.class );
if (light == null) {
light = new Foliage();
}
for (int i=room.top + 1; i < room.bottom; i++) {
for (int j=room.left + 1; j < room.right; j++) {
light.seed( j + Level.WIDTH * i, 1 );
}
}
level.blobs.put( Foliage.class, light );
}
}
@@ -0,0 +1,83 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Alchemy;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class LaboratoryPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY_SP );
Room.Door entrance = room.entrance();
Point pot = null;
if (entrance.x == room.left) {
pot = new Point( room.right-1, Random.Int( 2 ) == 0 ? room.top + 1 : room.bottom - 1 );
} else if (entrance.x == room.right) {
pot = new Point( room.left+1, Random.Int( 2 ) == 0 ? room.top + 1 : room.bottom - 1 );
} else if (entrance.y == room.top) {
pot = new Point( Random.Int( 2 ) == 0 ? room.left + 1 : room.right - 1, room.bottom-1 );
} else if (entrance.y == room.bottom) {
pot = new Point( Random.Int( 2 ) == 0 ? room.left + 1 : room.right - 1, room.top+1 );
}
set( level, pot, Terrain.ALCHEMY );
Alchemy alchemy = new Alchemy();
alchemy.seed( pot.x + Level.WIDTH * pot.y, 1 );
level.blobs.put( Alchemy.class, alchemy );
int n = Random.IntRange( 2, 3 );
for (int i=0; i < n; i++) {
int pos;
do {
pos = room.random();
} while (
level.map[pos] != Terrain.EMPTY_SP ||
level.heaps.get( pos ) != null);
level.drop( prize( level ), pos );
}
entrance.set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize instanceof Potion) {
return prize;
} else if (prize != null) {
level.addItemToSpawn( prize );
}
return Generator.random( Generator.Category.POTION );
}
}
@@ -0,0 +1,90 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class LibraryPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Room.Door entrance = room.entrance();
Point a = null;
Point b = null;
if (entrance.x == room.left) {
a = new Point( room.left+1, entrance.y-1 );
b = new Point( room.left+1, entrance.y+1 );
fill( level, room.right - 1, room.top + 1, 1, room.height() - 1 , Terrain.BOOKSHELF );
} else if (entrance.x == room.right) {
a = new Point( room.right-1, entrance.y-1 );
b = new Point( room.right-1, entrance.y+1 );
fill( level, room.left+1, room.top + 1, 1, room.height() - 1 , Terrain.BOOKSHELF );
} else if (entrance.y == room.top) {
a = new Point( entrance.x+1, room.top+1 );
b = new Point( entrance.x-1, room.top+1 );
fill( level, room.left + 1, room.bottom-1, room.width() - 1, 1 , Terrain.BOOKSHELF );
} else if (entrance.y == room.bottom) {
a = new Point( entrance.x+1, room.bottom-1 );
b = new Point( entrance.x-1, room.bottom-1 );
fill( level, room.left + 1, room.top+1, room.width() - 1, 1 , Terrain.BOOKSHELF );
}
if (a != null && level.map[a.x + a.y * Level.WIDTH] == Terrain.EMPTY) {
set( level, a, Terrain.STATUE );
}
if (b != null && level.map[b.x + b.y * Level.WIDTH] == Terrain.EMPTY) {
set( level, b, Terrain.STATUE );
}
int n = Random.IntRange( 2, 3 );
for (int i=0; i < n; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != Terrain.EMPTY || level.heaps.get( pos ) != null);
level.drop( prize( level), pos );
}
entrance.set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize instanceof Scroll) {
return prize;
} else if (prize != null) {
level.addItemToSpawn( prize );
}
return Generator.random( Generator.Category.SCROLL );
}
}
@@ -0,0 +1,67 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WaterOfAwareness;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WaterOfHealth;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WaterOfTransmutation;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WellWater;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class MagicWellPainter extends Painter {
private static final Class<?>[] WATERS =
{WaterOfAwareness.class, WaterOfHealth.class, WaterOfTransmutation.class};
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Point c = room.center();
set( level, c.x, c.y, Terrain.WELL );
@SuppressWarnings("unchecked")
Class<? extends WellWater> waterClass =
Dungeon.depth >= Dungeon.transmutation ?
WaterOfTransmutation.class :
(Class<? extends WellWater>)Random.element( WATERS );
if (waterClass == WaterOfTransmutation.class) {
Dungeon.transmutation = Integer.MAX_VALUE;
}
WellWater water = (WellWater)level.blobs.get( waterClass );
if (water == null) {
try {
water = waterClass.newInstance();
} catch (Exception e) {
water = null;
}
}
water.seed( c.x + Level.WIDTH * c.y, 1 );
level.blobs.put( waterClass, water );
room.entrance().set( Room.Door.Type.REGULAR );
}
}
@@ -0,0 +1,86 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import java.util.Arrays;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.watabou.utils.Point;
import com.watabou.utils.Rect;
public class Painter {
public static void set( Level level, int cell, int value ) {
level.map[cell] = value;
}
public static void set( Level level, int x, int y, int value ) {
set( level, x + y * Level.WIDTH, value );
}
public static void set( Level level, Point p, int value ) {
set( level, p.x, p.y, value );
}
public static void fill( Level level, int x, int y, int w, int h, int value ) {
int width = Level.WIDTH;
int pos = y * width + x;
for (int i=y; i < y + h; i++, pos += width) {
Arrays.fill( level.map, pos, pos + w, value );
}
}
public static void fill( Level level, Rect rect, int value ) {
fill( level, rect.left, rect.top, rect.width() + 1, rect.height() + 1, value );
}
public static void fill( Level level, Rect rect, int m, int value ) {
fill( level, rect.left + m, rect.top + m, rect.width() + 1 - m*2, rect.height() + 1 - m*2, value );
}
public static void fill( Level level, Rect rect, int l, int t, int r, int b, int value ) {
fill( level, rect.left + l, rect.top + t, rect.width() + 1 - (l + r), rect.height() + 1 - (t + b), value );
}
public static Point drawInside( Level level, Room room, Point from, int n, int value ) {
Point step = new Point();
if (from.x == room.left) {
step.set( +1, 0 );
} else if (from.x == room.right) {
step.set( -1, 0 );
} else if (from.y == room.top) {
step.set( 0, +1 );
} else if (from.y == room.bottom) {
step.set( 0, -1 );
}
Point p = new Point( from ).offset( step );
for (int i=0; i < n; i++) {
if (value != -1) {
set( level, p, value );
}
p.offset( step );
}
return p;
}
}
@@ -0,0 +1,116 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import java.util.ArrayList;
import java.util.Collections;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.watabou.utils.Point;
public class PassagePainter extends Painter {
private static int pasWidth;
private static int pasHeight;
public static void paint( Level level, Room room ) {
pasWidth = room.width() - 2;
pasHeight = room.height() - 2;
int floor = level.tunnelTile();
ArrayList<Integer> joints = new ArrayList<Integer>();
for (Point door : room.connected.values()) {
joints.add( xy2p( room, door ) );
}
Collections.sort( joints );
int nJoints = joints.size();
int perimeter = pasWidth * 2 + pasHeight * 2;
int start = 0;
int maxD = joints.get( 0 ) + perimeter - joints.get( nJoints - 1 );
for (int i=1; i < nJoints; i++) {
int d = joints.get( i ) - joints.get( i - 1 );
if (d > maxD) {
maxD = d;
start = i;
}
}
int end = (start + nJoints - 1) % nJoints;
int p = joints.get( start );
do {
set( level, p2xy( room, p ), floor );
p = (p + 1) % perimeter;
} while (p != joints.get( end ));
set( level, p2xy( room, p ), floor );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.TUNNEL );
}
}
private static int xy2p( Room room, Point xy ) {
if (xy.y == room.top) {
return (xy.x - room.left - 1);
} else if (xy.x == room.right) {
return (xy.y - room.top - 1) + pasWidth;
} else if (xy.y == room.bottom) {
return (room.right - xy.x - 1) + pasWidth + pasHeight;
} else {
if (xy.y == room.top + 1) {
return 0;
} else {
return (room.bottom - xy.y - 1) + pasWidth * 2 + pasHeight;
}
}
}
private static Point p2xy( Room room, int p ) {
if (p < pasWidth) {
return new Point( room.left + 1 + p, room.top + 1);
} else if (p < pasWidth + pasHeight) {
return new Point( room.right - 1, room.top + 1 + (p - pasWidth) );
} else if (p < pasWidth * 2 + pasHeight) {
return new Point( room.right - 1 - (p - (pasWidth + pasHeight)), room.bottom - 1 );
} else {
return new Point( room.left + 1, room.bottom - 1 - (p - (pasWidth * 2 + pasHeight)) );
}
}
}
@@ -0,0 +1,89 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap.Type;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class PitPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Room.Door entrance = room.entrance();
entrance.set( Room.Door.Type.LOCKED );
Point well = null;
if (entrance.x == room.left) {
well = new Point( room.right-1, Random.Int( 2 ) == 0 ? room.top + 1 : room.bottom - 1 );
} else if (entrance.x == room.right) {
well = new Point( room.left+1, Random.Int( 2 ) == 0 ? room.top + 1 : room.bottom - 1 );
} else if (entrance.y == room.top) {
well = new Point( Random.Int( 2 ) == 0 ? room.left + 1 : room.right - 1, room.bottom-1 );
} else if (entrance.y == room.bottom) {
well = new Point( Random.Int( 2 ) == 0 ? room.left + 1 : room.right - 1, room.top+1 );
}
set( level, well, Terrain.EMPTY_WELL );
int remains = room.random();
while (level.map[remains] == Terrain.EMPTY_WELL) {
remains = room.random();
}
level.drop( new IronKey( Dungeon.depth ), remains ).type = Type.SKELETON;
if (Random.Int( 5 ) == 0) {
level.drop( Generator.random( Generator.Category.RING ), remains );
} else {
level.drop( Generator.random( Random.oneOf(
Generator.Category.WEAPON,
Generator.Category.ARMOR
) ), remains );
}
int n = Random.IntRange( 1, 2 );
for (int i=0; i < n; i++) {
level.drop( prize( level ), remains );
}
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize != null) {
return prize;
}
return Generator.random( Random.oneOf(
Generator.Category.POTION,
Generator.Category.SCROLL,
Generator.Category.FOOD,
Generator.Category.GOLD
) );
}
}
@@ -0,0 +1,108 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Piranha;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfInvisibility;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class PoolPainter extends Painter {
private static final int NPIRANHAS = 3;
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.WATER );
Room.Door door = room.entrance();
door.set( Room.Door.Type.REGULAR );
int x = -1;
int y = -1;
if (door.x == room.left) {
x = room.right - 1;
y = room.top + room.height() / 2;
} else if (door.x == room.right) {
x = room.left + 1;
y = room.top + room.height() / 2;
} else if (door.y == room.top) {
x = room.left + room.width() / 2;
y = room.bottom - 1;
} else if (door.y == room.bottom) {
x = room.left + room.width() / 2;
y = room.top + 1;
}
int pos = x + y * Level.WIDTH;
level.drop( prize( level ), pos ).type =
Random.Int( 3 ) == 0 ? Heap.Type.CHEST : Heap.Type.HEAP;
set( level, pos, Terrain.PEDESTAL );
level.addItemToSpawn( new PotionOfInvisibility() );
for (int i=0; i < NPIRANHAS; i++) {
Piranha piranha = new Piranha();
do {
piranha.pos = room.random();
} while (level.map[piranha.pos] != Terrain.WATER|| Actor.findChar( piranha.pos ) != null);
level.mobs.add( piranha );
Actor.occupyCell( piranha );
}
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize != null) {
return prize;
}
prize = Generator.random( Random.oneOf(
Generator.Category.WEAPON,
Generator.Category.ARMOR
) );
for (int i=0; i < 4; i++) {
Item another = Generator.random( Random.oneOf(
Generator.Category.WEAPON,
Generator.Category.ARMOR
) );
if (another.level > prize.level) {
prize = another;
}
}
return prize;
}
}
@@ -0,0 +1,86 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.RatKing;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class RatKingPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY_SP );
Room.Door entrance = room.entrance();
entrance.set( Room.Door.Type.HIDDEN );
int door = entrance.x + entrance.y * Level.WIDTH;
for (int i=room.left + 1; i < room.right; i++) {
addChest( level, (room.top + 1) * Level.WIDTH + i, door );
addChest( level, (room.bottom - 1) * Level.WIDTH + i, door );
}
for (int i=room.top + 2; i < room.bottom - 1; i++) {
addChest( level, i * Level.WIDTH + room.left + 1, door );
addChest( level, i * Level.WIDTH + room.right - 1, door );
}
RatKing king = new RatKing();
king.pos = room.random( 1 );
level.mobs.add( king );
}
private static void addChest( Level level, int pos, int door ) {
if (pos == door - 1 ||
pos == door + 1 ||
pos == door - Level.WIDTH ||
pos == door + Level.WIDTH) {
return;
}
Item prize;
switch (Random.Int( 10 )) {
case 0:
prize = Generator.random( Generator.Category.WEAPON );
if (prize instanceof MissileWeapon) {
prize.quantity( 1 );
} else {
prize.degrade( Random.Int( 3 ) );
}
break;
case 1:
prize = Generator.random( Generator.Category.ARMOR ).degrade( Random.Int( 3 ) );
break;
default:
prize = new Gold( Random.IntRange( 1, 5 ) );
break;
}
level.drop( prize, pos ).type = Heap.Type.CHEST;
}
}
@@ -0,0 +1,214 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import java.util.ArrayList;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.ImpShopkeeper;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper;
import com.shatteredpixel.shatteredpixeldungeon.items.Ankh;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Torch;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.*;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.ScrollHolder;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.SeedPouch;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.WandHolster;
import com.shatteredpixel.shatteredpixeldungeon.items.food.OverpricedRation;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfIdentify;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRemoveCurse;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.*;
import com.shatteredpixel.shatteredpixeldungeon.levels.LastShopLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class ShopPainter extends Painter {
private static int pasWidth;
private static int pasHeight;
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY_SP );
pasWidth = room.width() - 2;
pasHeight = room.height() - 2;
int per = pasWidth * 2 + pasHeight * 2;
Item[] range = range();
int pos = xy2p( room, room.entrance() ) + (per - range.length) / 2;
for (int i=0; i < range.length; i++) {
Point xy = p2xy( room, (pos + per) % per );
int cell = xy.x + xy.y * Level.WIDTH;
if (level.heaps.get( cell ) != null) {
do {
cell = room.random();
} while (level.heaps.get( cell ) != null);
}
level.drop( range[i], cell ).type = Heap.Type.FOR_SALE;
pos++;
}
placeShopkeeper( level, room );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.REGULAR );
}
}
private static Item[] range() {
ArrayList<Item> items = new ArrayList<Item>();
switch (Dungeon.depth) {
case 6:
items.add( (Random.Int( 2 ) == 0 ? new Quarterstaff() : new Spear()).identify() );
items.add( new LeatherArmor().identify() );
items.add( new SeedPouch() );
break;
case 11:
items.add( (Random.Int( 2 ) == 0 ? new Sword() : new Mace()).identify() );
items.add( new MailArmor().identify() );
items.add( new ScrollHolder() );
break;
case 16:
items.add( (Random.Int( 2 ) == 0 ? new Longsword() : new BattleAxe()).identify() );
items.add( new ScaleArmor().identify() );
items.add( new WandHolster() );
break;
case 21:
switch (Random.Int( 3 )) {
case 0:
items.add( new Glaive().identify() );
break;
case 1:
items.add( new WarHammer().identify() );
break;
case 2:
items.add( new PlateArmor().identify() );
break;
}
items.add( new Torch() );
items.add( new Torch() );
break;
}
items.add( new PotionOfHealing() );
for (int i=0; i < 3; i++) {
items.add( Generator.random( Generator.Category.POTION ) );
}
items.add( new ScrollOfIdentify() );
items.add( new ScrollOfRemoveCurse() );
items.add( new ScrollOfMagicMapping() );
items.add( Generator.random( Generator.Category.SCROLL ) );
items.add( new OverpricedRation() );
items.add( new OverpricedRation() );
items.add( new Ankh() );
Item[] range =items.toArray( new Item[0] );
Random.shuffle( range );
return range;
}
private static void placeShopkeeper( Level level, Room room ) {
int pos;
do {
pos = room.random();
} while (level.heaps.get( pos ) != null);
Mob shopkeeper = level instanceof LastShopLevel ? new ImpShopkeeper() : new Shopkeeper();
shopkeeper.pos = pos;
level.mobs.add( shopkeeper );
if (level instanceof LastShopLevel) {
for (int i=0; i < Level.NEIGHBOURS9.length; i++) {
int p = shopkeeper.pos + Level.NEIGHBOURS9[i];
if (level.map[p] == Terrain.EMPTY_SP) {
level.map[p] = Terrain.WATER;
}
}
}
}
private static int xy2p( Room room, Point xy ) {
if (xy.y == room.top) {
return (xy.x - room.left - 1);
} else if (xy.x == room.right) {
return (xy.y - room.top - 1) + pasWidth;
} else if (xy.y == room.bottom) {
return (room.right - xy.x - 1) + pasWidth + pasHeight;
} else {
if (xy.y == room.top + 1) {
return 0;
} else {
return (room.bottom - xy.y - 1) + pasWidth * 2 + pasHeight;
}
}
}
private static Point p2xy( Room room, int p ) {
if (p < pasWidth) {
return new Point( room.left + 1 + p, room.top + 1);
} else if (p < pasWidth + pasHeight) {
return new Point( room.right - 1, room.top + 1 + (p - pasWidth) );
} else if (p < pasWidth * 2 + pasHeight) {
return new Point( room.right - 1 - (p - (pasWidth + pasHeight)), room.bottom - 1 );
} else {
return new Point( room.left + 1, room.bottom - 1 - (p - (pasWidth * 2 + pasHeight)) );
}
}
}
@@ -0,0 +1,240 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class StandardPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.REGULAR );
}
if (!Dungeon.bossLevel() && Random.Int( 5 ) == 0) {
switch (Random.Int( 6 )) {
case 0:
if (level.feeling != Level.Feeling.GRASS) {
if (Math.min( room.width(), room.height() ) >= 4 && Math.max( room.width(), room.height() ) >= 6) {
paintGraveyard( level, room );
return;
}
break;
} else {
// Burned room
}
case 1:
if (Dungeon.depth > 1) {
paintBurned( level, room );
return;
}
break;
case 2:
if (Math.max( room.width(), room.height() ) >= 4) {
paintStriped( level, room );
return;
}
break;
case 3:
if (room.width() >= 6 && room.height() >= 6) {
paintStudy( level, room );
return;
}
break;
case 4:
if (level.feeling != Level.Feeling.WATER) {
if (room.connected.size() == 2 && room.width() >= 4 && room.height() >= 4) {
paintBridge( level, room );
return;
}
break;
} else {
// Fissure
}
case 5:
if (!Dungeon.bossLevel() && !Dungeon.bossLevel( Dungeon.depth + 1 ) &&
Math.min( room.width(), room.height() ) >= 5) {
paintFissure( level, room );
return;
}
break;
}
}
fill( level, room, 1, Terrain.EMPTY );
}
private static void paintBurned( Level level, Room room ) {
for (int i=room.top + 1; i < room.bottom; i++) {
for (int j=room.left + 1; j < room.right; j++) {
int t = Terrain.EMBERS;
switch (Random.Int( 5 )) {
case 0:
t = Terrain.EMPTY;
break;
case 1:
t = Terrain.FIRE_TRAP;
break;
case 2:
t = Terrain.SECRET_FIRE_TRAP;
break;
case 3:
t = Terrain.INACTIVE_TRAP;
break;
}
level.map[i * Level.WIDTH + j] = t;
}
}
}
private static void paintGraveyard( Level level, Room room ) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, room.height() - 1 , Terrain.GRASS );
int w = room.width() - 1;
int h = room.height() - 1;
int nGraves = Math.max( w, h ) / 2;
int index = Random.Int( nGraves );
int shift = Random.Int( 2 );
for (int i=0; i < nGraves; i++) {
int pos = w > h ?
room.left + 1 + shift + i * 2 + (room.top + 2 + Random.Int( h-2 )) * Level.WIDTH :
(room.left + 2 + Random.Int( w-2 )) + (room.top + 1 + shift + i * 2) * Level.WIDTH;
level.drop( i == index ? Generator.random() : new Gold(), pos ).type = Heap.Type.TOMB;
}
}
private static void paintStriped( Level level, Room room ) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, room.height() - 1 , Terrain.EMPTY_SP );
if (room.width() > room.height()) {
for (int i=room.left + 2; i < room.right; i += 2) {
fill( level, i, room.top + 1, 1, room.height() - 1, Terrain.HIGH_GRASS );
}
} else {
for (int i=room.top + 2; i < room.bottom; i += 2) {
fill( level, room.left + 1, i, room.width() - 1, 1, Terrain.HIGH_GRASS );
}
}
}
private static void paintStudy( Level level, Room room ) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, room.height() - 1 , Terrain.BOOKSHELF );
fill( level, room.left + 2, room.top + 2, room.width() - 3, room.height() - 3 , Terrain.EMPTY_SP );
for (Point door : room.connected.values()) {
if (door.x == room.left) {
set( level, door.x + 1, door.y, Terrain.EMPTY );
} else if (door.x == room.right) {
set( level, door.x - 1, door.y, Terrain.EMPTY );
} else if (door.y == room.top) {
set( level, door.x, door.y + 1, Terrain.EMPTY );
} else if (door.y == room.bottom) {
set( level, door.x , door.y - 1, Terrain.EMPTY );
}
}
set( level, room.center(), Terrain.PEDESTAL );
}
private static void paintBridge( Level level, Room room ) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, room.height() - 1 ,
!Dungeon.bossLevel() && !Dungeon.bossLevel( Dungeon.depth + 1 ) && Random.Int( 3 ) == 0 ?
Terrain.CHASM :
Terrain.WATER );
Point door1 = null;
Point door2 = null;
for (Point p : room.connected.values()) {
if (door1 == null) {
door1 = p;
} else {
door2 = p;
}
}
if ((door1.x == room.left && door2.x == room.right) ||
(door1.x == room.right && door2.x == room.left)) {
int s = room.width() / 2;
drawInside( level, room, door1, s, Terrain.EMPTY_SP );
drawInside( level, room, door2, s, Terrain.EMPTY_SP );
fill( level, room.center().x, Math.min( door1.y, door2.y ), 1, Math.abs( door1.y - door2.y ) + 1, Terrain.EMPTY_SP );
} else
if ((door1.y == room.top && door2.y == room.bottom) ||
(door1.y == room.bottom && door2.y == room.top)) {
int s = room.height() / 2;
drawInside( level, room, door1, s, Terrain.EMPTY_SP );
drawInside( level, room, door2, s, Terrain.EMPTY_SP );
fill( level, Math.min( door1.x, door2.x ), room.center().y, Math.abs( door1.x - door2.x ) + 1, 1, Terrain.EMPTY_SP );
} else
if (door1.x == door2.x) {
fill( level, door1.x == room.left ? room.left + 1 : room.right - 1, Math.min( door1.y, door2.y ), 1, Math.abs( door1.y - door2.y ) + 1, Terrain.EMPTY_SP );
} else
if (door1.y == door2.y) {
fill( level, Math.min( door1.x, door2.x ), door1.y == room.top ? room.top + 1 : room.bottom - 1, Math.abs( door1.x - door2.x ) + 1, 1, Terrain.EMPTY_SP );
} else
if (door1.y == room.top || door1.y == room.bottom) {
drawInside( level, room, door1, Math.abs( door1.y - door2.y ), Terrain.EMPTY_SP );
drawInside( level, room, door2, Math.abs( door1.x - door2.x ), Terrain.EMPTY_SP );
} else
if (door1.x == room.left || door1.x == room.right) {
drawInside( level, room, door1, Math.abs( door1.x - door2.x ), Terrain.EMPTY_SP );
drawInside( level, room, door2, Math.abs( door1.y - door2.y ), Terrain.EMPTY_SP );
}
}
private static void paintFissure( Level level, Room room ) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, room.height() - 1 ,Terrain.EMPTY );
for (int i=room.top + 2; i < room.bottom - 1; i++) {
for (int j=room.left + 2; j < room.right - 1; j++) {
int v = Math.min( i - room.top, room.bottom - i );
int h = Math.min( j - room.left, room.right - j );
if (Math.min( v, h ) > 2 || Random.Int( 2 ) == 0) {
set( level, j, i, Terrain.CHASM );
}
}
}
}
}
@@ -0,0 +1,72 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Statue;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
public class StatuePainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
Point c = room.center();
int cx = c.x;
int cy = c.y;
Room.Door door = room.entrance();
door.set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
if (door.x == room.left) {
fill( level, room.right - 1, room.top + 1, 1, room.height() - 1 , Terrain.STATUE );
cx = room.right - 2;
} else if (door.x == room.right) {
fill( level, room.left + 1, room.top + 1, 1, room.height() - 1 , Terrain.STATUE );
cx = room.left + 2;
} else if (door.y == room.top) {
fill( level, room.left + 1, room.bottom - 1, room.width() - 1, 1 , Terrain.STATUE );
cy = room.bottom - 2;
} else if (door.y == room.bottom) {
fill( level, room.left + 1, room.top + 1, room.width() - 1, 1 , Terrain.STATUE );
cy = room.top + 2;
}
Statue statue = new Statue();
statue.pos = cx + cy * Level.WIDTH;
level.mobs.add( statue );
Actor.occupyCell( statue );
}
}
@@ -0,0 +1,64 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfLiquidFlame;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class StoragePainter extends Painter {
public static void paint( Level level, Room room ) {
final int floor = Terrain.EMPTY_SP;
fill( level, room, Terrain.WALL );
fill( level, room, 1, floor );
int n = Random.IntRange( 3, 4 );
for (int i=0; i < n; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != floor);
level.drop( prize( level ), pos );
}
room.entrance().set( Room.Door.Type.BARRICADE );
level.addItemToSpawn( new PotionOfLiquidFlame() );
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize != null) {
return prize;
}
return Generator.random( Random.oneOf(
Generator.Category.POTION,
Generator.Category.SCROLL,
Generator.Category.FOOD,
Generator.Category.GOLD
) );
}
}
@@ -0,0 +1,104 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
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.potions.PotionOfLevitation;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class TrapsPainter extends Painter {
public static void paint( Level level, Room room ) {
Integer traps[] = {
Terrain.TOXIC_TRAP, Terrain.TOXIC_TRAP, Terrain.TOXIC_TRAP,
Terrain.PARALYTIC_TRAP, Terrain.PARALYTIC_TRAP,
!Dungeon.bossLevel( Dungeon.depth + 1 ) ? Terrain.CHASM : Terrain.SUMMONING_TRAP };
fill( level, room, Terrain.WALL );
fill( level, room, 1, Random.element( traps ) );
Room.Door door = room.entrance();
door.set( Room.Door.Type.REGULAR );
int lastRow = level.map[room.left + 1 + (room.top + 1) * Level.WIDTH] == Terrain.CHASM ? Terrain.CHASM : Terrain.EMPTY;
int x = -1;
int y = -1;
if (door.x == room.left) {
x = room.right - 1;
y = room.top + room.height() / 2;
fill( level, x, room.top + 1, 1, room.height() - 1 , lastRow );
} else if (door.x == room.right) {
x = room.left + 1;
y = room.top + room.height() / 2;
fill( level, x, room.top + 1, 1, room.height() - 1 , lastRow );
} else if (door.y == room.top) {
x = room.left + room.width() / 2;
y = room.bottom - 1;
fill( level, room.left + 1, y, room.width() - 1, 1 , lastRow );
} else if (door.y == room.bottom) {
x = room.left + room.width() / 2;
y = room.top + 1;
fill( level, room.left + 1, y, room.width() - 1, 1 , lastRow );
}
int pos = x + y * Level.WIDTH;
if (Random.Int( 3 ) == 0) {
if (lastRow == Terrain.CHASM) {
set( level, pos, Terrain.EMPTY );
}
level.drop( prize( level ), pos ).type = Heap.Type.CHEST;
} else {
set( level, pos, Terrain.PEDESTAL );
level.drop( prize( level ), pos );
}
level.addItemToSpawn( new PotionOfLevitation() );
}
private static Item prize( Level level ) {
Item prize = level.itemToSpanAsPrize();
if (prize != null) {
return prize;
}
prize = Generator.random( Random.oneOf(
Generator.Category.WEAPON,
Generator.Category.ARMOR
) );
for (int i=0; i < 3; i++) {
Item another = Generator.random( Random.oneOf(
Generator.Category.WEAPON,
Generator.Category.ARMOR
) );
if (another.level > prize.level) {
prize = another;
}
}
return prize;
}
}
@@ -0,0 +1,62 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class TreasuryPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
set( level, room.center(), Terrain.STATUE );
Heap.Type heapType = Random.Int( 2 ) == 0 ? Heap.Type.CHEST : Heap.Type.HEAP;
int n = Random.IntRange( 2, 3 );
for (int i=0; i < n; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != Terrain.EMPTY || level.heaps.get( pos ) != null);
level.drop( new Gold().random(), pos ).type = heapType;
}
if (heapType == Heap.Type.HEAP) {
for (int i=0; i < 6; i++) {
int pos;
do {
pos = room.random();
} while (level.map[pos] != Terrain.EMPTY);
level.drop( new Gold( Random.IntRange( 1, 3 ) ), pos );
}
}
room.entrance().set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
}
@@ -0,0 +1,120 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class TunnelPainter extends Painter {
public static void paint( Level level, Room room ) {
int floor = level.tunnelTile();
Point c = room.center();
if (room.width() > room.height() || (room.width() == room.height() && Random.Int( 2 ) == 0)) {
int from = room.right - 1;
int to = room.left + 1;
for (Room.Door door : room.connected.values()) {
int step = door.y < c.y ? +1 : -1;
if (door.x == room.left) {
from = room.left + 1;
for (int i=door.y; i != c.y; i += step) {
set( level, from, i, floor );
}
} else if (door.x == room.right) {
to = room.right - 1;
for (int i=door.y; i != c.y; i += step) {
set( level, to, i, floor );
}
} else {
if (door.x < from) {
from = door.x;
}
if (door.x > to) {
to = door.x;
}
for (int i=door.y+step; i != c.y; i += step) {
set( level, door.x, i, floor );
}
}
}
for (int i=from; i <= to; i++) {
set( level, i, c.y, floor );
}
} else {
int from = room.bottom - 1;
int to = room.top + 1;
for (Room.Door door : room.connected.values()) {
int step = door.x < c.x ? +1 : -1;
if (door.y == room.top) {
from = room.top + 1;
for (int i=door.x; i != c.x; i += step) {
set( level, i, from, floor );
}
} else if (door.y == room.bottom) {
to = room.bottom - 1;
for (int i=door.x; i != c.x; i += step) {
set( level, i, to, floor );
}
} else {
if (door.y < from) {
from = door.y;
}
if (door.y > to) {
to = door.y;
}
for (int i=door.x+step; i != c.x; i += step) {
set( level, i, door.y, floor );
}
}
}
for (int i=from; i <= to; i++) {
set( level, c.x, i, floor );
}
}
for (Room.Door door : room.connected.values()) {
door.set( Room.Door.Type.TUNNEL );
}
}
}
@@ -0,0 +1,76 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap.Type;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.GoldenKey;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Random;
public class VaultPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.EMPTY );
int cx = (room.left + room.right) / 2;
int cy = (room.top + room.bottom) / 2;
int c = cx + cy * Level.WIDTH;
switch (Random.Int( 3 )) {
case 0:
level.drop( prize( level ), c ).type = Type.LOCKED_CHEST;
level.addItemToSpawn( new GoldenKey( Dungeon.depth ) );
break;
case 1:
Item i1, i2;
do {
i1 = prize( level );
i2 = prize( level );
} while (i1.getClass() == i2.getClass());
level.drop( i1, c ).type = Type.CRYSTAL_CHEST;
level.drop( i2, c + Level.NEIGHBOURS8[Random.Int( 8 )]).type = Type.CRYSTAL_CHEST;
level.addItemToSpawn( new GoldenKey( Dungeon.depth ) );
break;
case 2:
level.drop( prize( level ), c );
set( level, c, Terrain.PEDESTAL );
break;
}
room.entrance().set( Room.Door.Type.LOCKED );
level.addItemToSpawn( new IronKey( Dungeon.depth ) );
}
private static Item prize( Level level ) {
return Generator.random( Random.oneOf(
Generator.Category.WAND,
Generator.Category.RING
) );
}
}
@@ -0,0 +1,54 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.painters;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.utils.Point;
import com.watabou.utils.Random;
public class WeakFloorPainter extends Painter {
public static void paint( Level level, Room room ) {
fill( level, room, Terrain.WALL );
fill( level, room, 1, Terrain.CHASM );
Room.Door door = room.entrance();
door.set( Room.Door.Type.REGULAR );
if (door.x == room.left) {
for (int i=room.top + 1; i < room.bottom; i++) {
drawInside( level, room, new Point( room.left, i ), Random.IntRange( 1, room.width() - 2 ), Terrain.EMPTY_SP );
}
} else if (door.x == room.right) {
for (int i=room.top + 1; i < room.bottom; i++) {
drawInside( level, room, new Point( room.right, i ), Random.IntRange( 1, room.width() - 2 ), Terrain.EMPTY_SP );
}
} else if (door.y == room.top) {
for (int i=room.left + 1; i < room.right; i++) {
drawInside( level, room, new Point( i, room.top ), Random.IntRange( 1, room.height() - 2 ), Terrain.EMPTY_SP );
}
} else if (door.y == room.bottom) {
for (int i=room.left + 1; i < room.right; i++) {
drawInside( level, room, new Point( i, room.bottom ), Random.IntRange( 1, room.height() - 2 ), Terrain.EMPTY_SP );
}
}
}
}
@@ -0,0 +1,48 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.watabou.noosa.audio.Sample;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
public class AlarmTrap {
// 0xDD3333
public static void trigger( int pos, Char ch ) {
for (Mob mob : Dungeon.level.mobs) {
if (mob != ch) {
mob.beckon( pos );
}
}
if (Dungeon.visible[pos]) {
GLog.w( "The trap emits a piercing sound that echoes throughout the dungeon!" );
CellEmitter.center( pos ).start( Speck.factory( Speck.SCREAM ), 0.3f, 3 );
}
Sample.INSTANCE.play( Assets.SND_ALERT );
}
}
@@ -0,0 +1,37 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Fire;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
public class FireTrap {
// 0xFF7708
public static void trigger( int pos, Char ch ) {
GameScene.add( Blob.seed( pos, 2, Fire.class ) );
CellEmitter.get( pos ).burst( FlameParticle.FACTORY, 5 );
}
}
@@ -0,0 +1,42 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
import com.shatteredpixel.shatteredpixeldungeon.effects.Wound;
import com.watabou.utils.Random;
public class GrippingTrap {
public static void trigger( int pos, Char c ) {
if (c != null) {
int damage = Math.max( 0, (Dungeon.depth + 3) - Random.IntRange( 0, c.dr() / 2 ) );
Buff.affect( c, Bleeding.class ).set( damage );
Buff.prolong( c, Cripple.class, Cripple.DURATION );
Wound.hit( c );
} else {
Wound.hit( pos );
}
}
}
@@ -0,0 +1,73 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.watabou.noosa.Camera;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Lightning;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
import com.watabou.utils.Random;
public class LightningTrap {
private static final String name = "lightning trap";
// 00x66CCEE
public static void trigger( int pos, Char ch ) {
if (ch != null) {
ch.damage( Math.max( 1, Random.Int( ch.HP / 3, 2 * ch.HP / 3 ) ), LIGHTNING );
if (ch == Dungeon.hero) {
Camera.main.shake( 2, 0.3f );
if (!ch.isAlive()) {
Dungeon.fail( Utils.format( ResultDescriptions.TRAP, name, Dungeon.depth ) );
GLog.n( "You were killed by a discharge of a lightning trap..." );
} else {
((Hero)ch).belongings.charge( false );
}
}
int[] points = new int[2];
points[0] = pos - Level.WIDTH;
points[1] = pos + Level.WIDTH;
ch.sprite.parent.add( new Lightning( points, 2, null ) );
points[0] = pos - 1;
points[1] = pos + 1;
ch.sprite.parent.add( new Lightning( points, 2, null ) );
}
CellEmitter.center( pos ).burst( SparkParticle.FACTORY, Random.IntRange( 3, 4 ) );
}
public static final Electricity LIGHTNING = new Electricity();
public static class Electricity {
}
}
@@ -0,0 +1,35 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ParalyticGas;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
public class ParalyticTrap {
// 0xCCCC55
public static void trigger( int pos, Char ch ) {
GameScene.add( Blob.seed( pos, 80 + 5 * Dungeon.depth, ParalyticGas.class ) );
}
}
@@ -0,0 +1,40 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PoisonParticle;
public class PoisonTrap {
// 0xBB66EE
public static void trigger( int pos, Char ch ) {
if (ch != null) {
Buff.affect( ch, Poison.class ).set( 5 + Math.min( Dungeon.depth, 15 ) );
}
CellEmitter.center( pos ).burst( PoisonParticle.SPLASH, 3 );
}
}
@@ -0,0 +1,88 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import java.util.ArrayList;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlink;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.watabou.utils.Random;
public class SummoningTrap {
private static final float DELAY = 2f;
private static final Mob DUMMY = new Mob() {};
// 0x770088
public static void trigger( int pos, Char c ) {
if (Dungeon.bossLevel()) {
return;
}
if (c != null) {
Actor.occupyCell( c );
}
int nMobs = 1;
if (Random.Int( 2 ) == 0) {
nMobs++;
if (Random.Int( 2 ) == 0) {
nMobs++;
}
}
// It's complicated here, because these traps can be activated in chain
ArrayList<Integer> candidates = new ArrayList<Integer>();
for (int i=0; i < Level.NEIGHBOURS8.length; i++) {
int p = pos + Level.NEIGHBOURS8[i];
if (Actor.findChar( p ) == null && (Level.passable[p] || Level.avoid[p])) {
candidates.add( p );
}
}
ArrayList<Integer> respawnPoints = new ArrayList<Integer>();
while (nMobs > 0 && candidates.size() > 0) {
int index = Random.index( candidates );
DUMMY.pos = candidates.get( index );
Actor.occupyCell( DUMMY );
respawnPoints.add( candidates.remove( index ) );
nMobs--;
}
for (Integer point : respawnPoints) {
Mob mob = Bestiary.mob( Dungeon.depth );
mob.state = Mob.State.WANDERING;
GameScene.add( mob, DELAY );
WandOfBlink.appear( mob, point );
}
}
}
@@ -0,0 +1,35 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2014 Oleg Dolya
*
* 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.traps;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
public class ToxicTrap {
// 0x40CC55
public static void trigger( int pos, Char ch ) {
GameScene.add( Blob.seed( pos, 300 + 20 * Dungeon.depth, ToxicGas.class ) );
}
}