package net.scapeemulator.game.model.player.trade;
import net.scapeemulator.game.dispatcher.button.ButtonDispatcher;
import net.scapeemulator.game.model.ExtendedOption;
import net.scapeemulator.game.model.player.ScriptInputListenerAdapter;
import net.scapeemulator.game.model.player.Item;
import net.scapeemulator.game.model.player.Player;
import net.scapeemulator.game.model.player.interfaces.ComponentListener;
import net.scapeemulator.game.model.player.interfaces.InterfaceSet.Component;
import net.scapeemulator.game.model.player.inventory.*;
import net.scapeemulator.game.msg.impl.ScriptMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceAccessMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceVisibleMessage;
import net.scapeemulator.game.task.Action;
/**
* Represents a trade session between two players.
*
* @author David Insley
*/
public class TradeSession extends ComponentListener {
static {
ButtonDispatcher.getInstance().bind(new TradeInterfaceHandler());
}
private static final int VERIFY_WINDOW = 334;
private static final int TRADE_WINDOW = 335;
private static final int TRADE_INVENTORY = 336;
private static final String WHITE = "<col=FFFFFF>";
private static final String ORANGE = "<col=FF9040>";
private static final String WAITING = "Waiting for other player...";
private static final String ACCEPTED = "Other player has accepted.";
private static final int[] AMOUNTS = { 1, 5, 10, Integer.MAX_VALUE };
private final Player player;
private final Player otherPlayer;
private TradeStatus status = TradeStatus.INIT;
private TradeSession otherSession;
private Inventory inventory;
private Inventory tradeInventory;
public TradeSession(Player player, Player otherPlayer) {
this.player = player;
this.otherPlayer = otherPlayer;
}
public void init() {
player.startAction(new Action<Player>(player, 1, true) {
@Override
public void execute() {
}
@Override
public void stop() {
decline();
super.stop();
}
});
otherSession = otherPlayer.getTradeSession();
// Configure player inventory
player.getInventory().lock();
inventory = new Inventory(player.getInventory());
inventory.addListener(new InventorySpaceChangedListener());
inventory.addListener(new InventoryMessageListener(player, -1, -1, 93));
player.send(new InterfaceAccessMessage(TRADE_INVENTORY, 0, 0, 27, 1278));
player.send(new ScriptMessage(150, "IviiiIsssssssss", "", "", "", "", "Offer-X", "Offer-All", "Offer-10", "Offer-5", "Offer", -1, 0, 7, 4, 93, TRADE_INVENTORY << 16));
player.getInterfaceSet().openInventory(TRADE_INVENTORY);
inventory.refresh();
// Configure trade screen
player.send(new InterfaceAccessMessage(TRADE_WINDOW, 30, 0, 27, 1278));
player.send(new InterfaceAccessMessage(TRADE_WINDOW, 32, 0, 27, 1278));
player.send(new ScriptMessage(150, "IviiiIsssssssss", "", "", "", "", "Remove-X", "Remove-All", "Remove-10", "Remove-5", "Remove", -1, 0, 7, 4, 90, TRADE_WINDOW << 16 | 30));
player.send(new ScriptMessage(695, "IviiiIsssssssss", "", "", "", "", "", "", "", "", "", -1, 0, 7, 4, 90, TRADE_WINDOW << 16 | 32));
player.setInterfaceText(TRADE_WINDOW, 15, "Trading with: " + otherPlayer.getDisplayName());
player.setInterfaceText(TRADE_WINDOW, 36, "");
tradeInventory = new Inventory(player, 28);
tradeInventory.addListener(new InventoryMessageListener(player, -1, -1, 90));
tradeInventory.addListener(new TradeItemsChangedListener());
tradeInventory.addListener(new InventoryMessageListener(otherPlayer, -2, 60981, 90));
player.getInterfaceSet().openWindow(TRADE_WINDOW, this);
tradeInventory.refresh();
status = TradeStatus.UPDATING_ITEMS;
}
private void secondWindow() {
player.setInterfaceText(VERIFY_WINDOW, 37, itemsToString());
player.setInterfaceText(VERIFY_WINDOW, 41, otherPlayer.getTradeSession().itemsToString());
player.setInterfaceText(VERIFY_WINDOW, 45, "Trading with:<br>" + otherPlayer.getDisplayName());
player.send(new InterfaceVisibleMessage(VERIFY_WINDOW, 37, true));
player.send(new InterfaceVisibleMessage(VERIFY_WINDOW, 41, true));
// player.send(new InterfaceVisibleMessage(VERIFY_WINDOW, 46, true)); TODO TRADE MODIFIED
player.getInterfaceSet().openWindow(VERIFY_WINDOW);
status = TradeStatus.VERIFYING;
}
public void handleInterfaceClick(int windowId, int childId, final int dynamicId, ExtendedOption option) {
if (player.getInterfaceSet().getWindow().getCurrentId() != windowId) {
return;
}
switch (windowId) {
case VERIFY_WINDOW:
switch (childId) {
case 20:
accept();
break;
case 8: // Close
case 21: // Decline
decline();
break;
}
break;
case TRADE_WINDOW:
switch (childId) {
case 16:
accept();
break;
case 12: // Close
case 18: // Decline
decline();
break;
case 30:
if (dynamicId < 0 || dynamicId > 27) {
return;
}
final Item item = tradeInventory.get(dynamicId);
if (item == null) {
return;
}
if (option == ExtendedOption.NINE) {
player.sendMessage(item.getDefinition().getExamine());
return;
}
if (status != TradeStatus.UPDATING_ITEMS && status != TradeStatus.WAITING_FIRST) {
return;
}
switch (option) {
case ONE:
case TWO:
case THREE:
case FOUR:
Item removed = tradeInventory.remove(new Item(item.getId(), AMOUNTS[option.toInteger()]), dynamicId);
inventory.add(removed);
break;
case FIVE:
player.getScriptInput().showIntegerScriptInput(new ScriptInputListenerAdapter() {
@Override
public void intInputReceived(int value) {
Item removed = tradeInventory.remove(new Item(item.getId(), value), dynamicId);
inventory.add(removed);
player.getScriptInput().reset();
}
});
break;
default:
return;
}
break;
}
break;
}
}
public void handleInventoryClick(final int dynamicId, ExtendedOption option) {
if (player.getInterfaceSet().getInventory().getCurrentId() != TRADE_INVENTORY) {
return;
}
if (dynamicId < 0 || dynamicId > 27) {
return;
}
final Item item = inventory.get(dynamicId);
if (item == null) {
return;
}
if (option == ExtendedOption.NINE) {
player.sendMessage(item.getDefinition().getExamine());
return;
}
if (status != TradeStatus.UPDATING_ITEMS && status != TradeStatus.WAITING_FIRST) {
return;
}
switch (option) {
case ONE:
case TWO:
case THREE:
case FOUR:
Item removed = inventory.remove(new Item(item.getId(), AMOUNTS[option.toInteger()]), dynamicId);
tradeInventory.add(removed);
break;
case FIVE:
player.getScriptInput().showIntegerScriptInput(new ScriptInputListenerAdapter() {
@Override
public void intInputReceived(int value) {
Item removed = inventory.remove(new Item(item.getId(), value), dynamicId);
tradeInventory.add(removed);
player.getScriptInput().reset();
}
});
break;
default:
return;
}
}
private void accept() {
switch (status) {
case INIT:
case WAITING_FIRST:
case WAITING_FINISH:
break;
case UPDATING_ITEMS:
if (otherSession.status == TradeStatus.WAITING_FIRST) {
tradeInventory.lock();
otherSession.tradeInventory.lock();
secondWindow();
otherSession.secondWindow();
} else {
status = TradeStatus.WAITING_FIRST;
player.setInterfaceText(TRADE_WINDOW, 36, WAITING);
otherPlayer.setInterfaceText(TRADE_WINDOW, 36, ACCEPTED);
}
break;
case VERIFYING:
if (otherSession.status == TradeStatus.WAITING_FINISH) {
if (canComplete() && otherSession.canComplete()) {
player.sendMessage("Trade accepted.");
otherPlayer.sendMessage("Trade accepted.");
player.getInventory().unlock();
player.getInventory().removeAll(tradeInventory.toArray());
player.getInventory().addAll(otherSession.tradeInventory.toArray());
otherPlayer.getInventory().unlock();
otherPlayer.getInventory().removeAll(otherSession.tradeInventory.toArray());
otherPlayer.getInventory().addAll(tradeInventory.toArray());
}
closeTrade();
otherSession.closeTrade();
} else {
status = TradeStatus.WAITING_FINISH;
player.setInterfaceText(VERIFY_WINDOW, 33, WAITING);
otherPlayer.setInterfaceText(VERIFY_WINDOW, 33, ACCEPTED);
}
break;
}
}
private boolean canComplete() {
/*
* Copy the players inventory into a temporary one we can manipulate. The players inventory
* shouldn't have been modified since the start of the trade because we locked it.
*/
Inventory temp = new Inventory(player.getInventory());
if (!temp.removeAll(tradeInventory.toArray()).isEmpty()) {
player.sendMessage("There was a problem with the trade. Please try again.");
otherPlayer.sendMessage("There was a problem with the trade. Please try again.");
return false;
}
if (!temp.addAll(otherSession.tradeInventory.toArray()).isEmpty()) {
player.sendMessage("You do not have enough free inventory space to complete that transaction.");
otherPlayer.sendMessage("Other player does not have enough free inventory space.");
return false;
}
return true;
}
/**
* Called when the player closes the interface or clicks decline.
*/
private void decline() {
player.sendMessage("Trade cancelled.");
otherPlayer.sendMessage("Other player declined the trade.");
closeTrade();
otherSession.closeTrade();
}
private void closeTrade() {
player.getInterfaceSet().getWindow().removeListener();
player.getInterfaceSet().closeInventory();
player.getInterfaceSet().closeWindow();
player.getScriptInput().reset();
player.getInventory().unlock();
player.getInventory().refresh();
player.setTradeSession(null);
}
private String itemsToString() {
// TODO two columns?
if (tradeInventory.isEmpty()) {
return WHITE + "Absolutely nothing!";
}
String string = "";
for (Item item : tradeInventory.toArray()) {
if (item == null) {
continue;
}
string += ORANGE + item.getDefinition().getName();
string += (item.getAmount() == 1 ? "" : (WHITE + " x " + item.getAmount())) + "<br>";
}
return string;
}
private class TradeItemsChangedListener implements InventoryListener {
@Override
public void itemChanged(Inventory inventory, int slot, Item item, Item oldItem) {
if (oldItem != null) {
otherPlayer.send(new ScriptMessage(143, "Iiii", slot, 7, 4, TRADE_WINDOW << 16 | 33));
}
itemsChanged(inventory);
}
@Override
public void itemsChanged(Inventory inventory) {
player.setInterfaceText(TRADE_WINDOW, 36, "");
otherPlayer.setInterfaceText(TRADE_WINDOW, 36, "");
status = TradeStatus.UPDATING_ITEMS;
otherSession.status = TradeStatus.UPDATING_ITEMS;
}
@Override
public void capacityExceeded(Inventory inventory) {
}
}
private class InventorySpaceChangedListener implements InventoryListener {
@Override
public void itemChanged(Inventory inventory, int slot, Item item, Item oldItem) {
itemsChanged(inventory);
}
@Override
public void itemsChanged(Inventory inventory) {
otherPlayer.setInterfaceText(TRADE_WINDOW, 21, player.getDisplayName() + " has " + inventory.freeSlots() + " free inventory slots.");
}
@Override
public void capacityExceeded(Inventory inventory) {
}
}
@Override
public void inputPressed(Component component, int componentId, int dynamicId) {
}
@Override
public void componentClosed(Component component) {
decline();
}
@Override
public boolean componentChanged(Component component, int oldId) {
if(component.getCurrentId() != VERIFY_WINDOW) {
decline();
return false;
}
return true;
}
}