v0.6.0: moved all level building logic into builder classes
This commit is contained in:
parent
ec6ca86474
commit
e9a7384779
|
@ -245,75 +245,80 @@ public class Wandmaker extends NPC {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean spawn( PrisonLevel level, Room room, Collection<Room> rooms ) {
|
||||
if (!spawned && (type != 0 || (Dungeon.depth > 6 && Random.Int( 10 - Dungeon.depth ) == 0))) {
|
||||
// decide between 1,2, or 3 for quest type.
|
||||
// but if the no herbalism challenge is enabled, only pick 1 or 2, no rotberry.
|
||||
if (type == 0) type = Random.Int(Dungeon.isChallenged(Challenges.NO_HERBALISM) ? 2 : 3)+1;
|
||||
private static boolean questRoomSpawned;
|
||||
|
||||
public static void spawnWandmaker( PrisonLevel level, Room room, Collection<Room> rooms ) {
|
||||
if (questRoomSpawned) {
|
||||
|
||||
questRoomSpawned = false;
|
||||
|
||||
Wandmaker npc = new Wandmaker();
|
||||
do {
|
||||
npc.pos = level.pointToCell(room.random());
|
||||
//Wandmaker must never spawn in the center.
|
||||
//If he does, and the room is 3x3, there is no room for the stairs.
|
||||
} while (npc.pos == level.pointToCell(room.center()));
|
||||
level.mobs.add( npc );
|
||||
|
||||
//note that we set the type but can fail here. This ensures that if a level needs to be re-generated
|
||||
//we don't re-roll the quest, it will try to assign itself to that new level with the same type.
|
||||
if (setRoom( rooms )){
|
||||
Wandmaker npc = new Wandmaker();
|
||||
do {
|
||||
npc.pos = level.pointToCell(room.random());
|
||||
//Wandmaker must never spawn in the center.
|
||||
//If he does, and the room is 3x3, there is no room for the stairs.
|
||||
} while (npc.pos == level.pointToCell(room.center()));
|
||||
level.mobs.add( npc );
|
||||
spawned = true;
|
||||
|
||||
spawned = true;
|
||||
given = false;
|
||||
wand1 = (Wand) Generator.random(Generator.Category.WAND);
|
||||
wand1.cursed = false;
|
||||
wand1.identify();
|
||||
wand1.upgrade();
|
||||
|
||||
given = false;
|
||||
wand1 = (Wand) Generator.random(Generator.Category.WAND);
|
||||
wand1.cursed = false;
|
||||
wand1.identify();
|
||||
wand1.upgrade();
|
||||
|
||||
do {
|
||||
wand2 = (Wand) Generator.random(Generator.Category.WAND);
|
||||
} while (wand2.getClass().equals(wand1.getClass()));
|
||||
wand2.cursed = false;
|
||||
wand2.identify();
|
||||
wand2.upgrade();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
do {
|
||||
wand2 = (Wand) Generator.random(Generator.Category.WAND);
|
||||
} while (wand2.getClass().equals(wand1.getClass()));
|
||||
wand2.cursed = false;
|
||||
wand2.identify();
|
||||
wand2.upgrade();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean setRoom( Collection<Room> rooms) {
|
||||
Room questRoom = null;
|
||||
for (Room r : rooms){
|
||||
if (r.type == Room.Type.STANDARD && r.width() > 5 && r.height() > 5){
|
||||
if (type == 2 || r.connected.size() == 1){
|
||||
questRoom = r;
|
||||
break;
|
||||
public static boolean spawnRoom( Collection<Room> rooms) {
|
||||
questRoomSpawned = false;
|
||||
if (!spawned && (type != 0 || (Dungeon.depth > 6 && Random.Int( 10 - Dungeon.depth ) == 0))) {
|
||||
|
||||
// decide between 1,2, or 3 for quest type.
|
||||
// but if the no herbalism challenge is enabled, only pick 1 or 2, no rotberry.
|
||||
if (type == 0) type = Random.Int(Dungeon.isChallenged(Challenges.NO_HERBALISM) ? 2 : 3)+1;
|
||||
|
||||
//note that we set the type but can fail here. This ensures that if a level needs to be re-generated
|
||||
//we don't re-roll the quest, it will try to assign itself to that new level with the same type.
|
||||
Room questRoom = null;
|
||||
for (Room r : rooms){
|
||||
if (r.type == Room.Type.STANDARD && r.width() > 5 && r.height() > 5){
|
||||
if (type == 2 || r.connected.size() == 1){
|
||||
questRoom = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (questRoom == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type){
|
||||
case 1: default:
|
||||
questRoom.type = Room.Type.MASS_GRAVE;
|
||||
break;
|
||||
case 2:
|
||||
questRoom.type = Room.Type.RITUAL_SITE;
|
||||
break;
|
||||
case 3:
|
||||
questRoom.type = Room.Type.ROT_GARDEN;
|
||||
break;
|
||||
}
|
||||
|
||||
questRoomSpawned = true;
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (questRoom == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type){
|
||||
case 1: default:
|
||||
questRoom.type = Room.Type.MASS_GRAVE;
|
||||
break;
|
||||
case 2:
|
||||
questRoom.type = Room.Type.RITUAL_SITE;
|
||||
break;
|
||||
case 3:
|
||||
questRoom.type = Room.Type.ROT_GARDEN;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void complete() {
|
||||
|
|
|
@ -23,7 +23,6 @@ package com.shatteredpixel.shatteredpixeldungeon.levels;
|
|||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.ConfusionTrap;
|
||||
|
@ -98,16 +97,6 @@ public class CavesLevel extends RegularLevel {
|
|||
1 };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean assignRoomType() {
|
||||
if (!super.assignRoomType()) return false;
|
||||
|
||||
if (!Blacksmith.Quest.spawn( rooms ) && Dungeon.depth == 14)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorate() {
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ package com.shatteredpixel.shatteredpixeldungeon.levels;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.BlazingTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CursingTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.DisarmingTrap;
|
||||
|
@ -94,19 +92,6 @@ public class CityLevel extends RegularLevel {
|
|||
1, 1 };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean assignRoomType() {
|
||||
if (!super.assignRoomType()) return false;
|
||||
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Type.TUNNEL) {
|
||||
r.type = Type.PASSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorate() {
|
||||
|
||||
|
|
|
@ -27,15 +27,12 @@ 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.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.Builder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.LegacyBuilder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.watabou.noosa.Group;
|
||||
import com.watabou.utils.Graph;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LastShopLevel extends RegularLevel {
|
||||
|
||||
{
|
||||
|
@ -54,83 +51,10 @@ public class LastShopLevel extends RegularLevel {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean build() {
|
||||
|
||||
protected Builder builder() {
|
||||
feeling = Feeling.CHASM;
|
||||
viewDistance = 4;
|
||||
|
||||
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 < 54) {
|
||||
return false;
|
||||
} else {
|
||||
roomShop.type = Imp.Quest.isCompleted() ? Room.Type.SHOP : Room.Type.STANDARD;
|
||||
}
|
||||
|
||||
paint();
|
||||
|
||||
paintWater();
|
||||
paintGrass();
|
||||
|
||||
return true;
|
||||
return new LegacyBuilder(LegacyBuilder.Type.LAST_SHOP,
|
||||
width, height, minRoomSize, maxRoomSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -225,6 +149,10 @@ public class LastShopLevel extends RegularLevel {
|
|||
protected boolean[] grass() {
|
||||
return Patch.generate( width, height, 0.10f, 3, true );
|
||||
}
|
||||
|
||||
protected int nTraps() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group addVisuals( ) {
|
||||
|
|
|
@ -156,7 +156,7 @@ public abstract class Level implements Bundlable {
|
|||
public int color2 = 0x88CC44;
|
||||
|
||||
//FIXME this is sloppy. Should be able to keep track of this without static variables
|
||||
protected static boolean pitRoomNeeded = false;
|
||||
public static boolean pitRoomNeeded = false;
|
||||
public static boolean weakFloorCreated = false;
|
||||
|
||||
private static final String VERSION = "version";
|
||||
|
|
|
@ -26,8 +26,6 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
|||
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.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.AlarmTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.ChillingTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.ConfusionTrap;
|
||||
|
@ -88,23 +86,12 @@ public class PrisonLevel extends RegularLevel {
|
|||
2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1 };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean assignRoomType() {
|
||||
if (!super.assignRoomType()) return false;
|
||||
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Type.TUNNEL) {
|
||||
r.type = Type.PASSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
return Wandmaker.Quest.spawn( this, roomEntrance, rooms );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorate() {
|
||||
|
||||
Wandmaker.Quest.spawnWandmaker( this, roomEntrance, rooms );
|
||||
|
||||
for (int i=width() + 1; i < length() - width() - 1; i++) {
|
||||
if (map[i] == Terrain.EMPTY) {
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
package com.shatteredpixel.shatteredpixeldungeon.levels;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Bones;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
|
||||
|
@ -33,16 +32,16 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfWealth;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.Builder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.LegacyBuilder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.ShopRoom;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.ChillingTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.ExplosiveTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.FireTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.WornTrap;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Graph;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
import com.watabou.utils.Rect;
|
||||
|
@ -50,120 +49,36 @@ import com.watabou.utils.Rect;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class RegularLevel extends Level {
|
||||
|
||||
|
||||
protected ArrayList<Room> rooms;
|
||||
|
||||
protected Builder builder;
|
||||
|
||||
protected Room roomEntrance;
|
||||
protected Room roomExit;
|
||||
|
||||
protected ArrayList<Room.Type> specials;
|
||||
|
||||
public int secretDoors;
|
||||
|
||||
@Override
|
||||
protected boolean build() {
|
||||
|
||||
if (!initRooms()) {
|
||||
builder = builder();
|
||||
|
||||
rooms = builder.build(null);
|
||||
|
||||
if (rooms == null){
|
||||
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;
|
||||
roomEntrance = ((LegacyBuilder)builder).roomEntrance;
|
||||
roomExit = ((LegacyBuilder)builder).roomExit;
|
||||
|
||||
ArrayList<Room> connected = new ArrayList<>();
|
||||
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()-1)*(r.height()-1) >= ShopRoom.spaceNeeded())) {
|
||||
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 );
|
||||
}
|
||||
if (Dungeon.isChallenged( Challenges.NO_ARMOR )){
|
||||
//no sense in giving an armor reward room on a run with no armor.
|
||||
specials.remove( Room.Type.CRYPT );
|
||||
}
|
||||
if (Dungeon.isChallenged( Challenges.NO_HERBALISM )){
|
||||
//sorry warden, no lucky sungrass or blandfruit seeds for you!
|
||||
specials.remove( Room.Type.GARDEN );
|
||||
}
|
||||
if (!assignRoomType())
|
||||
if (!paint()){
|
||||
return false;
|
||||
}
|
||||
|
||||
paint();
|
||||
paintWater();
|
||||
paintGrass();
|
||||
|
||||
|
@ -171,6 +86,11 @@ public abstract class RegularLevel extends Level {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Builder builder(){
|
||||
return new LegacyBuilder(LegacyBuilder.Type.REGULAR,
|
||||
width, height, minRoomSize, maxRoomSize);
|
||||
}
|
||||
|
||||
protected void placeSign(){
|
||||
while (true) {
|
||||
|
@ -182,122 +102,6 @@ public abstract class RegularLevel extends Level {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean initRooms() {
|
||||
|
||||
rooms = new ArrayList<>();
|
||||
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 boolean assignRoomType() {
|
||||
|
||||
int specialRooms = 0;
|
||||
boolean pitMade = false;
|
||||
|
||||
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 && !pitMade) {
|
||||
|
||||
r.type = Type.PIT;
|
||||
pitMade = true;
|
||||
|
||||
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){
|
||||
|
||||
ArrayList<Room> neigbours = new ArrayList<>();
|
||||
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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pitRoomNeeded && !pitMade) return false;
|
||||
|
||||
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 < 6) {
|
||||
Room r = randomRoom( Type.TUNNEL, 20 );
|
||||
if (r != null) {
|
||||
r.type = Type.STANDARD;
|
||||
count++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void paintWater() {
|
||||
boolean[] lake = water();
|
||||
for (int i=0; i < length(); i++) {
|
||||
|
@ -394,45 +198,7 @@ public abstract class RegularLevel extends Level {
|
|||
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 ((Random.Float() <= (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() {
|
||||
protected boolean paint() {
|
||||
|
||||
for (Room r : rooms) {
|
||||
if (r.type != Type.NULL) {
|
||||
|
@ -448,6 +214,8 @@ public abstract class RegularLevel extends Level {
|
|||
for (Room r : rooms) {
|
||||
paintDoors( r );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void placeDoors( Room r ) {
|
||||
|
|
|
@ -29,19 +29,17 @@ 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.builders.Builder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.LegacyBuilder;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.watabou.noosa.Group;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Graph;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SewerBossLevel extends RegularLevel {
|
||||
|
||||
{
|
||||
|
@ -64,107 +62,13 @@ public class SewerBossLevel extends RegularLevel {
|
|||
@Override
|
||||
protected boolean build() {
|
||||
|
||||
initRooms();
|
||||
|
||||
int distance;
|
||||
//if we ever need to try 20 or more times to find a room, better to give up and try again.
|
||||
int retry = 0;
|
||||
|
||||
//start with finding an entrance room (will also contain exit)
|
||||
//the room must be at least 4x4 and be nearer the top of the map(so that it is less likely something connects to the top)
|
||||
do {
|
||||
if (retry++ > 20) {
|
||||
return false;
|
||||
}
|
||||
roomEntrance = Random.element( rooms );
|
||||
} while (roomEntrance.width() != 8 || roomEntrance.height() < 5 || roomEntrance.top == 0 || roomEntrance.top >= 8);
|
||||
|
||||
roomEntrance.type = Type.ENTRANCE;
|
||||
roomExit = roomEntrance;
|
||||
|
||||
|
||||
//now find the rest of the rooms for this boss mini-maze
|
||||
Room curRoom = null;
|
||||
Room lastRoom = roomEntrance;
|
||||
//we make 4 rooms, last iteration is tieing the final room to the start
|
||||
for(int i = 0; i <= 4; i++){
|
||||
retry = 0;
|
||||
//find a suitable room the first four times
|
||||
//suitable room should be empty, have a distance of 2 from the current room, and not touch the entrance.
|
||||
if (i < 4) {
|
||||
do {
|
||||
if (retry++ > 20) {
|
||||
return false;
|
||||
}
|
||||
curRoom = Random.element(rooms);
|
||||
Graph.buildDistanceMap(rooms, curRoom);
|
||||
distance = lastRoom.distance();
|
||||
} while (curRoom.type != Type.NULL || distance != 3 || curRoom.neigbours.contains(roomEntrance));
|
||||
|
||||
curRoom.type = Type.STANDARD;
|
||||
|
||||
//otherwise, we're on the last iteration.
|
||||
} else {
|
||||
//set the current room to the entrance, so we can build a connection to it.
|
||||
curRoom = roomEntrance;
|
||||
}
|
||||
|
||||
//now build a connection between the current room and the last one.
|
||||
Graph.buildDistanceMap( rooms, curRoom );
|
||||
List<Room> path = Graph.buildPath( rooms, lastRoom, curRoom );
|
||||
|
||||
Graph.setPrice( path, lastRoom.distance );
|
||||
|
||||
path = Graph.buildPath( rooms, lastRoom, curRoom );
|
||||
|
||||
Room room = lastRoom;
|
||||
for (Room next : path) {
|
||||
room.connect( next );
|
||||
room = next;
|
||||
}
|
||||
|
||||
if (i == 4) {
|
||||
|
||||
//we must find a room for his royal highness!
|
||||
//look at rooms adjacent to the final found room (likely to be furthest from start)
|
||||
ArrayList<Room> candidates = new ArrayList<Room>();
|
||||
for (Room r : lastRoom.neigbours) {
|
||||
if (r.type == Type.NULL && r.connected.size() == 0 && !r.neigbours.contains(roomEntrance)) {
|
||||
candidates.add(r);
|
||||
}
|
||||
}
|
||||
|
||||
//if we have candidates, pick a room and put the king there
|
||||
if (candidates.size() > 0) {
|
||||
Room kingsRoom = Random.element(candidates);
|
||||
kingsRoom.connect(lastRoom);
|
||||
kingsRoom.type = Room.Type.RAT_KING;
|
||||
|
||||
//unacceptable! make a new level...
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lastRoom = curRoom;
|
||||
}
|
||||
|
||||
//the connection structure ensures that (most of the time) there is a nice loop for the player to kite the
|
||||
//boss around. What's nice is that there is enough chaos such that the loop is rarely straightforward
|
||||
//and boring.
|
||||
|
||||
//fills our connection rooms in with tunnel
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Type.NULL && r.connected.size() > 0) {
|
||||
r.type = Type.TUNNEL;
|
||||
}
|
||||
}
|
||||
|
||||
paint();
|
||||
|
||||
if (!super.build())
|
||||
return false;
|
||||
|
||||
//sticks the exit in the room entrance.
|
||||
exit = roomEntrance.top * width() + (roomEntrance.left + roomEntrance.right) / 2;
|
||||
map[exit] = Terrain.LOCKED_EXIT;
|
||||
|
||||
|
||||
//make sure the exit is only visible in the entrance room.
|
||||
int count = 0;
|
||||
for (int i : PathFinder.NEIGHBOURS8){
|
||||
|
@ -174,13 +78,14 @@ public class SewerBossLevel extends RegularLevel {
|
|||
}
|
||||
if (count > 3)
|
||||
return false;
|
||||
|
||||
|
||||
paintWater();
|
||||
paintGrass();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Builder builder(){
|
||||
return new LegacyBuilder(LegacyBuilder.Type.SEWER_BOSS,
|
||||
width, height, minRoomSize, maxRoomSize);
|
||||
}
|
||||
|
||||
protected boolean[] water() {
|
||||
return Patch.generate( width, height, 0.5f, 5, true );
|
||||
|
@ -190,6 +95,10 @@ public class SewerBossLevel extends RegularLevel {
|
|||
return Patch.generate( width, height, 0.20f, 4, true );
|
||||
}
|
||||
|
||||
protected int nTraps() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorate() {
|
||||
int start = roomExit.top * width() + roomExit.left + 1;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.shatteredpixel.shatteredpixeldungeon.levels.builders;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class Builder {
|
||||
|
||||
//If builders require additional parameters, they should request them in their constructor
|
||||
|
||||
//builders take a list of rooms and returns them as a connected map
|
||||
//returns null on failure
|
||||
public abstract ArrayList<Room> build(ArrayList<Room> rooms);
|
||||
|
||||
}
|
|
@ -0,0 +1,507 @@
|
|||
package com.shatteredpixel.shatteredpixeldungeon.levels.builders;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Wandmaker;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.ShopRoom;
|
||||
import com.watabou.utils.Graph;
|
||||
import com.watabou.utils.Random;
|
||||
import com.watabou.utils.Rect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
//This builder exactly mimics pre-0.6.0 levelgen, including all of its limitations
|
||||
//Currently implemented during this transition period, it will likely not survive to 0.6.0 release
|
||||
public class LegacyBuilder extends Builder {
|
||||
|
||||
public enum Type{
|
||||
REGULAR,
|
||||
SEWER_BOSS,
|
||||
LAST_SHOP
|
||||
}
|
||||
|
||||
private Type type;
|
||||
private int width, height;
|
||||
private int minRoomSize, maxRoomSize;
|
||||
|
||||
public LegacyBuilder(Type t, int w, int h, int min, int max){
|
||||
type = t;
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
|
||||
minRoomSize = min;
|
||||
maxRoomSize = max;
|
||||
}
|
||||
|
||||
private ArrayList<Room> rooms;
|
||||
|
||||
public Room roomEntrance;
|
||||
public Room roomExit;
|
||||
|
||||
protected ArrayList<Room.Type> specials;
|
||||
|
||||
@Override
|
||||
//The list of rooms passed to this method is ignored
|
||||
public ArrayList<Room> build(ArrayList<Room> ignoredRooms) {
|
||||
|
||||
if (!initRooms()){
|
||||
return null;
|
||||
}
|
||||
|
||||
switch(type){
|
||||
case REGULAR: default:
|
||||
return buildRegularLevel();
|
||||
case SEWER_BOSS:
|
||||
return buildSewerBossLevel();
|
||||
case LAST_SHOP:
|
||||
return buildsLastShopLevel();
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<Room> buildRegularLevel(){
|
||||
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 null;
|
||||
}
|
||||
|
||||
} while (distance < minDistance);
|
||||
|
||||
roomEntrance.type = Room.Type.ENTRANCE;
|
||||
roomExit.type = Room.Type.EXIT;
|
||||
|
||||
ArrayList<Room> connected = new ArrayList<>();
|
||||
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()-1)*(r.height()-1) >= ShopRoom.spaceNeeded())) {
|
||||
shop = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shop == null) {
|
||||
return null;
|
||||
} 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 );
|
||||
}
|
||||
if (Dungeon.isChallenged( Challenges.NO_ARMOR )){
|
||||
//no sense in giving an armor reward room on a run with no armor.
|
||||
specials.remove( Room.Type.CRYPT );
|
||||
}
|
||||
if (Dungeon.isChallenged( Challenges.NO_HERBALISM )){
|
||||
//sorry warden, no lucky sungrass or blandfruit seeds for you!
|
||||
specials.remove( Room.Type.GARDEN );
|
||||
}
|
||||
|
||||
if (!assignRoomType())
|
||||
return null;
|
||||
|
||||
//Quest generation logic
|
||||
if (Dungeon.depth >= 6 && Dungeon.depth <= 9){
|
||||
if (!Wandmaker.Quest.spawnRoom( rooms ) && Dungeon.depth == 9)
|
||||
return null;
|
||||
} else if (Dungeon.depth >= 11 && Dungeon.depth <= 14){
|
||||
if (!Blacksmith.Quest.spawn( rooms ) && Dungeon.depth == 14)
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
private ArrayList<Room> buildSewerBossLevel(){
|
||||
int distance;
|
||||
//if we ever need to try 20 or more times to find a room, better to give up and try again.
|
||||
int retry = 0;
|
||||
|
||||
//start with finding an entrance room (will also contain exit)
|
||||
//the room must be at least 4x4 and be nearer the top of the map(so that it is less likely something connects to the top)
|
||||
do {
|
||||
if (retry++ > 20) {
|
||||
return null;
|
||||
}
|
||||
roomEntrance = Random.element( rooms );
|
||||
} while (roomEntrance.width() != 8 || roomEntrance.height() < 5 || roomEntrance.top == 0 || roomEntrance.top >= 8);
|
||||
|
||||
roomEntrance.type = Room.Type.ENTRANCE;
|
||||
roomExit = roomEntrance;
|
||||
|
||||
|
||||
//now find the rest of the rooms for this boss mini-maze
|
||||
Room curRoom = null;
|
||||
Room lastRoom = roomEntrance;
|
||||
//we make 4 rooms, last iteration is tieing the final room to the start
|
||||
for(int i = 0; i <= 4; i++){
|
||||
retry = 0;
|
||||
//find a suitable room the first four times
|
||||
//suitable room should be empty, have a distance of 2 from the current room, and not touch the entrance.
|
||||
if (i < 4) {
|
||||
do {
|
||||
if (retry++ > 20) {
|
||||
return null;
|
||||
}
|
||||
curRoom = Random.element(rooms);
|
||||
Graph.buildDistanceMap(rooms, curRoom);
|
||||
distance = lastRoom.distance();
|
||||
} while (curRoom.type != Room.Type.NULL || distance != 3 || curRoom.neigbours.contains(roomEntrance));
|
||||
|
||||
curRoom.type = Room.Type.STANDARD;
|
||||
|
||||
//otherwise, we're on the last iteration.
|
||||
} else {
|
||||
//set the current room to the entrance, so we can build a connection to it.
|
||||
curRoom = roomEntrance;
|
||||
}
|
||||
|
||||
//now build a connection between the current room and the last one.
|
||||
Graph.buildDistanceMap( rooms, curRoom );
|
||||
List<Room> path = Graph.buildPath( rooms, lastRoom, curRoom );
|
||||
|
||||
Graph.setPrice( path, lastRoom.distance );
|
||||
|
||||
path = Graph.buildPath( rooms, lastRoom, curRoom );
|
||||
|
||||
Room room = lastRoom;
|
||||
for (Room next : path) {
|
||||
room.connect( next );
|
||||
room = next;
|
||||
}
|
||||
|
||||
if (i == 4) {
|
||||
|
||||
//we must find a room for his royal highness!
|
||||
//look at rooms adjacent to the final found room (likely to be furthest from start)
|
||||
ArrayList<Room> candidates = new ArrayList<Room>();
|
||||
for (Room r : lastRoom.neigbours) {
|
||||
if (r.type == Room.Type.NULL && r.connected.size() == 0 && !r.neigbours.contains(roomEntrance)) {
|
||||
candidates.add(r);
|
||||
}
|
||||
}
|
||||
|
||||
//if we have candidates, pick a room and put the king there
|
||||
if (candidates.size() > 0) {
|
||||
Room kingsRoom = Random.element(candidates);
|
||||
kingsRoom.connect(lastRoom);
|
||||
kingsRoom.type = Room.Type.RAT_KING;
|
||||
|
||||
//unacceptable! make a new level...
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
lastRoom = curRoom;
|
||||
}
|
||||
|
||||
//the connection structure ensures that (most of the time) there is a nice loop for the player to kite the
|
||||
//boss around. What's nice is that there is enough chaos such that the loop is rarely straightforward
|
||||
//and boring.
|
||||
|
||||
//fills our connection rooms in with tunnel
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Room.Type.NULL && r.connected.size() > 0) {
|
||||
r.type = Room.Type.TUNNEL;
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
private ArrayList<Room> buildsLastShopLevel(){
|
||||
int distance;
|
||||
int retry = 0;
|
||||
int minDistance = (int)Math.sqrt( rooms.size() );
|
||||
do {
|
||||
int innerRetry = 0;
|
||||
do {
|
||||
if (innerRetry++ > 10) {
|
||||
return null;
|
||||
}
|
||||
roomEntrance = Random.element( rooms );
|
||||
} while (roomEntrance.width() < 4 || roomEntrance.height() < 4);
|
||||
|
||||
innerRetry = 0;
|
||||
do {
|
||||
if (innerRetry++ > 10) {
|
||||
return null;
|
||||
}
|
||||
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 null;
|
||||
}
|
||||
|
||||
} while (distance < minDistance);
|
||||
|
||||
roomEntrance.type = Room.Type.ENTRANCE;
|
||||
roomExit.type = Room.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 == Room.Type.NULL && r.connected.size() > 0) {
|
||||
r.type = Room.Type.PASSAGE;
|
||||
if (r.square() > shopSquare) {
|
||||
roomShop = r;
|
||||
shopSquare = r.square();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (roomShop == null || shopSquare < 54) {
|
||||
return null;
|
||||
} else {
|
||||
roomShop.type = Imp.Quest.isCompleted() ? Room.Type.SHOP : Room.Type.STANDARD;
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
private boolean initRooms(){
|
||||
rooms = new ArrayList<>();
|
||||
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;
|
||||
}
|
||||
|
||||
private 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 ((Random.Float() <= (minRoomSize * minRoomSize / rect.square()) && w <= maxRoomSize && h <= maxRoomSize) || w < minRoomSize || h < minRoomSize) {
|
||||
|
||||
rooms.add( new Room(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 boolean assignRoomType() {
|
||||
|
||||
int specialRooms = 0;
|
||||
boolean pitMade = false;
|
||||
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Room.Type.NULL &&
|
||||
r.connected.size() == 1) {
|
||||
|
||||
if (specials.size() > 0 &&
|
||||
r.width() > 3 && r.height() > 3 &&
|
||||
Random.Int( specialRooms * specialRooms + 2 ) == 0) {
|
||||
|
||||
if (Level.pitRoomNeeded && !pitMade) {
|
||||
|
||||
r.type = Room.Type.PIT;
|
||||
pitMade = true;
|
||||
|
||||
specials.remove( Room.Type.ARMORY );
|
||||
specials.remove( Room.Type.CRYPT );
|
||||
specials.remove( Room.Type.LABORATORY );
|
||||
specials.remove( Room.Type.LIBRARY );
|
||||
specials.remove( Room.Type.STATUE );
|
||||
specials.remove( Room.Type.TREASURY );
|
||||
specials.remove( Room.Type.VAULT );
|
||||
specials.remove( Room.Type.WEAK_FLOOR );
|
||||
|
||||
} else if (Dungeon.depth % 5 == 2 && specials.contains( Room.Type.LABORATORY )) {
|
||||
|
||||
r.type = Room.Type.LABORATORY;
|
||||
|
||||
} else if (Dungeon.depth >= Dungeon.transmutation && specials.contains( Room.Type.MAGIC_WELL )) {
|
||||
|
||||
r.type = Room.Type.MAGIC_WELL;
|
||||
|
||||
} else {
|
||||
|
||||
int n = specials.size();
|
||||
r.type = specials.get( Math.min( Random.Int( n ), Random.Int( n ) ) );
|
||||
if (r.type == Room.Type.WEAK_FLOOR) {
|
||||
Level.weakFloorCreated = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Room.useType( r.type );
|
||||
specials.remove( r.type );
|
||||
specialRooms++;
|
||||
|
||||
} else if (Random.Int( 2 ) == 0){
|
||||
|
||||
ArrayList<Room> neigbours = new ArrayList<>();
|
||||
for (Room n : r.neigbours) {
|
||||
if (!r.connected.containsKey( n ) &&
|
||||
!Room.SPECIALS.contains( n.type ) &&
|
||||
n.type != Room.Type.PIT) {
|
||||
|
||||
neigbours.add( n );
|
||||
}
|
||||
}
|
||||
if (neigbours.size() > 1) {
|
||||
r.connect( Random.element( neigbours ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Level.pitRoomNeeded && !pitMade) return false;
|
||||
|
||||
Room.Type tunnelType = Room.Type.TUNNEL;
|
||||
if ((Dungeon.depth > 5 && Dungeon.depth <= 10) ||
|
||||
(Dungeon.depth > 15 && Dungeon.depth <= 20)){
|
||||
tunnelType = Room.Type.PASSAGE;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Room.Type.NULL) {
|
||||
int connections = r.connected.size();
|
||||
if (connections == 0) {
|
||||
|
||||
} else if (Random.Int( connections * connections ) == 0) {
|
||||
r.type = Room.Type.STANDARD;
|
||||
count++;
|
||||
} else {
|
||||
r.type = tunnelType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (count < 6) {
|
||||
Room r = randomRoom( tunnelType, 20 );
|
||||
if (r != null) {
|
||||
r.type = Room.Type.STANDARD;
|
||||
count++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user