Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive Shop Dialogs #740

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/games/stendhal/server/actions/CommandCenter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand Down Expand Up @@ -133,6 +133,7 @@ private static void registerActions() {
WhoAction.register();
register("info", new InfoAction());
register("markscroll", new MarkScrollAction());
register("shop_inventory", new ShopInventoryAction());
}

/**
Expand Down
61 changes: 61 additions & 0 deletions src/games/stendhal/server/actions/ShopInventoryAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/***************************************************************************
* Copyright © 2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
package games.stendhal.server.actions;

import org.apache.log4j.Logger;

import games.stendhal.server.entity.npc.MerchantNPC;
import games.stendhal.server.entity.npc.NPCList;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.shop.ShopType;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.events.ShopInventoryEvent;
import marauroa.common.game.RPAction;


/**
* Action for requesting an NPC's shop inventory.
*/
public class ShopInventoryAction implements ActionListener {

private static Logger logger = Logger.getLogger(ShopInventoryAction.class);


@Override
public void onAction(final Player player, final RPAction action) {
if (!action.has("npc")) {
logger.error("NPC name must be specified");
return;
}
if (!action.has("type")) {
logger.error("Shop type must be specified");
return;
}

final String typeName = action.get("type");
final ShopType type = ShopType.fromString(typeName);
if (type == null) {
logger.error("Unrecognized shop type \"" + typeName + "\"");
return;
}

final String npcName = action.get("npc");
final SpeakerNPC npc = NPCList.get().get(npcName);
if (npc == null || !(npc instanceof MerchantNPC)) {
logger.error("Unrecognized merchant NPC \"" + npcName + "\"");
return;
}

player.addEvent(new ShopInventoryEvent((MerchantNPC) npc, type));
player.notifyWorldAboutChanges();
}
}
5 changes: 5 additions & 0 deletions src/games/stendhal/server/core/engine/RPClassGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
import games.stendhal.server.events.PrivateTextEvent;
import games.stendhal.server.events.ProgressStatusEvent;
import games.stendhal.server.events.ReachedAchievementEvent;
import games.stendhal.server.events.ShopInventoryEvent;
import games.stendhal.server.events.ShowItemListEvent;
import games.stendhal.server.events.ShowOutfitListEvent;
import games.stendhal.server.events.SoundEvent;
Expand Down Expand Up @@ -349,6 +350,10 @@ public void createRPClassesWithoutBaking() {
BestiaryEvent.generateRPClass();
}

