package net.scapeemulator.game.model.player.bank;
import static net.scapeemulator.game.model.player.bank.BankTab.TAB_ALL;
import static net.scapeemulator.game.model.player.interfaces.Interface.BANK;
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.ComponentListenerAdapter;
import net.scapeemulator.game.model.player.interfaces.InterfaceSet.Component;
import net.scapeemulator.game.model.player.inventory.Inventory;
import net.scapeemulator.game.msg.impl.inter.InterfaceAccessMessage;
/**
* @author David Insley
*/
public class BankSession extends ComponentListenerAdapter {
static {
ButtonDispatcher.getInstance().bind(new BankInterfaceHandler());
}
public static final int BANK_SLOTS = 400;
public static final int BANK_INVENTORY = 763;
private static final int[] AMOUNTS = { 1, 5, 10 };
private final Player player;
private final Inventory inventory;
private final Inventory bank;
private final BankSettings settings;
/**
* If true, items will attempt to be withdrawn as notes instead of their normal id. Move to
* BankSettings to have this persist across bank sessions, and add to the serializer as well to
* have it persist across login sessions.
*/
private boolean noteWithdrawal;
private boolean insert;
public BankSession(Player player) {
this.player = player;
this.inventory = player.getInventory();
this.bank = player.getBank();
this.settings = player.getBankSettings();
}
public void init() {
sendOpenTab();
bank.unlock();
// Set the deposit/withdraw-x default value and button configs
player.getStateSet().setState(1249, settings.getLastX());
player.getStateSet().setState(105, noteWithdrawal ? 1 : 0);
player.getStateSet().setState(304, insert ? 1 : 0);
// Configure player inventory
player.send(new InterfaceAccessMessage(BANK_INVENTORY, 0, 0, 27, 2360446));
player.getInterfaceSet().openInventory(BANK_INVENTORY);
inventory.refresh();
// TODO what do these do?
// player.send(new ConfigMessage(563, 4194304));
// player.send(new ScriptMessage(1451, 239, ""));
sendTabSizes();
// Configure bank screen
player.send(new InterfaceAccessMessage(BANK, 73, 0, BANK_SLOTS - 1, 2360446));
player.getInterfaceSet().openWindow(BANK, this);
bank.refresh();
}
public void handleInterfaceClick(int childId, final int dyn, ExtendedOption option) {
BankTab tab = BankTab.forChildId(childId);
if (tab != null) {
settings.setOpenTab(tab);
return;
}
switch (childId) {
case 14:
insert = !insert;
player.getStateSet().setState(304, insert ? 1 : 0);
break;
case 16:
noteWithdrawal = !noteWithdrawal;
player.getStateSet().setState(105, noteWithdrawal ? 1 : 0);
break;
case 73:
switch (option) {
case ONE:
case TWO:
case THREE:
withdraw(dyn, AMOUNTS[option.toInteger()]);
break;
case FOUR:
withdraw(dyn, settings.getLastX());
break;
case FIVE:
player.getScriptInput().showIntegerScriptInput(new ScriptInputListenerAdapter() {
@Override
public void intInputReceived(int value) {
withdraw(dyn, value);
settings.setLastX(value);
player.getStateSet().setState(1249, value);
player.getScriptInput().reset();
}
});
break;
case SIX:
withdraw(dyn, Integer.MAX_VALUE);
break;
case NINE:
player.sendMessage(bank.get(dyn).getDefinition().getExamine());
break;
default:
break;
}
break;
}
}
public void handleInventoryClick(int childId, final int dyn, ExtendedOption option) {
if (childId != 0) {
return;
}
switch (option) {
case ONE:
case TWO:
case THREE:
deposit(dyn, AMOUNTS[option.toInteger()]);
break;
case FOUR:
deposit(dyn, settings.getLastX());
break;
case FIVE:
player.getScriptInput().showIntegerScriptInput(new ScriptInputListenerAdapter() {
@Override
public void intInputReceived(int value) {
deposit(dyn, value);
settings.setLastX(value);
player.getStateSet().setState(1249, value);
player.getScriptInput().reset();
}
});
break;
case SIX:
deposit(dyn, Integer.MAX_VALUE);
break;
case NINE:
player.sendMessage(inventory.get(dyn).getDefinition().getExamine());
break;
default:
break;
}
}
/**
* Attempts to deposit items from the players inventory to the bank.
*
* @param slot the slot of the item in the players inventory
* @param amount the amount to deposit
*/
private void deposit(int slot, int amount) {
Item originalItem = inventory.get(slot);
if (originalItem == null) {
return;
}
if (!originalItem.getDefinition().canBank()) {
player.sendMessage("A magical force prevents you from banking that item.");
return;
}
// Check the requested deposit amount against the players actual amount
int invenAmount = inventory.getAmount(originalItem.getId());
amount = amount > invenAmount ? invenAmount : amount;
Item toDeposit = new Item(originalItem.getDefinition().getUnnotedItemId(), amount);
int depositedAmount = 0;
/*
* If we already have this stack in the bank, we can use the normal inventory add methods.
* If not, we can't use the normal inventory methods because it uses set instead of insert
* for the preferred slot.
*/
if (bank.contains(toDeposit.getId())) {
Item notAdded = bank.add(toDeposit);
if (notAdded != null) {
depositedAmount = amount - notAdded.getAmount();
} else {
depositedAmount = amount;
}
} else {
if (bank.freeSlot() == -1) {
player.sendMessage("You have run out of bank space.");
} else {
insert(toDeposit);
depositedAmount = amount;
}
}
/*
* If we actually deposited anything, make sure to remove the original item from the
* inventory.
*/
if (depositedAmount > 0) {
inventory.remove(new Item(originalItem.getId(), depositedAmount), slot);
}
sendOpenTab();
}
private void withdraw(int slot, int amount) {
BankTab fromTab = settings.getTab(slot);
Item originalItem = bank.get(slot);
if (originalItem == null) {
return;
}
// Check the requested withdraw amount against the actual amount in the bank
amount = amount > originalItem.getAmount() ? originalItem.getAmount() : amount;
Item toWithdraw = new Item(originalItem.getId(), amount);
if (noteWithdrawal) {
int notedId = originalItem.getDefinition().getNotedItemId();
if (notedId != originalItem.getId()) {
toWithdraw = new Item(notedId, amount);
} else {
player.sendMessage("That item cannot be withdrawn as a note.");
}
}
int withdrawn = 0;
Item notAdded = inventory.add(toWithdraw);
if (notAdded != null) {
withdrawn = amount - notAdded.getAmount();
} else {
withdrawn = amount;
}
// If we actually withdrew anything, make sure to remove the original item from the bank.
if (withdrawn > 0) {
bank.remove(new Item(originalItem.getId(), withdrawn), slot);
if (bank.get(slot) == null) {
// Move all items one slot to fill the empty space.
bank.silence();
for (int i = slot; i < BANK_SLOTS - 1; i++) {
bank.set(i, bank.get(i + 1));
}
bank.set(BANK_SLOTS - 1, null);
bank.unsilence();
settings.decrementTabStarts(fromTab);
if (fromTab != BankTab.TAB_ALL && settings.getTabSize(fromTab) == 0) {
settings.setOpenTab(TAB_ALL);
}
sendTabSizes();
bank.refresh();
}
}
sendOpenTab();
}
public void handleBankSwap(int childId2, int source, int dest) {
if (bank.get(source) == null) {
return;
}
if (childId2 != 73) {
BankTab tab = BankTab.forChildId(childId2);
if (tab != null && tab != settings.getOpenTab()) {
moveInsert(source, tab);
}
} else {
if (insert) {
swapInsert(source, dest);
} else {
bank.swap(source, dest);
}
}
sendOpenTab();
}
/**
* Called when the player attempts to swap two items but has the 'insert' option selected. Moves
* the source item to the slot after the destination item. Should only be called if the items
* are in the same tab.
*
* @param source the slot of the item to move
* @param dest the slot of the item to insert after
*/
private void swapInsert(int source, int dest) {
Item temp = bank.get(source);
bank.silence();
if (dest < source) {
dest += 1;
}
int delta = dest > source ? 1 : -1;
for (int i = source; Math.abs(i - dest) > 0; i += delta) {
bank.set(i, bank.get(i + delta));
}
bank.set(dest, temp);
bank.unsilence();
bank.refresh();
}
/**
* Moves an item from the specified bank slot to the end of the given tab. Creates a new tab if
* it does not exist.
*
* @param source the slot of the item to move
* @param destTab the tab to move the item to
*/
private void moveInsert(int source, BankTab destTab) {
BankTab sourceTab = settings.getTab(source);
/*
* If we're not moving to the main tab and the destination tab does no exist, make sure to
* set up a new one.
*/
if (destTab != BankTab.TAB_ALL && settings.getTabSize(destTab) == 0) {
destTab = settings.createTab();
}
/*
* Calculate the destination slot at the end of the destination tab, using the banks next
* free slot if the destination is the 'all' tab.
*/
int dest = destTab == BankTab.TAB_ALL ? bank.freeSlot() : settings.getTabStart(destTab) + settings.getTabSize(destTab);
/*
* If the destination slot is greater than the source slot, take into account that
* everything will shift.
*/
if (dest > source) {
dest -= 1;
}
Item temp = bank.get(source);
/*
* Move all of the items between the two slots in the correct direction, and then set the
* destination slot to the new item.
*/
bank.silence();
int delta = dest > source ? 1 : -1;
for (int i = source; Math.abs(i - dest) > 0; i += delta) {
bank.set(i, bank.get(i + delta));
}
bank.set(dest, temp);
bank.unsilence();
/*
* Increase the tab start slot of everything greater than the destination tab because we
* inserted a new item there, then decrease the tab starts of all tabs (source tab + 1)
* because we removed the item. These two operations will overlap only adjusting some of the
* tabs. If a tab is emptied, tabs shift appropriately.
*/
settings.incrementTabStarts(destTab);
settings.decrementTabStarts(sourceTab);
sendTabSizes();
bank.refresh();
}
/**
* Inserts an item at the end of the current open tab.
*
* @param source the slot of the item to move
* @param destTab the tab to move the item to
*/
private void insert(Item item) {
if (bank.freeSlot() == -1) {
return;
}
int last = bank.freeSlot();
/*
* Calculate the destination slot at the end of the open tab, using the banks next free slot
* if the destination is the 'all' tab.
*/
int dest = settings.getOpenTab() == BankTab.TAB_ALL ? last : settings.getTabStart(settings.getOpenTab()) + settings.getTabSize(settings.getOpenTab());
/*
* Move all items one slot to make room for the new one.
*/
bank.silence();
for (int i = last; i > dest; i--) {
bank.set(i, bank.get(i - 1));
}
bank.set(dest, item);
bank.unsilence();
/*
* Increase the tab start slot of everything greater than the destination tab because we
* inserted a new item there.
*/
settings.incrementTabStarts(settings.getOpenTab());
sendTabSizes();
bank.refresh();
}
private void endSession() {
player.getScriptInput().reset();
player.endBankSession();
bank.lock();
}
private void sendTabSizes() {
for (BankTab tab : BankTab.values()) {
if (tab == TAB_ALL) {
continue;
}
player.getStateSet().setBitState(4885 + tab.index(), settings.getTabSize(tab));
}
}
private void sendOpenTab() {
player.getStateSet().setBitState(4893, settings.getOpenTab().getTabId());
}
@Override
public void componentClosed(Component component) {
endSession();
}
@Override
public boolean componentChanged(Component component, int oldId) {
componentClosed(component);
return false;
}
}