v0.6.0: refactored shop rooms and the imp's shop

Imp's shop now spawns even if floor 21 is visited
This commit is contained in:
Evan Debenham 2017-04-18 00:15:50 -04:00 committed by Evan Debenham
parent b0456bd505
commit 85d9c94f93
6 changed files with 206 additions and 127 deletions

View File

@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.ShopRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ExitRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.FissureRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.ImpShopRoom;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.watabou.noosa.Group;
import com.watabou.utils.Random;
@ -61,14 +62,9 @@ public class LastShopLevel extends RegularLevel {
ArrayList<Room> rooms = new ArrayList<>();
rooms.add ( roomEntrance = new EntranceRoom());
rooms.add( new ImpShopRoom() );
rooms.add( roomExit = new ExitRoom());
if (Imp.Quest.isCompleted()){
rooms.add( new ShopRoom() );
} else {
rooms.add( new FissureRoom() );
}
return rooms;
}

View File

@ -397,6 +397,7 @@ public abstract class RegularLevel extends Level {
rooms = new ArrayList<>( (Collection<Room>) ((Collection<?>) bundle.getCollection( "rooms" )) );
for (Room r : rooms) {
r.onLevelLoad( this );
if (r instanceof EntranceRoom || r.legacyType.equals("ENTRANCE")){
roomEntrance = r;
} else if (r instanceof ExitRoom || r.legacyType.equals("EXIT")){

View File

@ -157,7 +157,8 @@ public class LegacyBuilder extends Builder {
connected.add( or );
}
}
/*
if (Dungeon.shopOnLevel()) {
Room shop = null;
for (Room r : roomEntrance.connected.keySet()) {
@ -176,7 +177,7 @@ public class LegacyBuilder extends Builder {
}
}
/*
specials = new ArrayList<>( SpecialRoom.SPECIALS );
if (Dungeon.bossLevel( Dungeon.depth + 1 )) {
specials.remove( WeakFloorRoom.class );

View File

@ -298,6 +298,11 @@ public class Room extends Rect implements Graph.Node, Bundlable {
if (bundle.contains( "type" ))
legacyType = bundle.getString( "type" );
}
//Note that currently connections and neighbours are not preserved on load
public void onLevelLoad( Level level ){
//does nothing by default
}
public static class Door extends Point {

View File

@ -41,6 +41,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.MailArmor;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.PlateArmor;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.ScaleArmor;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.PotionBandolier;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.ScrollHolder;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.SeedPouch;
@ -81,26 +82,17 @@ import java.util.Collections;
public class ShopRoom extends SpecialRoom {
private static int pasWidth;
private static int pasHeight;
private static ArrayList<Item> itemsToSpawn;
private ArrayList<Item> itemsToSpawn;
@Override
public int minWidth() {
if (itemsToSpawn == null) generateItems();
if (itemsToSpawn == null) itemsToSpawn = generateItems();
return Math.max(7, (int)(Math.sqrt(itemsToSpawn.size())+3));
}
//FIXME this is messy, the floor 21 shop should probably just be its own class.
@Override
public int maxConnections(int direction) {
return Dungeon.depth == 21 ? 2 : 1;
}
@Override
public int minHeight() {
if (itemsToSpawn == null) generateItems();
if (itemsToSpawn == null) itemsToSpawn = generateItems();
return Math.max(7, (int)(Math.sqrt(itemsToSpawn.size())+3));
}
@ -108,43 +100,71 @@ public class ShopRoom extends SpecialRoom {
Painter.fill( level, this, Terrain.WALL );
Painter.fill( level, this, 1, Terrain.EMPTY_SP );
pasWidth = width() - 3;
pasHeight = height() - 3;
int per = pasWidth * 2 + pasHeight * 2;
if (itemsToSpawn == null)
generateItems();
int pos = xy2p( this, entrance() ) + (per - itemsToSpawn.size()) / 2;
for (Item item : itemsToSpawn) {
Point xy = p2xy( this, (pos + per) % per );
int cell = xy.x + xy.y * level.width();
if (level.heaps.get( cell ) != null) {
do {
cell = level.pointToCell(random());
} while (level.heaps.get( cell ) != null);
}
level.drop( item, cell ).type = Heap.Type.FOR_SALE;
pos++;
}
placeShopkeeper( level, this );
placeShopkeeper( level );
placeItems( level );
for (Door door : connected.values()) {
door.set( Door.Type.REGULAR );
}
itemsToSpawn = null;
}
protected void placeShopkeeper( Level level ) {
int pos = level.pointToCell(center());
Mob shopkeeper = new Shopkeeper();
shopkeeper.pos = pos;
level.mobs.add( shopkeeper );
}
protected void placeItems( Level level ){
if (itemsToSpawn == null)
itemsToSpawn = generateItems();
Point itemPlacement = new Point(entrance());
if (itemPlacement.y == top){
itemPlacement.y++;
} else if (itemPlacement.y == bottom) {
itemPlacement.y--;
} else if (itemPlacement.x == left){
itemPlacement.x++;
} else {
itemPlacement.x--;
}
for (Item item : itemsToSpawn) {
if (itemPlacement.x == left+1 && itemPlacement.y != top+1){
itemPlacement.y--;
} else if (itemPlacement.y == top+1 && itemPlacement.x != right-1){
itemPlacement.x++;
} else if (itemPlacement.x == right-1 && itemPlacement.y != bottom-1){
itemPlacement.y++;
} else {
itemPlacement.x--;
}
int cell = level.pointToCell(itemPlacement);
if (level.heaps.get( cell ) != null) {
do {
cell = level.pointToCell(random());
} while (level.heaps.get( cell ) != null || level.findMob( cell ) != null);
}
level.drop( item, cell ).type = Heap.Type.FOR_SALE;
}
}
private static void generateItems() {
protected static ArrayList<Item> generateItems() {
itemsToSpawn = new ArrayList<Item>();
ArrayList<Item> itemsToSpawn = new ArrayList<>();
switch (Dungeon.depth) {
case 6:
@ -185,7 +205,7 @@ public class ShopRoom extends SpecialRoom {
itemsToSpawn.add( new MerchantsBeacon() );
ChooseBag(Dungeon.hero.belongings);
itemsToSpawn.add(ChooseBag(Dungeon.hero.belongings));
itemsToSpawn.add( new PotionOfHealing() );
@ -275,9 +295,10 @@ public class ShopRoom extends SpecialRoom {
throw new RuntimeException("Shop attempted to carry more than 63 items!");
Random.shuffle(itemsToSpawn);
return itemsToSpawn;
}
private static void ChooseBag(Belongings pack){
protected static Bag ChooseBag(Belongings pack){
int seeds = 0, scrolls = 0, potions = 0, wands = 0;
@ -297,92 +318,22 @@ public class ShopRoom extends SpecialRoom {
//note that the order here gives a perference if counts are otherwise equal
if (seeds >= scrolls && seeds >= potions && seeds >= wands && !Dungeon.limitedDrops.seedBag.dropped()) {
Dungeon.limitedDrops.seedBag.drop();
itemsToSpawn.add( new SeedPouch() );
return new SeedPouch();
} else if (scrolls >= potions && scrolls >= wands && !Dungeon.limitedDrops.scrollBag.dropped()) {
Dungeon.limitedDrops.scrollBag.drop();
itemsToSpawn.add( new ScrollHolder() );
return new ScrollHolder();
} else if (potions >= wands && !Dungeon.limitedDrops.potionBag.dropped()) {
Dungeon.limitedDrops.potionBag.drop();
itemsToSpawn.add( new PotionBandolier() );
return new PotionBandolier();
} else if (!Dungeon.limitedDrops.wandBag.dropped()) {
Dungeon.limitedDrops.wandBag.drop();
itemsToSpawn.add(new WandHolster());
return new WandHolster();
}
return null;
}
public static int spaceNeeded(){
if (itemsToSpawn == null)
generateItems();
//plus one for the shopkeeper
return itemsToSpawn.size() + 1;
}
private static void placeShopkeeper( Level level, Room room ) {
int pos;
do {
pos = level.pointToCell(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 < PathFinder.NEIGHBOURS9.length; i++) {
int p = shopkeeper.pos + PathFinder.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)) );
}
}
}

View File

@ -0,0 +1,125 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2017 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.rooms.standard;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.ImpShopkeeper;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper;
import com.shatteredpixel.shatteredpixeldungeon.levels.LastShopLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.ShopRoom;
import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder;
//shops probably shouldn't extend special room, because of cases like this.
public class ImpShopRoom extends ShopRoom {
private boolean impSpawned = false;
//force a certain size here to guarantee enough room for 48 items, and the same center space
@Override
public int minWidth() {
return 9;
}
public int minHeight() {
return 9;
}
public int maxWidth() { return 9; }
public int maxHeight() { return 9; }
@Override
public int maxConnections(int direction) {
return 2;
}
@Override
public void paint(Level level) {
Painter.fill( level, this, Terrain.WALL );
Painter.fill( level, this, 1, Terrain.EMPTY_SP );
Painter.fill( level, this, 3, Terrain.WATER);
for (Door door : connected.values()) {
door.set( Door.Type.REGULAR );
}
if (Imp.Quest.isCompleted()){
impSpawned = true;
placeItems(level);
placeShopkeeper(level);
} else {
impSpawned = false;
}
}
@Override
protected void placeShopkeeper(Level level) {
int pos = level.pointToCell(center());
Mob shopkeeper = new ImpShopkeeper();
shopkeeper.pos = pos;
level.mobs.add( shopkeeper );
}
//fix for connections not being bundled normally
@Override
public Door entrance() {
return connected.isEmpty() ? new Door(left, top+2) : super.entrance();
}
private void spawnShop(Level level){
impSpawned = true;
super.paint(level);
}
private static final String IMP = "imp_spawned";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(IMP, impSpawned);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
impSpawned = bundle.getBoolean(IMP);
}
@Override
public void onLevelLoad(Level level) {
super.onLevelLoad(level);
if (Imp.Quest.isCompleted() && !impSpawned){
impSpawned = true;
placeItems(level);
placeShopkeeper(level);
}
}
}