// shops
if (!RPClass.hasRPClass("shop_inventory")) {
ShopInventoryEvent.generateRPClass();
}
if (!RPClass.hasRPClass(Events.OUTFIT_LIST)) {
ShowOutfitListEvent.generateRPClass();
}
Expand Down
84 changes: 84 additions & 0 deletions src/games/stendhal/server/entity/npc/MerchantNPC.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/***************************************************************************
* Copyright © 2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
package games.stendhal.server.entity.npc;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import games.stendhal.server.entity.npc.shop.OutfitShopsList;
import games.stendhal.server.entity.npc.shop.ShopInventory;
import games.stendhal.server.entity.npc.shop.ShopType;
import games.stendhal.server.entity.npc.shop.ShopsList;


/**
* An NPC that manages one or more shops.
*/
public class MerchantNPC extends SpeakerNPC {

/** Shops that this NPC manages. */
private final Map<ShopType, String> shops;


/**
* Creates a new shopkeeper.
*
* @param name
* NPC's name.
*/
public MerchantNPC(final String name) {
super(name);
shops = new HashMap<>();
}

/**
* Adds a shop to this NPC.
*
* @param type
* Shop type (buy, sell, outfit).
* @param name
* Shop name identifier used to retrieve inventory from shops list.
*/
public void addShop(final ShopType type, final String name) {
shops.put(type, name);
}

/**
* Retrieves NPC's shop inventory list.
*
* @param type
* Shop type (buy, sell, outfit).
* @return
* Shop inventory or `null` if NPC does not support shop type.
*/
public ShopInventory<?, ?> getInventory(final ShopType type) {
final String name = shops.get(type);
if (name == null) {
return null;
}
if (ShopType.OUTFIT.equals(type)) {
return OutfitShopsList.get().get(name);
}
return ShopsList.get().get(name, type);
}

/**
* Retrieves shop types supported by this NPC.
*
* @return
* List of available shop types.
*/
public Set<ShopType> getShopTypes() {
return shops.keySet();
}
}
15 changes: 14 additions & 1 deletion src/games/stendhal/server/entity/npc/shop/ItemShopInventory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/***************************************************************************
* (C) Copyright 2023 - Stendhal *
* Copyright © 2023-2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -44,4 +45,16 @@ public void addTradeFor(final String name, final String required, final int coun
put(name, 0);
}
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
for (final String name: keySet()) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(name + ":" + get(name));
}
return getShopType().toString() + "(" + sb.toString() + ")";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/***************************************************************************
* (C) Copyright 2023 - Stendhal *
* Copyright © 2023-2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -117,4 +118,17 @@ public void addTradeFor(final String name, final String required, final int coun
}
super.addTradeFor(name, required, count);
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
for (final String name: keySet()) {
if (sb.length() > 0) {
sb.append(",");
}
final Pair<String, Integer> p = get(name);
sb.append("name=" + name + "," + p.first() + ":" + p.second());
}
return getShopType().toString() + "(" + sb.toString() + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.apache.log4j.Logger;

import games.stendhal.server.entity.npc.MerchantNPC;
import games.stendhal.server.entity.npc.NPCList;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.behaviour.adder.OutfitChangerAdder;
Expand Down Expand Up @@ -164,6 +165,11 @@ public void putOnOutfit(final Player player, final String oname) {
}
new OutfitChangerAdder().addOutfitChanger(npc, behaviour, action, !fl.containsKey("noOffer"),
fl.containsKey("returnable"));

if (npc instanceof MerchantNPC) {
// register with merchant NPC for retrieving shop inventory for interactive dialogs
((MerchantNPC) npc).addShop(ShopType.OUTFIT, name);
}
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/games/stendhal/server/entity/npc/shop/ShopInventory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/***************************************************************************
* (C) Copyright 2023 - Stendhal *
* Copyright © 2023-2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -84,4 +85,7 @@ public void addTradeFor(final String name, final String required, final int coun
temp.add(new Pair<>(required, count));
tradeFor.put(name, temp);
}

@Override
public abstract String toString();
}
8 changes: 7 additions & 1 deletion src/games/stendhal/server/entity/npc/shop/ShopsList.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
* (C) Copyright 2003-2023 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand All @@ -17,6 +17,7 @@
import org.apache.log4j.Logger;

import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.entity.npc.MerchantNPC;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.behaviour.adder.BuyerAdder;
import games.stendhal.server.entity.npc.behaviour.adder.SellerAdder;
Expand Down Expand Up @@ -205,6 +206,11 @@ public void configureNPC(final SpeakerNPC npc, final String shopname, final Shop
} else {
new BuyerAdder().addBuyer(npc, new BuyerBehaviour(inventory, priceFactor), offer);
}

if (npc instanceof MerchantNPC) {
// register with merchant NPC for retrieving shop inventory for interactive dialogs
((MerchantNPC) npc).addShop(stype, shopname);
}
}

/**
Expand Down
51 changes: 51 additions & 0 deletions src/games/stendhal/server/events/ShopInventoryEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/***************************************************************************
* Copyright © 2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
package games.stendhal.server.events;

import org.apache.log4j.Logger;

import games.stendhal.server.entity.npc.MerchantNPC;
import games.stendhal.server.entity.npc.shop.ShopInventory;
import games.stendhal.server.entity.npc.shop.ShopType;
import marauroa.common.game.Definition.Type;
import marauroa.common.game.RPClass;
import marauroa.common.game.RPEvent;


/**
* Event that retrieves an NPC's shop inventory.
*/
public class ShopInventoryEvent extends RPEvent {

private static Logger logger = Logger.getLogger(ShopInventoryEvent.class);


public static void generateRPClass() {
final RPClass rpclass = new RPClass("shop_inventory");
rpclass.addAttribute("type", Type.STRING);
rpclass.addAttribute("contents", Type.STRING);
}

public ShopInventoryEvent(final MerchantNPC npc, final ShopType type) {
final ShopInventory<?, ?> inv = npc.getInventory(type);
if (inv == null) {
logger.warn("Shop type " + type.toString() + " does not exist for NPC " + npc.getName());
return;
}
put("type", type.toString());
put("contents", buildInventoryList(inv));
}

private String buildInventoryList(final ShopInventory<?, ?> inv) {
return inv.toString().split("(")[1].split(")")[0];
}
}
Loading