v2.1.0: added a basic UI for shopkeeper interaction, with buyback!

This commit is contained in:
Evan Debenham
2023-05-04 17:44:17 -04:00
parent 1879a762dd
commit 070b380b8a
3 changed files with 144 additions and 12 deletions

View File

@@ -978,7 +978,8 @@ actors.mobs.npcs.impshopkeeper.name=ambitious imp
actors.mobs.npcs.impshopkeeper.greetings=Hello, %s!
actors.mobs.npcs.impshopkeeper.greetings_ascent=What did you do %s? Shop quickly, I've got to get out of here!
actors.mobs.npcs.impshopkeeper.thief=I thought I could trust you!
actors.mobs.npcs.impshopkeeper.desc=Imps are lesser demons. They are notable for neither their strength nor their magic talent. But they are quite smart and sociable, and many of imps prefer to live and do business among non-demons.
actors.mobs.npcs.impshopkeeper.buyback=The imp cheerily returns your item.
actors.mobs.npcs.impshopkeeper.desc=The imp has set up a little shop on the border of the inner halls. It's nice to see a friendly face, but his prices certainly don't seem friendly.
actors.mobs.npcs.mirrorimage.name=mirror image
actors.mobs.npcs.mirrorimage.desc=This illusion bears a close resemblance to you, even seeming to wield your current weapon and armor.\n\nMirror images will seek and attack enemies using their mimicked weapon, which behaves the same as yours, but deals less damage. They start out nearly invisible, but must take on a form that's more easily seen in order to attack.\n\nWhile their offensive power can be potent, mirror images have no durability, and will fade the moment they take damage.
@@ -1012,6 +1013,13 @@ actors.mobs.npcs.sheep.desc=This is a magic sheep. What's so magical about it? Y
actors.mobs.npcs.shopkeeper.name=shopkeeper
actors.mobs.npcs.shopkeeper.thief=Thief, Thief!
actors.mobs.npcs.shopkeeper.sell=Sell an item
actors.mobs.npcs.shopkeeper.talk=Talk
actors.mobs.npcs.shopkeeper.buyback=The shopkeeper reluctantly returns your item.
actors.mobs.npcs.shopkeeper.talk_prison="I have everything you need for a successful adventure!"
actors.mobs.npcs.shopkeeper.talk_caves="Spend money, live longer."
actors.mobs.npcs.shopkeeper.talk_city="My wares can keep you safe down here."
actors.mobs.npcs.shopkeeper.talk_halls="Hey there, I've got special prices for demon hunters!"
actors.mobs.npcs.shopkeeper.talk_ascent="I don't know what you're planning to do with that amulet but I want no part of it. Buy something and move on, we both need to leave this place!"
actors.mobs.npcs.shopkeeper.desc=This stout guy looks more appropriate for a trade district in some large city than for a dungeon. His prices explain why he prefers to do business here.
actors.mobs.npcs.wandmaker.name=old wandmaker

View File

