v2.3.2: improved item placement logic in shops.

This improves layouts and also fixes seed problems with varying item count
This commit is contained in:
Evan Debenham
2024-01-30 16:03:04 -05:00
parent 14f4b0a38e
commit 6a05169b51
2 changed files with 73 additions and 27 deletions

View File

@@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special; package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper;
@@ -111,38 +112,88 @@ public class ShopRoom extends SpecialRoom {
itemsToSpawn = generateItems(); itemsToSpawn = generateItems();
} }
Point itemPlacement = new Point(entrance()); Point entryInset = new Point(entrance());
if (itemPlacement.y == top){ if (entryInset.y == top){
itemPlacement.y++; entryInset.y++;
} else if (itemPlacement.y == bottom) { } else if (entryInset.y == bottom) {
itemPlacement.y--; entryInset.y--;
} else if (itemPlacement.x == left){ } else if (entryInset.x == left){
itemPlacement.x++; entryInset.x++;
} else { } else {
itemPlacement.x--; entryInset.x--;
} }
for (Item item : itemsToSpawn) { Point curItemPlace = entryInset.clone();
if (itemPlacement.x == left+1 && itemPlacement.y != top+1){ int inset = 1;
itemPlacement.y--;
} else if (itemPlacement.y == top+1 && itemPlacement.x != right-1){ for (Item item : itemsToSpawn.toArray(new Item[0])) {
itemPlacement.x++;
} else if (itemPlacement.x == right-1 && itemPlacement.y != bottom-1){ //place items in a clockwise pattern
itemPlacement.y++; if (curItemPlace.x == left+inset && curItemPlace.y != top+inset){
curItemPlace.y--;
} else if (curItemPlace.y == top+inset && curItemPlace.x != right-inset){
curItemPlace.x++;
} else if (curItemPlace.x == right-inset && curItemPlace.y != bottom-inset){
curItemPlace.y++;
} else { } else {
itemPlacement.x--; curItemPlace.x--;
} }
int cell = level.pointToCell(itemPlacement); //once we get to the inset from the entrance again, move another cell inward and loop
if (curItemPlace.equals(entryInset)){
if (level.heaps.get( cell ) != null) { if (entryInset.y == top+inset){
do { entryInset.y++;
cell = level.pointToCell(random()); } else if (entryInset.y == bottom-inset){
} while (level.heaps.get( cell ) != null || level.findMob( cell ) != null); entryInset.y--;
}
if (entryInset.x == left+inset){
entryInset.x++;
} else if (entryInset.x == right-inset){
entryInset.x--;
}
inset++;
if (inset > (Math.min(width(), height())-3)/2){
break; //out of space!
}
curItemPlace = entryInset.clone();
//make sure to step forward again
if (curItemPlace.x == left+inset && curItemPlace.y != top+inset){
curItemPlace.y--;
} else if (curItemPlace.y == top+inset && curItemPlace.x != right-inset){
curItemPlace.x++;
} else if (curItemPlace.x == right-inset && curItemPlace.y != bottom-inset){
curItemPlace.y++;
} else {
curItemPlace.x--;
}
} }
int cell = level.pointToCell(curItemPlace);
level.drop( item, cell ).type = Heap.Type.FOR_SALE; level.drop( item, cell ).type = Heap.Type.FOR_SALE;
itemsToSpawn.remove(item);
}
//we didn't have enough space to place everything neatly, so now just fill in anything left
if (!itemsToSpawn.isEmpty()){
for (Point p : getPoints()){
int cell = level.pointToCell(p);
if ((level.map[cell] == Terrain.EMPTY_SP || level.map[cell] == Terrain.EMPTY)
&& level.heaps.get(cell) == null && level.findMob(cell) == null){
level.drop( itemsToSpawn.remove(0), level.pointToCell(p) ).type = Heap.Type.FOR_SALE;
}
if (itemsToSpawn.isEmpty()){
break;
}
}
}
if (!itemsToSpawn.isEmpty()){
ShatteredPixelDungeon.reportException(new RuntimeException("failed to place all items in a shop!"));
} }
} }
@@ -270,11 +321,6 @@ public class ShopRoom extends SpecialRoom {
rare.cursedKnown = true; rare.cursedKnown = true;
itemsToSpawn.add( rare ); itemsToSpawn.add( rare );
//hard limit is 63 items + 1 shopkeeper, as shops can't be bigger than 8x8=64 internally
if (itemsToSpawn.size() > 63) {
throw new RuntimeException("Shop attempted to carry more than 63 items!");
}
//use a new generator here to prevent items in shop stock affecting levelgen RNG (e.g. sandbags) //use a new generator here to prevent items in shop stock affecting levelgen RNG (e.g. sandbags)
//we can use a random long for the seed as it will be the same long every time //we can use a random long for the seed as it will be the same long every time
Random.pushGenerator(Random.Long()); Random.pushGenerator(Random.Long());

View File

@@ -91,7 +91,7 @@ public class ImpShopRoom extends ShopRoom {
//fix for connections not being bundled normally //fix for connections not being bundled normally
@Override @Override
public Door entrance() { public Door entrance() {
return connected.isEmpty() ? new Door(left, top+2) : super.entrance(); return connected.isEmpty() ? new Door((left+right)/2 + 1, bottom-1) : super.entrance();
} }
public void spawnShop(Level level){ public void spawnShop(Level level){