Skip to content

Commit

Permalink
Add shift click max buy/sell to the shop trait
Browse files Browse the repository at this point in the history
  • Loading branch information
fullwall committed Apr 5, 2023
1 parent d6ffa08 commit 163499f
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 98 deletions.
8 changes: 4 additions & 4 deletions main/src/main/java/net/citizensnpcs/trait/CommandTrait.java
Expand Up @@ -97,25 +97,25 @@ private Transaction chargeCommandCosts(Player player, Hand hand) {
NPCShopAction action = null;
if (cost > 0) {
action = new MoneyAction(cost);
if (!action.take(player).isPossible()) {
if (!action.take(player, 1).isPossible()) {
sendErrorMessage(player, CommandTraitError.MISSING_MONEY, null, cost);
}
}
if (experienceCost > 0) {
action = new ExperienceAction(experienceCost);
if (!action.take(player).isPossible()) {
if (!action.take(player, 1).isPossible()) {
sendErrorMessage(player, CommandTraitError.MISSING_EXPERIENCE, null, experienceCost);
}
}
if (itemRequirements.size() > 0) {
action = new ItemAction(itemRequirements);
if (!action.take(player).isPossible()) {
if (!action.take(player, 1).isPossible()) {
ItemStack stack = itemRequirements.get(0);
sendErrorMessage(player, CommandTraitError.MISSING_ITEM, null, Util.prettyEnum(stack.getType()),
stack.getAmount());
}
}
return action == null ? Transaction.success() : action.take(player);
return action == null ? Transaction.success() : action.take(player, 1);
}

public void clearHistory(CommandTraitError which, String raw) {
Expand Down
82 changes: 47 additions & 35 deletions main/src/main/java/net/citizensnpcs/trait/ShopTrait.java
Expand Up @@ -262,8 +262,25 @@ public static class NPCShopItem implements Cloneable, Persistable {
@Persist
private ItemStack display;
@Persist
private boolean maxRepeatsOnShiftClick;
@Persist
private final List<NPCShopAction> result = Lists.newArrayList();

public List<Transaction> apply(List<NPCShopAction> actions, Function<NPCShopAction, Transaction> func) {
List<Transaction> pending = Lists.newArrayList();
for (NPCShopAction action : actions) {
Transaction take = func.apply(action);
if (!take.isPossible()) {
pending.forEach(a -> a.rollback());
return null;
} else {
take.run();
pending.add(take);
}
}
return pending;
}

private void changeAction(List<NPCShopAction> source, Function<NPCShopAction, Boolean> filter,
NPCShopAction delta) {
for (int i = 0; i < source.size(); i++) {
Expand Down Expand Up @@ -298,21 +315,6 @@ public NPCShopItem clone() {
}
}

public List<Transaction> execute(List<NPCShopAction> actions, Function<NPCShopAction, Transaction> func) {
List<Transaction> pending = Lists.newArrayList();
for (NPCShopAction action : actions) {
Transaction take = func.apply(action);
if (!take.isPossible()) {
pending.forEach(a -> a.rollback());
return null;
} else {
take.run();
pending.add(take);
}
}
return pending;
}

public ItemStack getDisplayItem(Player player) {
if (display == null)
return null;
Expand All @@ -323,12 +325,8 @@ public ItemStack getDisplayItem(Player player) {
}
if (!meta.hasLore()) {
List<String> lore = Lists.newArrayList();
if (cost.size() > 0) {
result.forEach(a -> lore.add(a.describe()));
}
if (result.size() > 0) {
result.forEach(a -> lore.add(a.describe()));
}
cost.forEach(a -> lore.add(a.describe()));
result.forEach(a -> lore.add(a.describe()));
}
if (meta.hasLore()) {
meta.setLore(Lists.transform(meta.getLore(), line -> placeholders(line, player)));
Expand All @@ -351,11 +349,22 @@ public void onClick(NPCShop shop, CitizensInventoryClickEvent event, boolean sec
placeholders(clickToConfirmMessage, (Player) event.getWhoClicked()));
return;
}
List<Transaction> take = execute(cost, action -> action.take(event.getWhoClicked()));
int max = Integer.MAX_VALUE;
if (maxRepeatsOnShiftClick && event.isShiftClick()) {
for (NPCShopAction action : cost) {
int r = action.getMaxRepeats(event.getWhoClicked());
if (r != -1) {
max = Math.min(max, r);
}
}
}
final int repeats = max == Integer.MAX_VALUE ? 1 : max;
List<Transaction> take = apply(cost, action -> action.take(event.getWhoClicked(), repeats));
if (take == null)
return;
if (execute(result, action -> action.grant(event.getWhoClicked())) == null) {
if (apply(result, action -> action.grant(event.getWhoClicked(), repeats)) == null) {
take.forEach(a -> a.rollback());
return;
}
if (clickMessage != null) {
Messaging.sendColorless(event.getWhoClicked(),
Expand Down Expand Up @@ -387,14 +396,14 @@ public static class NPCShopItemEditor extends InventoryMenuPage {
@MenuPattern(
offset = { 0, 6 },
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
value = "x x\n x \nx x")
value = "xxx\nxxx\nxxx")
private InventoryMenuPattern actionItems;
private NPCShopItem base;
private final Consumer<NPCShopItem> callback;
@MenuPattern(
offset = { 0, 0 },
slots = { @MenuSlot(pat = 'x', material = Material.AIR) },
value = "x x\n x \nx x")
value = "xxx\nxxx\nxxx")
private InventoryMenuPattern costItems;
private MenuContext ctx;
private final NPCShopItem modified;
Expand All @@ -412,7 +421,7 @@ public void initialise(MenuContext ctx) {
ctx.getSlot(9 * 4 + 4).setItemStack(modified.getDisplayItem(null));
}
ctx.getSlot(9 * 3 + 3).setItemStack(new ItemStack(Util.getFallbackMaterial("OAK_SIGN", "SIGN")),
"Set message to send on click, currently:",
"Set message to send on click, currently:\n",
modified.clickMessage == null ? "Unset" : modified.clickMessage);
ctx.getSlot(9 * 3 + 3).setClickHandler(
e -> ctx.getMenu().transition(InputMenus.stringSetter(() -> modified.clickMessage, s -> {
Expand All @@ -428,6 +437,11 @@ public void initialise(MenuContext ctx) {
modified.clickToConfirmMessage = s;
ctx.getSlot(9 * 3 + 5).setDescription(modified.clickToConfirmMessage);
})));

ctx.getSlot(9 * 3 + 4).setItemStack(new ItemStack(Material.REDSTONE),
"Sell as many times as possible on shift click\n", "Currently: " + modified.maxRepeatsOnShiftClick);
ctx.getSlot(9 * 3 + 4).setClickHandler(
InputMenus.toggler(res -> modified.maxRepeatsOnShiftClick = res, modified.maxRepeatsOnShiftClick));
int pos = 0;
for (GUI template : NPCShopAction.getGUIs()) {
if (template.createMenuItem(null) == null)
Expand Down Expand Up @@ -554,9 +568,8 @@ public NPCShopPageSettings(NPCShopPage page) {

@MenuSlot(slot = { 0, 4 }, material = Material.FEATHER, amount = 1)
public void editPageTitle(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
ctx.getMenu().transition(InputMenus.stringSetter(() -> page.title, newTitle -> {
page.title = newTitle.isEmpty() ? null : newTitle;
}));
ctx.getMenu().transition(InputMenus.stringSetter(() -> page.title,
newTitle -> page.title = newTitle.isEmpty() ? null : newTitle));
}

@Override
Expand Down Expand Up @@ -606,16 +619,15 @@ public void onPermissionChange(InventoryMenuSlot slot, CitizensInventoryClickEve

@MenuSlot(slot = { 0, 6 }, material = Material.NAME_TAG, amount = 1)
public void onSetTitle(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
ctx.getMenu().transition(InputMenus.stringSetter(() -> shop.title, newTitle -> {
shop.title = newTitle;
}));
ctx.getMenu().transition(InputMenus.stringSetter(() -> shop.title, newTitle -> shop.title = newTitle));
}

@MenuSlot(slot = { 0, 0 }, material = Material.BOOK, amount = 1, title = "<f>Edit shop type")
public void onShopTypeChange(InventoryMenuSlot slot, CitizensInventoryClickEvent event) {
ctx.getMenu().transition(InputMenus.<ShopType> picker("Edit shop type", chosen -> {
shop.type = chosen.getValue();
}, Choice.<ShopType> of(ShopType.BUY, Material.DIAMOND, "Players buy items", shop.type == ShopType.BUY),
ctx.getMenu().transition(InputMenus.<ShopType> picker("Edit shop type",
chosen -> shop.type = chosen.getValue(),
Choice.<ShopType> of(ShopType.BUY, Material.DIAMOND, "Players buy items",
shop.type == ShopType.BUY),
Choice.of(ShopType.SELL, Material.EMERALD, "Players sell items", shop.type == ShopType.SELL),
Choice.of(ShopType.COMMAND, Util.getFallbackMaterial("ENDER_EYE", "ENDER_PEARL"),
"Clicks trigger commands only", shop.type == ShopType.COMMAND)));
Expand Down
26 changes: 16 additions & 10 deletions main/src/main/java/net/citizensnpcs/trait/shop/CommandAction.java
Expand Up @@ -48,26 +48,35 @@ public String describe() {
}

@Override
public Transaction grant(Entity entity) {
public int getMaxRepeats(Entity entity) {
return -1;
}

@Override
public Transaction grant(Entity entity, int repeats) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
return Transaction.create(() -> true, () -> {
for (String command : commands) {
Util.runCommand(null, player, command, op, !server);
for (int i = 0; i < repeats; i++) {
for (String command : commands) {
Util.runCommand(null, player, command, op, !server);
}
}
}, () -> {
});
}

@Override
public Transaction take(Entity entity) {
public Transaction take(Entity entity, int repeats) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
return Transaction.create(() -> true, () -> {
for (String command : commands) {
Util.runCommand(null, player, command, op, !server);
for (int i = 0; i < repeats; i++) {
for (String command : commands) {
Util.runCommand(null, player, command, op, !server);
}
}
}, () -> {
});
Expand Down Expand Up @@ -122,10 +131,7 @@ public void initialise(MenuContext ctx) {
}
ctx.getSlot(3 * 9 + 3).setItemStack(new ItemStack(Util.getFallbackMaterial("COMMAND_BLOCK", "COMMAND")),
"Run commands as server", base.server ? ChatColor.GREEN + "On" : ChatColor.RED + "OFF");
ctx.getSlot(3 * 9 + 3).addClickHandler(InputMenus.clickToggle((res) -> {
base.server = res;
return res ? ChatColor.GREEN + "On" : ChatColor.RED + "Off";
}, base.server));
ctx.getSlot(3 * 9 + 3).addClickHandler(InputMenus.toggler((res) -> base.server = res, base.server));
ctx.getSlot(3 * 9 + 4).setItemStack(
new ItemStack(Util.getFallbackMaterial("COMPARATOR", "REDSTONE_COMPARATOR")), "Run commands as op",
base.op ? ChatColor.GREEN + "On" : ChatColor.RED + "OFF");
Expand Down
Expand Up @@ -29,30 +29,39 @@ public String describe() {
}

@Override
public Transaction grant(Entity entity) {
public int getMaxRepeats(Entity entity) {
if (!(entity instanceof Player))
return 0;
return ((Player) entity).getLevel() / exp;
}

@Override
public Transaction grant(Entity entity, int repeats) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
int amount = exp * repeats;
return Transaction.create(() -> {
return true;
}, () -> {
player.setLevel(player.getLevel() + exp);
player.setLevel(player.getLevel() + amount);
}, () -> {
player.setLevel(player.getLevel() - exp);
player.setLevel(player.getLevel() - amount);
});
}

@Override
public Transaction take(Entity entity) {
public Transaction take(Entity entity, int repeats) {
if (!(entity instanceof Player))
return Transaction.fail();
Player player = (Player) entity;
int amount = exp * repeats;
return Transaction.create(() -> {
return player.getLevel() >= exp;
return player.getLevel() >= amount;
}, () -> {
player.setLevel(player.getLevel() - exp);
player.setLevel(player.getLevel() - amount);
}, () -> {
player.setLevel(player.getLevel() + exp);
player.setLevel(player.getLevel() + amount);
});
}

Expand Down

0 comments on commit 163499f

Please sign in to comment.