@@ -35,12 +35,21 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ShopkeeperSprite;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndTitledMessage;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndTradeItem;
import com.watabou.noosa.Game;
import com.watabou.noosa.Image;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
import com.watabou.utils.Callback;
import java.util.ArrayList;
public class Shopkeeper extends NPC {
{
@@ -48,6 +57,9 @@ public class Shopkeeper extends NPC {
properties.add(Property.IMMOVABLE);
}
public static int MAX_BUYBACK_HISTORY = 3;
public ArrayList<Item> buybackItems = new ArrayList<>();
@Override
protected boolean act() {
@@ -56,11 +68,7 @@ public class Shopkeeper extends NPC {
Notes.add(Notes.Landmark.SHOP);
}
/*if (Statistics.highestAscent < 20 && Dungeon.hero.buff(AscensionChallenge.class) != null){
flee();
return true;
}*/
sprite.turnTo( pos, Dungeon.hero.pos );
spend( TICK );
return super.act();
@@ -159,9 +167,91 @@ public class Shopkeeper extends NPC {
Game.runOnRenderThread(new Callback() {
@Override
public void call() {
sell();
String[] options = new String[2+ buybackItems.size()];
int i = 0;
options[i++] = Messages.get(Shopkeeper.this, "sell");
options[i++] = Messages.get(Shopkeeper.this, "talk");
for (Item item : buybackItems){
options[i++] = Messages.get(Heap.class, "for_sale", item.value(), Messages.titleCase(item.title()));
}
GameScene.show(new WndOptions(sprite(), Messages.titleCase(name()), description(), options){
@Override
protected void onSelect(int index) {
super.onSelect(index);
if (index == 0){
sell();
} else if (index == 1){
GameScene.show(new WndTitledMessage(sprite(), Messages.titleCase(name()), chatText()));
} else if (index > 1){
GLog.i(Messages.get(Shopkeeper.this, "buyback"));
Item returned = buybackItems.remove(index-2);
Dungeon.gold -= returned.value();
Statistics.goldCollected -= returned.value();
if (!returned.doPickUp(Dungeon.hero)){
Dungeon.level.drop(returned, Dungeon.hero.pos);
}
}
}
@Override
protected boolean enabled(int index) {
if (index > 1){
return Dungeon.gold >= buybackItems.get(index-2).value();
} else {
return super.enabled(index);
}
}
@Override
protected boolean hasIcon(int index) {
return index > 1;
}
@Override
protected Image getIcon(int index) {
if (index > 1){
return new ItemSprite(buybackItems.get(index-2));
}
return null;
}
});
}
});
return true;
}
public String chatText(){
if (Dungeon.hero.buff(AscensionChallenge.class) != null){
return Messages.get(this, "talk_ascent");
}
switch (Dungeon.depth){
case 6: default:
return Messages.get(this, "talk_prison");
case 11:
return Messages.get(this, "talk_caves");
case 16:
return Messages.get(this, "talk_city");
case 20:
return Messages.get(this, "talk_halls");
}
}
public static String BUYBACK_ITEMS = "buyback_items";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(BUYBACK_ITEMS, buybackItems);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
buybackItems.clear();
if (bundle.contains(BUYBACK_ITEMS)){
for (Bundlable i : bundle.getCollection(BUYBACK_ITEMS)){
buybackItems.add((Item) i);
}
}
}
}

View File

@@ -22,6 +22,8 @@
package com.shatteredpixel.shatteredpixeldungeon.windows;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper;
@@ -55,12 +57,22 @@ public class WndTradeItem extends WndInfoItem {
float pos = height;
//find the shopkeeper in the current level
Shopkeeper shop = null;
for (Char ch : Actor.chars()){
if (ch instanceof Shopkeeper){
shop = (Shopkeeper) ch;
break;
}
}
final Shopkeeper finalShop = shop;
if (item.quantity() == 1) {
RedButton btnSell = new RedButton( Messages.get(this, "sell", item.value()) ) {
@Override
protected void onClick() {
sell( item );
sell( item, finalShop);
hide();
}
};
@@ -76,7 +88,7 @@ public class WndTradeItem extends WndInfoItem {
RedButton btnSell1 = new RedButton( Messages.get(this, "sell_1", priceAll / item.quantity()) ) {
@Override
protected void onClick() {
sellOne( item );
sellOne( item, finalShop );
hide();
}
};
@@ -86,7 +98,7 @@ public class WndTradeItem extends WndInfoItem {
RedButton btnSellAll = new RedButton( Messages.get(this, "sell_all", priceAll ) ) {
@Override
protected void onClick() {
sell( item );
sell( item, finalShop );
hide();
}
};
@@ -176,8 +188,12 @@ public class WndTradeItem extends WndInfoItem {
}
if (selling) Shopkeeper.sell();
}
public static void sell( Item item ) {
sell(item, null);
}
public static void sell( Item item, Shopkeeper shop ) {
Hero hero = Dungeon.hero;
@@ -190,12 +206,23 @@ public class WndTradeItem extends WndInfoItem {
hero.spend(-hero.cooldown());
new Gold( item.value() ).doPickUp( hero );
if (shop != null){
shop.buybackItems.add(item);
while (shop.buybackItems.size() > Shopkeeper.MAX_BUYBACK_HISTORY){
shop.buybackItems.remove(0);
}
}
}
public static void sellOne( Item item ) {
sellOne( item, null );
}
public static void sellOne( Item item, Shopkeeper shop ) {
if (item.quantity() <= 1) {
sell( item );
sell( item, shop );
} else {
Hero hero = Dungeon.hero;
@@ -206,6 +233,13 @@ public class WndTradeItem extends WndInfoItem {
hero.spend(-hero.cooldown());
new Gold( item.value() ).doPickUp( hero );
if (shop != null){
shop.buybackItems.add(item);
while (shop.buybackItems.size() > Shopkeeper.MAX_BUYBACK_HISTORY){
shop.buybackItems.remove(0);
}
}
}
}