package javastory.channel.handling;
import java.util.Arrays;
import java.util.List;
import javastory.channel.ChannelCharacter;
import javastory.channel.ChannelClient;
import javastory.channel.ChannelServer;
import javastory.channel.maps.GameMapObject;
import javastory.channel.maps.GameMapObjectType;
import javastory.channel.packet.PlayerShopPacket;
import javastory.channel.server.InventoryManipulator;
import javastory.channel.server.Trade;
import javastory.channel.shops.AbstractPlayerShop;
import javastory.channel.shops.GenericPlayerStore;
import javastory.channel.shops.HiredMerchantStore;
import javastory.channel.shops.PlayerShop;
import javastory.channel.shops.PlayerShopItem;
import javastory.game.GameConstants;
import javastory.game.Inventory;
import javastory.game.InventoryType;
import javastory.game.Item;
import javastory.game.ItemFlag;
import javastory.game.data.ItemInfoProvider;
import javastory.io.PacketFormatException;
import javastory.io.PacketReader;
import javastory.tools.packets.ChannelPackets;
public class PlayerInteractionHandler {
public static void handlePlayerInteraction(final PacketReader reader, final ChannelClient client, final ChannelCharacter player)
throws PacketFormatException {
final byte action = reader.readByte();
final PlayerInteractionType type = PlayerInteractionType.fromNumber(action);
switch (type) { // Mode
case CREATE:
create(reader, client, player);
break;
case TRADE_INVITE:
inviteTrade(reader, player);
break;
case TRADE_DECLINE:
tradeDecline(player);
break;
case VISIT:
visit(reader, client, player);
break;
case CHAT:
chat(reader, player);
break;
case EXIT:
exit(client, player);
break;
case OPEN:
open(reader, client, player);
break;
case TRADE_SET_ITEMS:
tradeSetItems(reader, client, player);
break;
case TRADE_SET_MESO:
tradeSetMeso(reader, player);
break;
case TRADE_CONFIRM:
tradeConfirm(player);
break;
case MERCHANT_EXIT:
exitMerchant(player);
break;
case ADD_ITEM:
addItem(reader, client, player);
break;
case BUY_ITEM_STORE:
case BUY_ITEM_HIREDMERCHANT:
// Buy and Merchant buy
buyItem(reader, client, player);
break;
case REMOVE_ITEM:
removeItem(reader, client, player);
break;
case MAINTENANCE_OFF:
shopMaintenanceOff(player);
break;
case MAINTENANCE_ORGANISE:
shopMaintenance(client, player);
break;
case CLOSE_MERCHANT:
closeMerchant(client, player);
break;
case ADMIN_STORE_NAMECHANGE:
// Changing store name, only Admin
// 01 00 00 00
case VIEW_MERCHANT_VISITOR:
case VIEW_MERCHANT_BLACKLIST:
break;
default:
System.out.println("Unhandled interaction action : " + action + ", " + reader.toString());
break;
}
}
private static void create(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final byte createType = reader.readByte();
if (createType == 1) { // omok
// nvm
} else if (createType == 3) { // trade
Trade.startTrade(chr);
} else if (createType == 4 || createType == 5) { // shop
final List<GameMapObjectType> filter = Arrays.asList(GameMapObjectType.SHOP, GameMapObjectType.HIRED_MERCHANT);
final List<GameMapObject> objects = chr.getMap().getMapObjectsInRange(chr.getPosition(), 19500, filter);
if (!objects.isEmpty()) {
chr.sendNotice(1, "You may not establish a store here.");
} else {
final String desc = reader.readLengthPrefixedString();
reader.skip(3);
final int itemId = reader.readInt();
if (createType == 4) {
chr.setPlayerShop(new GenericPlayerStore(chr, itemId, desc));
c.write(PlayerShopPacket.getPlayerStore(chr, true));
} else {
final HiredMerchantStore merch = new HiredMerchantStore(chr, itemId, desc);
chr.setPlayerShop(merch);
c.write(PlayerShopPacket.getHiredMerch(chr, merch, true));
}
}
}
}
private static void inviteTrade(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final ChannelCharacter ochr = chr.getMap().getCharacterById_InMap(reader.readInt());
if (ochr.getWorldId() != chr.getWorldId()) {
chr.getClient().write(ChannelPackets.serverNotice(5, "Cannot find player"));
return;
}
Trade.inviteTrade(chr, ochr);
}
private static void tradeDecline(final ChannelCharacter chr) {
Trade.declineTrade(chr);
}
private static void visit(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
if (chr.getTrade() != null && chr.getTrade().getPartner() != null) {
Trade.visitTrade(chr, chr.getTrade().getPartner().getChr());
} else {
final GameMapObject ob = chr.getMap().getMapObject(reader.readInt());
if (ob instanceof PlayerShop && chr.getPlayerShop() == null) {
final PlayerShop ips = (PlayerShop) ob;
if (ob instanceof HiredMerchantStore) {
final HiredMerchantStore merchant = (HiredMerchantStore) ips;
if (merchant.isOwner(chr)) {
merchant.setOpen(false);
merchant.broadcastToVisitors(PlayerShopPacket.shopErrorMessage(0x0D, 1));
merchant.removeAllVisitors((byte) 16, (byte) 0);
chr.setPlayerShop(ips);
c.write(PlayerShopPacket.getHiredMerch(chr, merchant, false));
} else {
if (!merchant.isOpen()) {
chr.sendNotice(1, "This shop is in maintenance, please come by later.");
} else {
if (ips.getFreeSlot() == -1) {
chr.sendNotice(1, "This shop has reached it's maximum capacity, please come by later.");
} else {
chr.setPlayerShop(ips);
merchant.addVisitor(chr);
c.write(PlayerShopPacket.getHiredMerch(chr, merchant, false));
}
}
}
} else if (ips.getShopType() == 2) {
if (((GenericPlayerStore) ips).isBanned(chr.getName())) {
chr.sendNotice(1, "You have been banned from this store.");
return;
}
} else {
if (ips.getFreeSlot() == -1) {
chr.sendNotice(1, "This shop has reached it's maximum capacity, please come by later.");
} else {
chr.setPlayerShop(ips);
ips.addVisitor(chr);
c.write(PlayerShopPacket.getPlayerStore(chr, false));
}
}
}
}
}
private static void chat(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
reader.readInt();
if (chr.getTrade() != null) {
chr.getTrade().chat(reader.readLengthPrefixedString());
} else if (chr.getPlayerShop() != null) {
final PlayerShop ips = chr.getPlayerShop();
final String message = reader.readLengthPrefixedString();
ips.broadcastToVisitors(PlayerShopPacket.shopChat(chr.getName() + " : " + message, ips.isOwner(chr) ? 0 : ips.getVisitorSlot(chr)));
}
}
private static void exit(final ChannelClient c, final ChannelCharacter chr) {
if (chr.getTrade() != null) {
Trade.cancelTrade(chr.getTrade());
} else {
final PlayerShop ips = chr.getPlayerShop();
if (ips == null) {
return;
}
if (ips.isOwner(chr)) {
if (ips.getShopType() == 2) {
boolean save = false;
for (final PlayerShopItem items : ips.getItems()) {
if (items.bundles > 0) {
if (InventoryManipulator.addFromDrop(c, items.item, false)) {
items.bundles = 0;
} else {
save = true;
break;
}
}
}
ips.removeAllVisitors(3, 1);
ips.closeShop(save, true);
}
} else {
ips.removeVisitor(chr);
}
chr.setPlayerShop(null);
}
}
private static void open(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
// c.getPlayer().haveItem(mode, 1, false, true)
if (chr.getMap().allowPersonalShop()) {
final PlayerShop shop = chr.getPlayerShop();
if (shop != null && shop.isOwner(chr)) {
chr.getMap().addMapObject((AbstractPlayerShop) shop);
if (shop.getShopType() == 1) {
final HiredMerchantStore merchant = (HiredMerchantStore) shop;
merchant.setStoreid(ChannelServer.getInstance().addMerchant(merchant));
merchant.setOpen(true);
chr.getMap().broadcastMessage(PlayerShopPacket.spawnHiredMerchant(merchant));
chr.setPlayerShop(null);
} else if (shop.getShopType() == 2) {
chr.getMap().broadcastMessage(PlayerShopPacket.sendPlayerShopBox(chr));
}
reader.readByte();
}
} else {
c.disconnect(true);
}
}
private static void tradeSetItems(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final ItemInfoProvider ii = ItemInfoProvider.getInstance();
final byte typeByte = reader.readByte();
final InventoryType type = InventoryType.fromNumber(typeByte);
final Inventory inventory = chr.getInventoryByType(type);
final Item item = inventory.getItem((byte) reader.readShort());
final short quantity = reader.readShort();
final byte targetSlot = reader.readByte();
if (chr.getTrade() != null && item != null) {
if (quantity <= item.getQuantity() && quantity >= 0 || GameConstants.isThrowingStar(item.getItemId()) || GameConstants.isBullet(item.getItemId())) {
final byte flag = item.getFlag();
if (ItemFlag.UNTRADEABLE.check(flag) || ItemFlag.LOCK.check(flag)) {
c.write(ChannelPackets.enableActions());
return;
}
if (ii.isDropRestricted(item.getItemId())) {
if (!(ItemFlag.KARMA_EQ.check(flag) || ItemFlag.KARMA_USE.check(flag))) {
c.write(ChannelPackets.enableActions());
return;
}
}
final Item tradeItem = item.copy();
if (GameConstants.isThrowingStar(item.getItemId()) || GameConstants.isBullet(item.getItemId())) {
tradeItem.setQuantity(item.getQuantity());
InventoryManipulator.removeFromSlot(c, inventory, item.getPosition(), item.getQuantity(), true);
} else {
tradeItem.setQuantity(quantity);
InventoryManipulator.removeFromSlot(c, inventory, item.getPosition(), quantity, true);
}
tradeItem.setPosition(targetSlot);
chr.getTrade().addItem(tradeItem);
}
}
}
private static void tradeSetMeso(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final Trade trade = chr.getTrade();
if (trade != null) {
trade.setMeso(reader.readInt());
}
}
private static void tradeConfirm(final ChannelCharacter chr) {
if (chr.getTrade() != null) {
Trade.completeTrade(chr);
}
}
private static void exitMerchant(final ChannelCharacter chr) {
// final PlayerShop shop = chr.getPlayerShop();
// if (shop != null && shop instanceof HiredMerchantStore && shop.isOwner(chr)) {
// shop.setOpen(true);
// chr.setPlayerShop(null);
// }
}
private static void addItem(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final byte typeByte = reader.readByte();
final InventoryType type = InventoryType.fromNumber(typeByte);
final Inventory inventory = chr.getInventoryByType(type);
final byte slot = (byte) reader.readShort();
final short bundles = reader.readShort(); // How many in a bundle
final short perBundle = reader.readShort(); // Price per bundle
final int price = reader.readInt();
if (price <= 0 || bundles <= 0 || perBundle <= 0) {
return;
}
final PlayerShop shop = chr.getPlayerShop();
if (shop == null || !shop.isOwner(chr)) {
return;
}
final Item ivItem = inventory.getItem(slot);
if (ivItem != null) {
final short bundles_perbundle = (short) (bundles * perBundle);
if (bundles_perbundle < 0) { // int_16 overflow
return;
}
if (ivItem.getQuantity() >= bundles_perbundle) {
final byte flag = ivItem.getFlag();
if (ItemFlag.UNTRADEABLE.check(flag) || ItemFlag.LOCK.check(flag)) {
c.write(ChannelPackets.enableActions());
return;
}
if (ItemInfoProvider.getInstance().isDropRestricted(ivItem.getItemId())) {
if (!(ItemFlag.KARMA_EQ.check(flag) || ItemFlag.KARMA_USE.check(flag))) {
c.write(ChannelPackets.enableActions());
return;
}
}
if (GameConstants.isThrowingStar(ivItem.getItemId()) || GameConstants.isBullet(ivItem.getItemId())) {
// Ignore the bundles
InventoryManipulator.removeFromSlot(c, inventory, slot, ivItem.getQuantity(), true);
final Item sellItem = ivItem.copy();
shop.addItem(new PlayerShopItem(sellItem, (short) 1, price));
} else {
InventoryManipulator.removeFromSlot(c, inventory, slot, bundles_perbundle, true);
final Item sellItem = ivItem.copy();
sellItem.setQuantity(perBundle);
shop.addItem(new PlayerShopItem(sellItem, bundles, price));
}
c.write(PlayerShopPacket.shopItemUpdate(shop));
}
}
}
private static void buyItem(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final int item = reader.readByte();
final short quantity = reader.readShort();
final PlayerShop shop = chr.getPlayerShop();
if (shop == null || shop.isOwner(chr)) {
return;
}
final PlayerShopItem tobuy = shop.getItems().get(item);
if (quantity < 0 || tobuy == null || tobuy.bundles < quantity
|| tobuy.bundles % quantity != 0 && GameConstants.isEquip(tobuy.item.getItemId()) // Buying
|| (short) (tobuy.bundles * quantity) < 0 || quantity * tobuy.price < 0 || quantity * tobuy.item.getQuantity() < 0
|| chr.getMeso() - quantity * tobuy.price < 0 || shop.getMeso() + quantity * tobuy.price < 0) {
return;
}
shop.buy(c, item, quantity);
shop.broadcastToVisitors(PlayerShopPacket.shopItemUpdate(shop));
}
private static void removeItem(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final int slot = reader.readShort();
final PlayerShop shop = chr.getPlayerShop();
if (shop == null || !shop.isOwner(chr)) {
return;
}
final PlayerShopItem item = shop.getItems().get(slot);
if (item != null) {
if (item.bundles > 0) {
final Item item_get = item.item.copy();
item_get.setQuantity((short) (item.bundles * item.item.getQuantity()));
if (InventoryManipulator.addFromDrop(c, item_get, false)) {
item.bundles = 0;
shop.removeFromSlot(slot);
}
}
}
c.write(PlayerShopPacket.shopItemUpdate(shop));
}
private static void shopMaintenanceOff(final ChannelCharacter chr) {
final PlayerShop shop = chr.getPlayerShop();
// TS TODO: If the player is NOT the owner, should track a cheating
// offense.
if (shop != null && shop instanceof HiredMerchantStore && shop.isOwner(chr)) {
shop.setOpen(true);
chr.setPlayerShop(null);
}
}
private static void shopMaintenance(final ChannelClient c, final ChannelCharacter chr) {
final PlayerShop imps = chr.getPlayerShop();
// TS TODO: If the player is NOT the owner, should track a cheating
// offense.
if (imps.isOwner(chr)) {
for (int i = 0; i < imps.getItems().size(); i++) {
if (imps.getItems().get(i).bundles == 0) {
imps.getItems().remove(i);
}
}
if (chr.getMeso() + imps.getMeso() < 0) {
c.write(PlayerShopPacket.shopItemUpdate(imps));
} else {
chr.gainMeso(imps.getMeso(), false);
imps.setMeso(0);
c.write(PlayerShopPacket.shopItemUpdate(imps));
}
}
}
private static void closeMerchant(final ChannelClient c, final ChannelCharacter chr) {
final PlayerShop merchant = chr.getPlayerShop();
// TS TODO: If the player is NOT the owner, should track a cheating
// offense.
if (merchant != null && merchant.getShopType() == 1 && merchant.isOwner(chr)) {
boolean save = false;
if (chr.getMeso() + merchant.getMeso() < 0) {
save = true;
} else {
if (merchant.getMeso() > 0) {
chr.gainMeso(merchant.getMeso(), false);
}
merchant.setMeso(0);
if (merchant.getItems().size() > 0) {
for (final PlayerShopItem items : merchant.getItems()) {
if (items.bundles > 0) {
final Item item_get = items.item.copy();
item_get.setQuantity((short) (items.bundles * items.item.getQuantity()));
if (InventoryManipulator.addFromDrop(c, item_get, false)) {
items.bundles = 0;
} else {
save = true;
break;
}
}
}
}
}
c.write(PlayerShopPacket.shopErrorMessage(0x10, 0));
merchant.closeShop(save, true);
chr.setPlayerShop(null);
}
}
}