From 7d35101dbfa13ad95e137048370e96ef276384c8 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 24 Nov 2025 15:29:01 -0500 Subject: [PATCH] Question might work? --- .../server/questions/ShopQuestion.java | 93 ++++++++++++++++++- .../mod/treestar/shopmod/ShopService.java | 88 ++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/wurmonline/server/questions/ShopQuestion.java b/src/main/java/com/wurmonline/server/questions/ShopQuestion.java index fa7aa57..290035f 100644 --- a/src/main/java/com/wurmonline/server/questions/ShopQuestion.java +++ b/src/main/java/com/wurmonline/server/questions/ShopQuestion.java @@ -2,28 +2,115 @@ package com.wurmonline.server.questions; import com.wurmonline.server.NoSuchPlayerException; import com.wurmonline.server.Players; +import com.wurmonline.server.players.Player; import mod.treestar.shopmod.ShopService; +import mod.treestar.shopmod.datamodels.ShopCategory; +import mod.treestar.shopmod.datamodels.ShopItem; +import java.util.List; import java.util.Properties; +import java.util.stream.Collectors; public class ShopQuestion extends Question { private static final int SHOP_QUESTION_ID = 90001; private ShopService shopService; + private int selectedCategoryId = -1; public ShopQuestion(long responderId, String shopName, ShopService shopService) throws NoSuchPlayerException { super(Players.getInstance().getPlayer(responderId), shopName, null, SHOP_QUESTION_ID, responderId); this.shopService = shopService; + List categories = shopService.getCategories(); + if (!categories.isEmpty()) { + selectedCategoryId = categories.get(0).getId(); + } } @Override public void answer(Properties properties) { super.answer(properties); + List categories = shopService.getCategories(); + + // Update category selection if present + String categoryIndex = properties.getProperty("category"); + if (categoryIndex != null && !categories.isEmpty()) { + try { + int idx = Integer.parseInt(categoryIndex); + if (idx >= 0 && idx < categories.size()) { + selectedCategoryId = categories.get(idx).getId(); + } + } catch (NumberFormatException ignored) { } + } + + // If purchase not requested, refresh UI with selected category + if (!properties.containsKey("submit")) { + sendQuestion(); + return; + } + + String itemIdStr = properties.getProperty("itemid"); + if (itemIdStr == null) { + getResponder().getCommunicator().sendNormalServerMessage("No item selected."); + return; + } + int itemId; + try { + itemId = Integer.parseInt(itemIdStr); + } catch (NumberFormatException e) { + getResponder().getCommunicator().sendNormalServerMessage("Invalid item selected."); + return; + } + ShopService.PurchaseResult result = shopService.purchaseItem((Player)getResponder(), itemId); + if (result.isSuccess()) { + getResponder().getCommunicator().sendSafeServerMessage(result.getMessage()); + } else { + getResponder().getCommunicator().sendNormalServerMessage(result.getMessage()); + } } @Override public void sendQuestion() { - super.sendQuestion(); + List categories = shopService.getCategories(); + if (categories.isEmpty()) { + getResponder().getCommunicator().sendNormalServerMessage("No shop categories are available."); + return; + } + if (selectedCategoryId == -1 || categories.stream().noneMatch(c -> c.getId() == selectedCategoryId)) { + selectedCategoryId = categories.get(0).getId(); + } + int defaultCategoryIndex = 0; + for (int i = 0; i < categories.size(); i++) { + if (categories.get(i).getId() == selectedCategoryId) { + defaultCategoryIndex = i; + break; + } + } + + List items = shopService.getItems().stream() + .filter(i -> i.getCategoryId() == selectedCategoryId) + .collect(Collectors.toList()); + if (items.isEmpty()) { + getResponder().getCommunicator().sendNormalServerMessage("No shop items are available."); + return; + } + StringBuilder bml = new StringBuilder(); + bml.append("border{center{heading{text=\"").append(escape(title)).append("\"}}"); + if (categories.size() > 1) { + bml.append("harray{label{text=\"Category\"};dropdown{id=\"category\";options=\"") + .append(categories.stream().map(c -> escape(c.getName())).collect(Collectors.joining(","))) + .append("\";default=\"").append(defaultCategoryIndex).append("\"}}"); + } + bml.append("center{scroll{table{rows=\""); + for (ShopItem item : items) { + bml.append("label{text=\"").append(escape(item.getName())).append("\"};"); + bml.append("label{text=\"").append(escape(item.getDescription())).append("\"};"); + bml.append("label{text=\"").append(escape(item.getPriceDisplay())).append("\"};"); + bml.append("radio{group=\"itemid\";id=\"").append(item.getId()).append("\"};"); + } + bml.append("\"}}}"); + bml.append("harray{button{id=\"submit\";text=\"Purchase\"};button{id=\"cancel\";text=\"Cancel\"}}"); + bml.append("}"); + getResponder().getCommunicator().sendBml(400, 400, true, true, bml.toString(), 200, 200, 200, title); } public ShopService getShopService() { @@ -33,4 +120,8 @@ public class ShopQuestion extends Question { public void setShopService(ShopService shopService) { this.shopService = shopService; } + + private String escape(String value) { + return value == null ? "" : value.replace("\"", "''"); + } } diff --git a/src/main/java/mod/treestar/shopmod/ShopService.java b/src/main/java/mod/treestar/shopmod/ShopService.java index bad8a1b..825266f 100644 --- a/src/main/java/mod/treestar/shopmod/ShopService.java +++ b/src/main/java/mod/treestar/shopmod/ShopService.java @@ -1,12 +1,21 @@ package mod.treestar.shopmod; +import com.wurmonline.server.players.Player; import mod.treestar.shopmod.categoryprovider.ShopCategoryProvider; import mod.treestar.shopmod.itemprovider.ShopItemProvider; +import mod.treestar.shopmod.datamodels.ShopCategory; +import mod.treestar.shopmod.datamodels.ShopItem; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; public class ShopService { + private static final Logger logger = Logger.getLogger(ShopService.class.getName()); + private List categoryProviders = new ArrayList<>(); private List itemProviders = new ArrayList<>(); @@ -20,6 +29,59 @@ public class ShopService { itemProviders.add(provider); } + public List getCategories() { + List categories = new ArrayList<>(); + for (ShopCategoryProvider provider : categoryProviders) { + List provided = provider.getCategories(); + if (provided != null) { + categories.addAll(provided); + } + } + return categories; + } + + public List getItems() { + List items = new ArrayList<>(); + for (ShopItemProvider provider : itemProviders) { + List provided = provider.getItems(); + if (provided != null) { + items.addAll(provided); + } + } + return items; + } + + public ShopItem getItemById(int id) { + return getItems().stream().filter(i -> i.getId() == id).findFirst().orElse(null); + } + + public PurchaseResult purchaseItem(Player player, int itemId) { + ShopItem item = getItemById(itemId); + if (item == null) { + return PurchaseResult.failure("Item not found."); + } + if (item.getCurrency() == null) { + return PurchaseResult.failure("Item has no currency configured."); + } + if (item.getPurchaseHandler() == null) { + return PurchaseResult.failure("Item has no purchase handler configured."); + } + if (!item.getCurrency().canPlayerAfford(player)) { + return PurchaseResult.failure("You cannot afford this item."); + } + boolean charged = item.getCurrency().chargePlayer(player); + if (!charged) { + return PurchaseResult.failure("Charging failed; purchase canceled."); + } + try { + item.getPurchaseHandler().onPurchase(player); + return PurchaseResult.success("Purchase successful."); + } catch (Exception e) { + logger.log(Level.WARNING, "Purchase handler failed for item " + itemId + " for player " + player.getName(), e); + return PurchaseResult.failure("An error occurred while delivering the item."); + } + } + public static ShopService getInstance() { if(instance == null) { @@ -34,4 +96,30 @@ public class ShopService { public static ShopService create() { return new ShopService(); } + + public static class PurchaseResult { + private final boolean success; + private final String message; + + private PurchaseResult(boolean success, String message) { + this.success = success; + this.message = message; + } + + public static PurchaseResult success(String message) { + return new PurchaseResult(true, message); + } + + public static PurchaseResult failure(String message) { + return new PurchaseResult(false, message); + } + + public boolean isSuccess() { + return success; + } + + public String getMessage() { + return message; + } + } }