package com.asteria.game.character.player.content; import com.asteria.game.character.player.IOState; import com.asteria.game.character.player.Player; import com.asteria.game.character.player.Rights; import com.asteria.game.item.Item; import com.asteria.game.item.container.ItemContainer; import com.asteria.game.item.container.ItemContainerPolicy; /** * The container class that represents a trade session between players. * * @author lare96 <http://github.com/lare96> */ public final class TradeSession { /** * The player that controls this trade session. */ private final Player player; /** * The container of items in this trade session. */ private final ItemContainer container = new ItemContainer(28, ItemContainerPolicy.NORMAL); /** * The other player in this trade session. */ private Player other; /** * The stage that this trade session is in. */ private TradeStage stage; /** * Creates a new {@link TradeSession}. * * @param player * the player that controls this trade session. */ public TradeSession(Player player) { this.player = player; } /** * Attempts to add {@code item} from {@code inventorySlot} onto the trade * offer screen. * * @param item * the item to attempt to add to the trade. * @param inventorySlot * the inventory slot that the item is located on. */ public void add(Item item, int inventorySlot) { if (!inTradeSession()) return; if (!Item.valid(item) || !player.getInventory().contains(item.getId())) return; if (!item.getDefinition().isTradeable()) { player.getMessages().sendMessage("You cannot trade this item!"); return; } if (item.getAmount() > player.getInventory().amount(item.getId()) && !item.getDefinition().isStackable()) { item.setAmount(player.getInventory().amount(item.getId())); } else if (item.getAmount() > player.getInventory().get(inventorySlot).getAmount() && item.getDefinition().isStackable()) { item.setAmount(player.getInventory().get(inventorySlot).getAmount()); } if (container.add(item)) { player.getInventory().remove(item, inventorySlot); String trade = name(player); int remaining = player.getInventory().remaining(); other.getMessages().sendString("Trading with: " + trade + " who " + "has @gre@" + remaining + " free slots", 3417); player.getMessages().sendItemsOnInterface(3322, player.getInventory().container()); int length = container.size(); player.getMessages().sendItemsOnInterface(3415, container.container(), length); other.getMessages().sendItemsOnInterface(3416, container.container(), length); stage = TradeStage.OFFER; other.getTradeSession().setStage(TradeStage.OFFER); player.getMessages().sendString("", 3431); other.getMessages().sendString("", 3431); } } /** * Attempts to remove {@code item} from the trade offer screen. * * @param item * the item to attempt to remove from the trade. */ public void remove(Item item) { if (!inTradeSession()) return; if (!container.contains(item.getId())) return; if (item.getAmount() > container.amount(item.getId())) item.setAmount(container.amount(item.getId())); if (container.remove(item)) { player.getInventory().add(item); String trade = name(player); int remaining = player.getInventory().remaining(); other.getMessages().sendString("Trading with: " + trade + " who " + "has @gre@" + remaining + " free slots", 3417); player.getMessages().sendItemsOnInterface(3322, player.getInventory().container()); int length = container.size(); player.getMessages().sendItemsOnInterface(3415, container.container(), length); other.getMessages().sendItemsOnInterface(3416, container.container(), length); stage = TradeStage.OFFER; other.getTradeSession().stage = TradeStage.OFFER; player.getMessages().sendString("", 3431); other.getMessages().sendString("", 3431); } } /** * Attempts to initiate this trade session with {@code requester}. * * @param other * the person requesting or receiving a request for a trade * session. */ public void request(Player other) { if (other.getTradeSession().inTradeSession()) { other.getMessages().sendMessage("You are already in a trade session!"); return; } if (inTradeSession()) { other.getMessages().sendMessage("They are already in a trade session!"); return; } if (player.equals(other)) { other.getMessages().sendMessage("You cannot initiate a trade session with yourself!"); return; } if (player.equals(other.getTradeSession().getOther())) { this.other = other; other.getTradeSession().setOther(player); stage = TradeStage.OFFER; other.getTradeSession().setStage(TradeStage.OFFER); execute(TradeStage.OFFER); other.getTradeSession().execute(TradeStage.OFFER); player.facePosition(other.getPosition()); other.facePosition(player.getPosition()); return; } this.other = other; player.getMessages().sendMessage("Sending trade request..."); other.getMessages().sendMessage(player.getFormatUsername() + ":tradereq:"); player.facePosition(other.getPosition()); } /** * Executes the action that corresponds with {@code stage}. * * @param stage * the stage to execute the action for. * @throws IllegalArgumentException * if the trade stage is invalid. */ public void execute(TradeStage stage) { if (!inTradeSession()) return; switch (stage) { case OFFER: String trade = name(player); int remaining = player.getInventory().remaining(); player.getMessages().sendItemsOnInterface(3322, player.getInventory().container()); player.getMessages().sendString("Trading with: " + trade + " " + "who has @gre@" + remaining + " free slots", 3417); player.getMessages().sendString("", 3431); player.getMessages().sendString("Are you sure you want to make" + " this trade?", 3535); player.getMessages().sendInventoryInterface(3323, 3321); player.getMessages().sendItemsOnInterface(3415, null, 0); other.getMessages().sendItemsOnInterface(3416, null, 0); break; case FIRST_ACCEPT: player.getMessages().sendItemsOnInterface(3214, player.getInventory().container()); player.getMessages().sendString(getItemNames(container.container()), 3557); player.getMessages().sendString(getItemNames(other.getTradeSession().getContainer().container()), 3558); player.getMessages().sendInventoryInterface(3443, 3213); break; case FINAL_ACCEPT: if (other.getSession().getState() == IOState.LOGGED_IN && player.getSession().getState() == IOState.LOGGED_IN) { other.getInventory().addAll(container); reset(); } else { reset(false); } break; default: throw new IllegalArgumentException("Invalid trade stage!"); } } /** * Resets this trade session for both the controller and their partner. * * @param declined * determines if the trade is being reset because they declined. */ public void reset(boolean declined) { if (!inTradeSession()) return; player.getInventory().addAll(container); other.getInventory().addAll(other.getTradeSession().getContainer()); if (declined) { other.getMessages().sendMessage("The other player has declined the trade!"); player.getMessages().sendMessage("You have declined the trade."); } other.getTradeSession().reset(); reset(); } /** * Determines if this controller is in an active trade session. * * @return {@code true} if the controller is in a trade, {@code false} * otherwise. */ public boolean inTradeSession() { return stage == TradeStage.OFFER || stage == TradeStage.FIRST_ACCEPT || stage == TradeStage.FINAL_ACCEPT; } /** * Resets the trade session for the controller. */ private void reset() { if (!inTradeSession()) return; player.getMessages().sendCloseWindows(); container.clear(); stage = null; other = null; } /** * Determines and returns the trade display name for {@code player}. * * @param player * the player to determine this display name for. * @return the trade display name. */ private String name(Player player) { return player.getFormatUsername().concat( player.getRights().equal(Rights.MODERATOR) ? "@cr1@" : player.getRights().greater(Rights.MODERATOR) ? "@cr2@" : ""); } /** * Determines and returns the text for {@code items} that will be displayed * on the confirm trade screen. * * @param items * the array of items to display. * @return the confirm text for the array of items. */ private String getItemNames(Item[] items) { String tradeItems = "Absolutely nothing!"; String tradeAmount = ""; int count = 0; for (Item item : items) { if (item == null) { continue; } tradeAmount = item.getAmount() >= 1000 && item.getAmount() < 1000000 ? "@cya@" + (item.getAmount() / 1000) + "K @whi@" + "(" + item.getAmount() + ")" : item.getAmount() >= 1000000 ? "@gre@" + (item.getAmount() / 1000000) + " " + "million @whi@(" + item.getAmount() + ")" : "" + item.getAmount(); tradeItems = count == 0 ? item.getDefinition().getName() : tradeItems + "\\n" + item.getDefinition().getName(); if (item.getDefinition().isStackable()) tradeItems = tradeItems + " x " + tradeAmount; count++; } return tradeItems; } /** * Gets the player that controls this trade session. * * @return the player in control. */ public Player getPlayer() { return player; } /** * Gets the container of items in this trade session. * * @return the container of items. */ public ItemContainer getContainer() { return container; } /** * Gets the other player in this trade session. * * @return the other player. */ public Player getOther() { return other; } /** * Sets the value for {@link TradeSession#other}. * * @param other * the new value to set. */ public void setOther(Player other) { this.other = other; } /** * Gets the stage that this trade session is in * * @return the stage of the trade session. */ public TradeStage getStage() { return stage; } /** * Sets the value for {@link TradeSession#stage}. * * @param stage * the new value to set. */ public void setStage(TradeStage stage) { this.stage = stage; } }