v3.3.2: implemented a simple grid builder and tied it into vault level
This commit is contained in:
@@ -21,10 +21,7 @@
|
|||||||
|
|
||||||
package com.shatteredpixel.shatteredpixeldungeon.levels;
|
package com.shatteredpixel.shatteredpixeldungeon.levels;
|
||||||
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Bones;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||||
@@ -33,186 +30,115 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
|||||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
|
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
|
import com.shatteredpixel.shatteredpixeldungeon.items.keys.GoldenKey;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.TrinketCatalyst;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon;
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.Builder;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.GridBuilder;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EmptyRoom;
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.RegionDecoLineRoom;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.RegionDecoLineRoom;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.SegmentedRoom;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.SegmentedRoom;
|
||||||
import com.watabou.noosa.audio.Music;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.entrance.EntranceRoom;
|
||||||
import com.watabou.utils.Point;
|
import com.watabou.utils.Point;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
import com.watabou.utils.Rect;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class VaultLevel extends Level { //for now
|
public class VaultLevel extends CityLevel {
|
||||||
|
|
||||||
{
|
@Override
|
||||||
color1 = 0x4b6636;
|
protected ArrayList<Room> initRooms() {
|
||||||
color2 = 0xf2f2f2;
|
ArrayList<Room> initRooms = new ArrayList<>();
|
||||||
|
|
||||||
|
initRooms.add(roomEntrance = new EntranceRoom(){
|
||||||
|
@Override
|
||||||
|
public int maxConnections(int direction) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canMerge(Level l, Room other, Point p, int mergeTerrain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < 23; i++){
|
||||||
|
initRooms.add(new SegmentedRoom(){
|
||||||
|
@Override
|
||||||
|
public float[] sizeCatProbs() {
|
||||||
|
return new float[]{1, 0, 0};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initRooms.add(new RegionDecoLineRoom(){
|
||||||
|
@Override
|
||||||
|
public int maxConnections(int direction) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canMerge(Level l, Room other, Point p, int mergeTerrain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return initRooms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playLevelMusic() {
|
protected Builder builder() {
|
||||||
Music.INSTANCE.playTracks(CityLevel.CITY_TRACK_LIST, CityLevel.CITY_TRACK_CHANCES, false);
|
return new GridBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tilesTex() {
|
protected int nTraps() {
|
||||||
return Assets.Environment.TILES_CITY;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String waterTex() {
|
|
||||||
return Assets.Environment.WATER_CITY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean build() {
|
protected boolean build() {
|
||||||
setSize(34, 34);
|
for (int i = 0; i < 20; i++){
|
||||||
|
Item item = Generator.randomUsingDefaults(Random.oneOf(
|
||||||
ArrayList<Room> rooms = new ArrayList<>();
|
Generator.Category.WEAPON, Generator.Category.WEAPON, Generator.Category.WEAPON,
|
||||||
|
Generator.Category.ARMOR,
|
||||||
Room finalRoom = null;
|
Generator.Category.WAND,
|
||||||
Room entryRoom = null;
|
Generator.Category.RING));
|
||||||
|
if (item.cursed){
|
||||||
for (int x = 0; x < 4; x++){
|
item.cursed = false;
|
||||||
for (int y = 0; y < 4; y++){
|
if (item instanceof MeleeWeapon && ((MeleeWeapon) item).hasCurseEnchant()){
|
||||||
|
((MeleeWeapon) item).enchant(null);
|
||||||
if (x == 3 && y <= 1){
|
} else if (item instanceof Armor && ((Armor) item).hasCurseGlyph()){
|
||||||
if (y == 1) {
|
((Armor) item).inscribe(null);
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
Room r = new RegionDecoLineRoom();
|
|
||||||
r.set(1+8*x, 1+8*y, 9+8*x, 17);
|
|
||||||
rooms.add(r);
|
|
||||||
finalRoom = r;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
item.identify();
|
||||||
|
addItemToSpawn(item);
|
||||||
|
}
|
||||||
|
|
||||||
if (x == 0 && y == 3){
|
if (!super.build()){
|
||||||
Room r = new EmptyRoom();
|
return false;
|
||||||
r.set(1+8*x, 1+8*y, 9+8*x, 9+8*y);
|
}
|
||||||
rooms.add(r);
|
|
||||||
entryRoom = r;
|
Room finalRoom = room(RegionDecoLineRoom.class);
|
||||||
} else {
|
for (Point p : finalRoom.getPoints()){
|
||||||
Room r = new SegmentedRoom();
|
int cell = pointToCell(p);
|
||||||
r.set(1+8*x, 1+8*y, 9+8*x, 9+8*y);
|
if (map[cell] == Terrain.REGION_DECO){
|
||||||
rooms.add(r);
|
set(cell, Terrain.REGION_DECO_ALT, this);
|
||||||
}
|
} else if (map[cell] == Terrain.EMPTY || map[cell] == Terrain.EMPTY_DECO || map[cell] == Terrain.WATER || map[cell] == Terrain.HIGH_GRASS || map[cell] == Terrain.GRASS){
|
||||||
|
set(cell, Terrain.EMPTY_SP, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//builder.findneighbnours
|
set(entrance(), Terrain.EMPTY, this);
|
||||||
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] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Room n : rooms){
|
|
||||||
for (Room p : n.neigbours){
|
|
||||||
if (p.height() > 10){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (n.height() > 10){
|
|
||||||
if (n.canConnect(p)){
|
|
||||||
if (n.bottom == p.top){
|
|
||||||
n.connect(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (n.canConnect(p)) {
|
|
||||||
n.connect(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Painter.placedoors
|
|
||||||
for (Room r : rooms){
|
|
||||||
for (Room n : r.connected.keySet()) {
|
|
||||||
Room.Door door = r.connected.get( n );
|
|
||||||
if (door == null) {
|
|
||||||
|
|
||||||
Rect i = r.intersect( n );
|
|
||||||
ArrayList<Point> doorSpots = new ArrayList<>();
|
|
||||||
for (Point p : i.getPoints()){
|
|
||||||
if (r.canConnect(p) && n.canConnect(p))
|
|
||||||
doorSpots.add(p);
|
|
||||||
}
|
|
||||||
if (doorSpots.isEmpty()){
|
|
||||||
ShatteredPixelDungeon.reportException(
|
|
||||||
new RuntimeException("Could not place a door! " +
|
|
||||||
"r=" + r.getClass().getSimpleName() +
|
|
||||||
" n=" + n.getClass().getSimpleName()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
door = new Room.Door(Random.element(doorSpots));
|
|
||||||
|
|
||||||
r.connected.put( n, door );
|
|
||||||
n.connected.put( r, door );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Room n : rooms){
|
|
||||||
n.paint(this);
|
|
||||||
if (n instanceof RegionDecoLineRoom){
|
|
||||||
Painter.fill(this, n, 1, Terrain.EMPTY_SP);
|
|
||||||
Painter.fill(this, n.left+1, n.top+1, 7, 1, Terrain.REGION_DECO_ALT);
|
|
||||||
Painter.fill(this, n.left+1, n.top+1, 1, 14, Terrain.REGION_DECO_ALT);
|
|
||||||
Painter.fill(this, n.right-1, n.top+1, 1, 14, Terrain.REGION_DECO_ALT);
|
|
||||||
}
|
|
||||||
for (Point door : n.connected.values()){
|
|
||||||
Painter.set(this, door, Terrain.DOOR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entrance = pointToCell(entryRoom.random());
|
|
||||||
transitions.add(new LevelTransition(this,
|
transitions.add(new LevelTransition(this,
|
||||||
entrance,
|
entrance(),
|
||||||
LevelTransition.Type.BRANCH_ENTRANCE,
|
LevelTransition.Type.BRANCH_ENTRANCE,
|
||||||
Dungeon.depth,
|
Dungeon.depth,
|
||||||
0,
|
0,
|
||||||
LevelTransition.Type.BRANCH_EXIT));
|
LevelTransition.Type.BRANCH_EXIT));
|
||||||
|
|
||||||
rooms.remove(entryRoom);
|
|
||||||
rooms.remove(finalRoom);
|
|
||||||
|
|
||||||
for (Room n : rooms){
|
|
||||||
if (Random.Int(5) != 0){
|
|
||||||
Item item = Generator.randomUsingDefaults(Random.oneOf(
|
|
||||||
Generator.Category.WEAPON, Generator.Category.WEAPON,
|
|
||||||
Generator.Category.ARMOR,
|
|
||||||
Generator.Category.WAND,
|
|
||||||
Generator.Category.RING));
|
|
||||||
|
|
||||||
//regrowth is disallowed as it can be used to farm HP regen
|
|
||||||
if (item instanceof WandOfRegrowth){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos;
|
|
||||||
do {
|
|
||||||
pos = pointToCell(n.random());
|
|
||||||
} while (map[pos] != Terrain.EMPTY);
|
|
||||||
if (item.cursed){
|
|
||||||
item.cursed = false;
|
|
||||||
if (item instanceof MeleeWeapon && ((MeleeWeapon) item).hasCurseEnchant()){
|
|
||||||
((MeleeWeapon) item).enchant(null);
|
|
||||||
} else if (item instanceof Armor && ((Armor) item).hasCurseGlyph()){
|
|
||||||
((Armor) item).inscribe(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.identify();
|
|
||||||
drop(item, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,9 +163,29 @@ public class VaultLevel extends Level { //for now
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createItems() {
|
protected void createItems() {
|
||||||
//do nothing for now
|
//copypasta from super.createItems
|
||||||
|
for (Item item : itemsToSpawn) {
|
||||||
|
int cell = randomDropCell();
|
||||||
|
if (item instanceof TrinketCatalyst){
|
||||||
|
drop( item, cell ).type = Heap.Type.LOCKED_CHEST;
|
||||||
|
int keyCell = randomDropCell();
|
||||||
|
drop( new GoldenKey(Dungeon.depth), keyCell ).type = Heap.Type.HEAP;
|
||||||
|
if (map[keyCell] == Terrain.HIGH_GRASS || map[keyCell] == Terrain.FURROWED_GRASS) {
|
||||||
|
map[keyCell] = Terrain.GRASS;
|
||||||
|
losBlocking[keyCell] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drop( item, cell ).type = Heap.Type.HEAP;
|
||||||
|
}
|
||||||
|
if (map[cell] == Terrain.HIGH_GRASS || map[cell] == Terrain.FURROWED_GRASS) {
|
||||||
|
map[cell] = Terrain.GRASS;
|
||||||
|
losBlocking[cell] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO createItems will generate normal ones too =S
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int randomRespawnCell( Char ch ) {
|
public int randomRespawnCell( Char ch ) {
|
||||||
return entrance()-width();
|
return entrance()-width();
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2025 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.levels.builders;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
|
||||||
|
import com.watabou.utils.Random;
|
||||||
|
import com.watabou.utils.SparseArray;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
//a builder with static room sizes aligned to a grid
|
||||||
|
//TODO extend regular builder?
|
||||||
|
public class GridBuilder extends Builder {
|
||||||
|
|
||||||
|
public static int ROOM_SIZE = 9;
|
||||||
|
|
||||||
|
//each adjacency is processed twice, so this gives a ~50% chance to connect two adjacent rooms
|
||||||
|
protected float extraConnectionChance = 0.30f;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayList<Room> build(ArrayList<Room> rooms) {
|
||||||
|
for(Room r : rooms){
|
||||||
|
r.setEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Room entrance = null;
|
||||||
|
Room exit = null;
|
||||||
|
|
||||||
|
for (Room r : rooms){
|
||||||
|
if (r.isEntrance()){
|
||||||
|
entrance = r;
|
||||||
|
} else if (r.isExit()){
|
||||||
|
exit = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entrance.forceSize(ROOM_SIZE, ROOM_SIZE)){
|
||||||
|
throw new RuntimeException("rigid room sizes for now!");
|
||||||
|
}
|
||||||
|
entrance.setPos(0, 0);
|
||||||
|
|
||||||
|
ArrayList<Room> toPlace = new ArrayList<>(rooms);
|
||||||
|
toPlace.remove(entrance);
|
||||||
|
|
||||||
|
ArrayList<Room> placed = new ArrayList<>();
|
||||||
|
placed.add(entrance);
|
||||||
|
|
||||||
|
//use a sparse array to track room positions, with a mapping of x + 1000*y = cell
|
||||||
|
//this assumes that levels won't more than 1000 rooms wide
|
||||||
|
SparseArray<Room> gridCells = new SparseArray<>();
|
||||||
|
gridCells.put(0, entrance);
|
||||||
|
|
||||||
|
for (Room r : toPlace){
|
||||||
|
if (!r.forceSize(ROOM_SIZE, ROOM_SIZE)){
|
||||||
|
throw new RuntimeException("rigid room sizes for now!");
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
Room n = Random.element(placed);
|
||||||
|
int nIdx = gridCells.findKey(n, true, Integer.MIN_VALUE);
|
||||||
|
int rIdx = nIdx;
|
||||||
|
switch (Random.Int(4)){
|
||||||
|
case 0:
|
||||||
|
rIdx += 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rIdx += 1000;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rIdx -= 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rIdx -= 1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//TODO negatives
|
||||||
|
int x = rIdx%1000;
|
||||||
|
int y = rIdx/1000;
|
||||||
|
r.setPos(x*(ROOM_SIZE-1), y*(ROOM_SIZE-1));
|
||||||
|
//TODO want to manually limit size probably
|
||||||
|
if (x >= 0 && y >= 0 && !gridCells.containsKey(rIdx)){
|
||||||
|
if (r.connect(n)) {
|
||||||
|
placed.add(r);
|
||||||
|
gridCells.put(rIdx, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!placed.contains(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
//need a buffer room?
|
||||||
|
//contains an internal room, fills with
|
||||||
|
|
||||||
|
findNeighbours(rooms);
|
||||||
|
|
||||||
|
for (Room r : rooms){
|
||||||
|
for (Room n : r.neigbours){
|
||||||
|
if (!n.connected.containsKey(r)
|
||||||
|
&& Random.Float() < extraConnectionChance){
|
||||||
|
r.connect(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.PetrifiedSeed;
|
|||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.VaultLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
|
|
||||||
@@ -118,6 +119,11 @@ public class HighGrass {
|
|||||||
&& Random.Int(3) != 0){
|
&& Random.Int(3) != 0){
|
||||||
naturalismLevel = -1;
|
naturalismLevel = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//grass gives no loot in vault tester area
|
||||||
|
if (Dungeon.level instanceof VaultLevel){
|
||||||
|
naturalismLevel = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (naturalismLevel >= 0) {
|
if (naturalismLevel >= 0) {
|
||||||
// Seed, scales from 1/25 to 1/9
|
// Seed, scales from 1/25 to 1/9
|
||||||
|
|||||||
Reference in New Issue
Block a user