package server.shops; import client.MapleClient; import client.SkillFactory; import client.inventory.Item; import client.inventory.MapleInventoryIdentifier; import client.inventory.MapleInventoryType; import client.inventory.MaplePet; import constants.GameConstants; import constants.ItemConstants; import database.DatabaseConnection; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import server.MapleInventoryManipulator; import server.MapleItemInformationProvider; import tools.FileoutputUtil; import tools.Pair; import tools.packet.CField; import tools.packet.CWvsContext; public class MapleShop { private static final Set<Integer> rechargeableItems = new LinkedHashSet(); private final int id; private final int npcId; private final List<MapleShopItem> items = new LinkedList(); private final List<Pair<Integer, String>> ranks = new ArrayList(); static { //鏢 rechargeableItems.add(2070000);//海星鏢 rechargeableItems.add(2070001);//迴旋鏢 rechargeableItems.add(2070002);//黑色利刃 rechargeableItems.add(2070003);//雪花鏢 rechargeableItems.add(2070004);//梅之鏢 rechargeableItems.add(2070005);//雷之鏢 rechargeableItems.add(2070006);//日之鏢 rechargeableItems.add(2070007);//月牙鏢 rechargeableItems.add(2070008);//雪球 rechargeableItems.add(2070009);//木製陀螺 rechargeableItems.add(2070010);//冰柱 rechargeableItems.add(2070011);//楓葉飛鏢 rechargeableItems.add(2070012);//紙飛機 rechargeableItems.add(2070013);//橘子 rechargeableItems.add(2070015);//新手盜賊的飛鏢 rechargeableItems.add(2070019);//手裡劍-魔 rechargeableItems.add(2070020);//鞭炮 rechargeableItems.add(2070021);//手裡劍-魔 rechargeableItems.add(2070022);//閃亮的紙條 rechargeableItems.add(2070023);//火牢術飛鏢 rechargeableItems.add(2070024);//無限的增加鏢 rechargeableItems.add(2070026);//白金飛鏢 //弹 rechargeableItems.add(2330000);//彈丸 rechargeableItems.add(2330001);//子彈 rechargeableItems.add(2330002);//強力子彈 rechargeableItems.add(2330003);//高等子彈 rechargeableItems.add(2330004);//高爆彈 rechargeableItems.add(2330005);//穿甲彈 rechargeableItems.add(2330006);//新手海盜的子彈 rechargeableItems.add(2330007);//貫穿裝甲的特製子彈 rechargeableItems.add(2330008);//巨人彈丸 rechargeableItems.add(2330016);//白金彈丸 rechargeableItems.add(2331000);//火炎膠囊 rechargeableItems.add(2332000);//寒冰膠囊 } public MapleShop(int id, int npcId) { this.id = id; this.npcId = npcId; } public void addItem(MapleShopItem item) { this.items.add(item); } public List<MapleShopItem> getItems() { return this.items; } public void sendShop(MapleClient c) { c.getPlayer().setShop(this); c.getSession().write(CField.NPCPacket.getNPCShop(getNpcId(), this, c)); } public void sendShop(MapleClient c, int customNpc) { c.getPlayer().setShop(this); c.getSession().write(CField.NPCPacket.getNPCShop(customNpc, this, c)); } public void buy(MapleClient c, short slot, int itemId, short quantity) { if ((itemId / 10000 == 190) && (!GameConstants.isMountItemAvailable(itemId, c.getPlayer().getJob()))) { c.getPlayer().dropMessage(1, "無法購買此道具."); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); return; } MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); int x = 0; int index = -1; for (Item i : c.getPlayer().getRebuy()) { if (i.getItemId() == itemId) { index = x; break; } x++; } if (index >= 0) { Item i = c.getPlayer().getRebuy().get(index); int price = (int) Math.max(Math.ceil(ii.getPrice(itemId) * (ItemConstants.類型.可充值道具(itemId) ? 1 : i.getQuantity())), 0.0D); if ((price >= 0) && (c.getPlayer().getMeso() >= price)) { if (MapleInventoryManipulator.checkSpace(c, itemId, i.getQuantity(), i.getOwner())) { c.getPlayer().gainMeso(-price, false); MapleInventoryManipulator.addbyItem(c, i); c.getPlayer().getRebuy().remove(index); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, x)); } else { c.getPlayer().dropMessage(1, "請確認道具欄有足夠的空間."); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); } } else { c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); } return; } MapleShopItem item = findBySlotAndId(itemId, slot); if (item == null) { c.getPlayer().dropMessage(1, "無法購買此道具."); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); return; } if (c.getPlayer().getLevel() < item.getMinLevel()) { c.getPlayer().dropMessage(1, item.getMinLevel() + "等級以上才可購入。"); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); return; } int slotMax = MapleItemInformationProvider.getInstance().getSlotMax(item.getItemId()); int shopItemQ = item.getQuantity() == 0 ? slotMax : item.getQuantity(); int buyable = shopItemQ > 1 ? 1 : item.getBuyable() == 0 ? slotMax : item.getBuyable(); if ((shopItemQ > 1 && quantity > 1) || (shopItemQ == 1 && quantity > buyable) || shopItemQ < 1) { c.getPlayer().dropMessage(1, "購買失敗."); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); return; } quantity = (short) (shopItemQ > 1 ? shopItemQ : quantity); if (item.getPrice() > 0 && item.getReqItem() == 0) { if (item.getRank() >= 0) { boolean passed = true; int y = 0; for (Pair i : getRanks()) { if ((c.getPlayer().haveItem(((Integer) i.left), 1, true, true)) && (item.getRank() >= y)) { passed = true; break; } y++; } if (!passed) { c.getPlayer().dropMessage(1, "你需要更高的級別才能購買此道具."); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); return; } } int price = ItemConstants.類型.可充值道具(itemId) || shopItemQ > 1 ? item.getPrice() : item.getPrice() * quantity; if (price >= 0 && c.getPlayer().getMeso() >= price) { if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) { c.getPlayer().gainMeso(-price, false); if (ItemConstants.類型.寵物(itemId)) { MapleInventoryManipulator.addById(c, itemId, (short) quantity, "", MaplePet.createPet(itemId, MapleInventoryIdentifier.getInstance()), item.getExpiration() == 0 ? -1 : item.getExpiration(), MapleInventoryManipulator.MINUTE, "從商店ID:" + this.id + ", NPCID:" + this.npcId + " 處購買, 時間:" + FileoutputUtil.CurrentReadable_Date()); } else { if (ItemConstants.類型.可充值道具(itemId)) { quantity = ii.getSlotMax(item.getItemId()); } MapleInventoryManipulator.addById(c, itemId, quantity, null, null, item.getExpiration(), MapleInventoryManipulator.MINUTE, "從商店ID:" + this.id + ", NPCID:" + this.npcId + " 處購買, 時間:" + FileoutputUtil.CurrentReadable_Date()); } } else { c.getPlayer().dropMessage(1, "請確認道具欄有足夠的空間."); } c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); } } else if (item.getReqItem() > 0 && quantity == 1 && c.getPlayer().haveItem(item.getReqItem(), item.getReqItemQ(), false, true)) { if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) { MapleInventoryManipulator.removeById(c, GameConstants.getInventoryType(item.getReqItem()), item.getReqItem(), item.getReqItemQ(), false, false); if (ItemConstants.類型.寵物(itemId)) { MapleInventoryManipulator.addById(c, itemId, (short) quantity, "", MaplePet.createPet(itemId, MapleInventoryIdentifier.getInstance()), item.getExpiration() == 0 ? -1 : item.getExpiration(), MapleInventoryManipulator.MINUTE, "從商店ID:" + this.id + ", NPCID:" + this.npcId + " 處購買, 時間:" + FileoutputUtil.CurrentReadable_Date()); } else { if (ItemConstants.類型.可充值道具(itemId)) { quantity = ii.getSlotMax(item.getItemId()); } MapleInventoryManipulator.addById(c, itemId, quantity, null, null, item.getExpiration(), MapleInventoryManipulator.MINUTE, "從商店ID:" + this.id + ", NPCID:" + this.npcId + " 處購買, 時間:" + FileoutputUtil.CurrentReadable_Date()); } } else { c.getPlayer().dropMessage(1, "請確認道具欄有足夠的空間."); } c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); } } public void sell(MapleClient c, MapleInventoryType type, byte slot, short quantity) { if ((quantity == 65535) || (quantity == 0)) { quantity = 1; } Item item = c.getPlayer().getInventory(type).getItem(slot); if (item == null) { return; } if (ItemConstants.類型.可充值道具(item.getItemId())) { quantity = item.getQuantity(); } short iQuant = item.getQuantity(); if (iQuant == 65535) { iQuant = 1; } MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if ((ii.cantSell(item.getItemId())) || (ItemConstants.類型.寵物(item.getItemId()))) { return; } List<Item> listRebuy = new ArrayList<>(); if ((quantity <= iQuant) && (iQuant > 0)) { if (item.getQuantity() == quantity) { if (c.getPlayer().getRebuy().size() < 10) { c.getPlayer().getRebuy().add(item.copy()); } else if (c.getPlayer().getRebuy().size() == 10) { for (int i = 1; i < 10; i++) { listRebuy.add(c.getPlayer().getRebuy().get(i)); } listRebuy.add(item.copy()); c.getPlayer().setRebuy(listRebuy); } else { int x = c.getPlayer().getRebuy().size(); for (int i = x - 10; i < x; i++) { listRebuy.add(c.getPlayer().getRebuy().get(i)); } c.getPlayer().setRebuy(listRebuy); } } else { c.getPlayer().getRebuy().add(item.copyWithQuantity(quantity)); } MapleInventoryManipulator.removeFromSlot(c, type, slot, quantity, false); double price; if (ItemConstants.類型.可充值道具(item.getItemId())) { price = ii.getWholePrice(item.getItemId()) / ii.getSlotMax(item.getItemId()); } else { price = ii.getPrice(item.getItemId()); } int recvMesos = (int) Math.max(Math.ceil(price * quantity), 0.0D); if ((price != -1.0D) && (recvMesos > 0)) { c.getPlayer().gainMeso(recvMesos, false); } c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 8, this, c, -1)); } } public void recharge(MapleClient c, byte slot) { Item item = c.getPlayer().getInventory(MapleInventoryType.USE).getItem(slot); if ((item == null) || (!ItemConstants.類型.可充值道具(item.getItemId()))) { return; } MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); short slotMax = ii.getSlotMax(item.getItemId()); int skill = GameConstants.getMasterySkill(c.getPlayer().getJob()); if (skill != 0) { slotMax = (short) (slotMax + c.getPlayer().getTotalSkillLevel(SkillFactory.getSkill(skill)) * 10); } if (item.getQuantity() < slotMax) { int price = (int) Math.round(ii.getPrice(item.getItemId()) * (slotMax - item.getQuantity())); if (c.getPlayer().getMeso() >= price) { item.setQuantity(slotMax); c.getSession().write(CWvsContext.InventoryPacket.updateInventorySlot(MapleInventoryType.USE, item, false)); c.getPlayer().gainMeso(-price, false, false); c.getSession().write(CField.NPCPacket.confirmShopTransaction((byte) 0, this, c, -1)); } } } protected MapleShopItem findById(int itemId) { for (MapleShopItem item : this.items) { if (item.getItemId() == itemId) { return item; } } return null; } protected MapleShopItem findBySlot(short slot) { for (MapleShopItem item : this.items) { if (item.getSlot() == slot) { return item; } } return null; } protected MapleShopItem findBySlotAndId(int itemId, int slot) { MapleShopItem shopItem = (MapleShopItem) items.get(slot); if ((shopItem != null) && (shopItem.getItemId() == itemId)) { return shopItem; } return null; } public static MapleShop createFromDB(int id, boolean isShopId) { MapleShop ret = null; MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement(isShopId ? "SELECT * FROM shops WHERE shopid = ?" : "SELECT * FROM shops WHERE npcid = ?"); int shopId; ps.setInt(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { shopId = rs.getInt("shopid"); ret = new MapleShop(shopId, rs.getInt("npcid")); rs.close(); ps.close(); } else { rs.close(); ps.close(); return null; } ps = con.prepareStatement("SELECT * FROM shopitems WHERE shopid = ? ORDER BY position ASC"); ps.setInt(1, shopId); rs = ps.executeQuery(); List<Integer> recharges = new ArrayList(rechargeableItems); while (rs.next()) { if (ii.itemExists(rs.getInt("itemid"))) { if (ItemConstants.類型.可充值道具(rs.getInt("itemid"))) { MapleShopItem starItem = new MapleShopItem(rs.getShort("buyable"), ii.getSlotMax(rs.getInt("itemid")), rs.getInt("itemid"), rs.getInt("price"), (short) rs.getInt("position"), rs.getInt("reqitem"), rs.getInt("reqitemq"), rs.getByte("rank"), rs.getInt("category"), rs.getInt("minLevel"), rs.getInt("expiration"), false); ret.addItem(starItem); if (rechargeableItems.contains(starItem.getItemId())) { recharges.remove(Integer.valueOf(starItem.getItemId())); } } else { ret.addItem(new MapleShopItem(rs.getShort("buyable"), rs.getShort("quantity"), rs.getInt("itemid"), rs.getInt("price"), (short) rs.getInt("position"), rs.getInt("reqitem"), rs.getInt("reqitemq"), rs.getByte("rank"), rs.getInt("category"), rs.getInt("minLevel"), rs.getInt("expiration"), false)); //todo potential } } } for (Integer recharge : recharges) { ret.addItem(new MapleShopItem((short) 1, ii.getSlotMax(recharge), recharge, 0, (short) 0, 0, 0, (byte) 0, 0, 0, 0, false)); } rs.close(); ps.close(); ps = con.prepareStatement("SELECT * FROM shopranks WHERE shopid = ? ORDER BY rank ASC"); ps.setInt(1, shopId); rs = ps.executeQuery(); while (rs.next()) { if (ii.itemExists(rs.getInt("itemid"))) { ret.ranks.add(new Pair(rs.getInt("itemid"), rs.getString("name"))); } } rs.close(); ps.close(); } catch (SQLException e) { System.err.println("Could not load shop"); } return ret; } public int getNpcId() { return this.npcId; } public int getId() { return this.id; } public List<Pair<Integer, String>> getRanks() { return this.ranks; } }