GMS-like Wedding + Scissors of Karma + Maple Life + Buyback
Properly developed the Marriage feature in the source. Added TRAVEL_RATE server flag, a modifier for the travel frequency rate. Corrected stance for players in 3rd party view when entering a map to work similarly as GMS. Fixed mobs spamming skills incoherently. Added code support for old GMS-like PQ NPCs, where party leaders just need to click once to start a new PQ. Implemented podium system for the Hall of Fame PlayerNPCs. Improved character load-out system, now using way less queries to the DB in the process. Fixed birthday field for accounts not being read correctly. Further implemented the incomplete yet-existing Scissors of Karma mechanic. Fixed Duey not propagating item flags when packaging an item. Added a custom buyback system. Refactored the character creation system, now offering support for Maple Life. Fixed some issues with the PlayerNPC positioning system. Added server flag allowing AP assignment for novices (beginners under level 11). Fixed Strategy Time (GPQ) announcement being sent twice to guilds in certain cases. Tweaked mount EXP system now awarding it accordingly with the amount of tiredness healed. Removed the randomness aspect of closeness gain when feeding the pet, now acting accordingly with amount of fullness gained. Fixed an exploit with Arwen script. Fixed travel-back from Florina forcefully sending players to Lith Harbor in certain situations. Thoroughly reviewed job skill questlines for Explorers and Aran. Localhost edit: removed MTS block in certain maps (useful for the buyback system). Localhost edit: removed party blocks for novices. Localhost edit: removed AP assigning block for novices. Localhost edit: removed speed cap. Localhost edit: removed Maker block popping up when inputting ATK gems on non-weapons.
This commit is contained in:
@@ -1,631 +0,0 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package server;
|
||||
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.ModifyInventory;
|
||||
import client.newyear.NewYearCardRecord;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import tools.FilePrinter;
|
||||
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public class MapleInventoryManipulator {
|
||||
|
||||
public static boolean addById(MapleClient c, int itemId, short quantity) {
|
||||
return addById(c, itemId, quantity, null, -1, -1);
|
||||
}
|
||||
|
||||
public static boolean addById(MapleClient c, int itemId, short quantity, long expiration) {
|
||||
return addById(c, itemId, quantity, null, -1, (byte) 0, expiration);
|
||||
}
|
||||
|
||||
public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid) {
|
||||
return addById(c, itemId, quantity, owner, petid, -1);
|
||||
}
|
||||
|
||||
public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, long expiration) {
|
||||
return addById(c, itemId, quantity, owner, petid, (byte) 0, expiration);
|
||||
}
|
||||
|
||||
public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, byte flag, long expiration) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
MapleInventoryType type = ItemConstants.getInventoryType(itemId);
|
||||
if (!type.equals(MapleInventoryType.EQUIP)) {
|
||||
short slotMax = ii.getSlotMax(c, itemId);
|
||||
List<Item> existing = c.getPlayer().getInventory(type).listById(itemId);
|
||||
if (!ItemConstants.isRechargeable(itemId) && petid == -1) {
|
||||
if (existing.size() > 0) { // first update all existing slots to slotMax
|
||||
Iterator<Item> i = existing.iterator();
|
||||
while (quantity > 0) {
|
||||
if (i.hasNext()) {
|
||||
Item eItem = (Item) i.next();
|
||||
short oldQ = eItem.getQuantity();
|
||||
if (oldQ < slotMax && (eItem.getOwner().equals(owner) || owner == null)) {
|
||||
short newQ = (short) Math.min(oldQ + quantity, slotMax);
|
||||
quantity -= (newQ - oldQ);
|
||||
eItem.setQuantity(newQ);
|
||||
eItem.setExpiration(expiration);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(1, eItem))));
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (quantity > 0 || ItemConstants.isRechargeable(itemId)) {
|
||||
short newQ = (short) Math.min(quantity, slotMax);
|
||||
if (newQ != 0) {
|
||||
quantity -= newQ;
|
||||
Item nItem = new Item(itemId, (short) 0, newQ, petid);
|
||||
nItem.setFlag(flag);
|
||||
nItem.setExpiration(expiration);
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(nItem);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
if (owner != null) {
|
||||
nItem.setOwner(owner);
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
if ((ItemConstants.isRechargeable(itemId)) && quantity == 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Item nItem = new Item(itemId, (short) 0, quantity, petid);
|
||||
nItem.setFlag(flag);
|
||||
nItem.setExpiration(expiration);
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(nItem);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
}
|
||||
} else if (quantity == 1) {
|
||||
Item nEquip = ii.getEquipById(itemId);
|
||||
nEquip.setFlag(flag);
|
||||
nEquip.setExpiration(expiration);
|
||||
if (owner != null) {
|
||||
nEquip.setOwner(owner);
|
||||
}
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(nEquip);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nEquip))));
|
||||
} else {
|
||||
throw new RuntimeException("Trying to create equip with non-one quantity");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean addFromDrop(MapleClient c, Item item) {
|
||||
return addFromDrop(c, item, true);
|
||||
}
|
||||
|
||||
public static boolean addFromDrop(MapleClient c, Item item, boolean show) {
|
||||
return addFromDrop(c, item, show, item.getPetId());
|
||||
}
|
||||
|
||||
public static boolean addFromDrop(MapleClient c, Item item, boolean show, int petId) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
MapleInventoryType type = item.getInventoryType();
|
||||
if (ii.isPickupRestricted(item.getItemId()) && c.getPlayer().haveItemWithId(item.getItemId(), true)) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.showItemUnavailable());
|
||||
return false;
|
||||
}
|
||||
short quantity = item.getQuantity();
|
||||
if (!type.equals(MapleInventoryType.EQUIP)) {
|
||||
short slotMax = ii.getSlotMax(c, item.getItemId());
|
||||
List<Item> existing = c.getPlayer().getInventory(type).listById(item.getItemId());
|
||||
if (!ItemConstants.isRechargeable(item.getItemId()) && petId == -1) {
|
||||
if (existing.size() > 0) { // first update all existing slots to slotMax
|
||||
Iterator<Item> i = existing.iterator();
|
||||
while (quantity > 0) {
|
||||
if (i.hasNext()) {
|
||||
Item eItem = (Item) i.next();
|
||||
short oldQ = eItem.getQuantity();
|
||||
if (oldQ < slotMax && item.getOwner().equals(eItem.getOwner())) {
|
||||
short newQ = (short) Math.min(oldQ + quantity, slotMax);
|
||||
quantity -= (newQ - oldQ);
|
||||
eItem.setQuantity(newQ);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(1, eItem))));
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (quantity > 0) {
|
||||
short newQ = (short) Math.min(quantity, slotMax);
|
||||
quantity -= newQ;
|
||||
Item nItem = new Item(item.getItemId(), (short) 0, newQ, petId);
|
||||
nItem.setExpiration(item.getExpiration());
|
||||
nItem.setOwner(item.getOwner());
|
||||
nItem.setFlag(item.getFlag());
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(nItem);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
item.setQuantity((short) (quantity + newQ));
|
||||
return false;
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
}
|
||||
} else {
|
||||
Item nItem = new Item(item.getItemId(), (short) 0, quantity, petId);
|
||||
nItem.setExpiration(item.getExpiration());
|
||||
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(nItem);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, nItem))));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
} else if (quantity == 1) {
|
||||
short newSlot = c.getPlayer().getInventory(type).addItem(item);
|
||||
if (newSlot == -1) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return false;
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(0, item))));
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.ITEM, "Tried to pickup Equip id " + item.getItemId() + " containing more than 1 quantity --> " + quantity);
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.showItemUnavailable());
|
||||
return false;
|
||||
}
|
||||
if (show) {
|
||||
c.announce(MaplePacketCreator.getShowItemGain(item.getItemId(), item.getQuantity()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean haveItemWithId(MapleInventory inv, int itemid) {
|
||||
return inv.findById(itemid) != null;
|
||||
}
|
||||
|
||||
public static boolean checkSpace(MapleClient c, int itemid, int quantity, String owner) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
MapleInventoryType type = ItemConstants.getInventoryType(itemid);
|
||||
|
||||
if(ii.isPickupRestricted(itemid) && haveItemWithId(c.getPlayer().getInventory(type), itemid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!type.equals(MapleInventoryType.EQUIP)) {
|
||||
short slotMax = ii.getSlotMax(c, itemid);
|
||||
List<Item> existing = c.getPlayer().getInventory(type).listById(itemid);
|
||||
if (!ItemConstants.isRechargeable(itemid)) {
|
||||
if (existing.size() > 0) // first update all existing slots to slotMax
|
||||
{
|
||||
for (Item eItem : existing) {
|
||||
short oldQ = eItem.getQuantity();
|
||||
if (oldQ < slotMax && owner.equals(eItem.getOwner())) {
|
||||
short newQ = (short) Math.min(oldQ + quantity, slotMax);
|
||||
quantity -= (newQ - oldQ);
|
||||
}
|
||||
if (quantity <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final int numSlotsNeeded;
|
||||
if (slotMax > 0) {
|
||||
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
|
||||
} else if (ItemConstants.isRechargeable(itemid)) {
|
||||
numSlotsNeeded = 1;
|
||||
} else {
|
||||
numSlotsNeeded = 1;
|
||||
}
|
||||
return !c.getPlayer().getInventory(type).isFull(numSlotsNeeded - 1);
|
||||
} else {
|
||||
return !c.getPlayer().getInventory(type).isFull();
|
||||
}
|
||||
}
|
||||
|
||||
public static int checkSpaceProgressively(MapleClient c, int itemid, int quantity, String owner, int usedSlots) {
|
||||
// return value --> bit0: if has space for this one;
|
||||
// value after: new slots filled;
|
||||
// assumption: equipments always have slotMax == 1.
|
||||
|
||||
int returnValue;
|
||||
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
MapleInventoryType type = ItemConstants.getInventoryType(itemid);
|
||||
|
||||
if(ii.isPickupRestricted(itemid) && haveItemWithId(c.getPlayer().getInventory(type), itemid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!type.equals(MapleInventoryType.EQUIP)) {
|
||||
short slotMax = ii.getSlotMax(c, itemid);
|
||||
if (!ItemConstants.isRechargeable(itemid)) {
|
||||
List<Item> existing = c.getPlayer().getInventory(type).listById(itemid);
|
||||
|
||||
if (existing.size() > 0) // first update all existing slots to slotMax
|
||||
{
|
||||
for (Item eItem : existing) {
|
||||
short oldQ = eItem.getQuantity();
|
||||
if (oldQ < slotMax && owner.equals(eItem.getOwner())) {
|
||||
short newQ = (short) Math.min(oldQ + quantity, slotMax);
|
||||
quantity -= (newQ - oldQ);
|
||||
}
|
||||
if (quantity <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final int numSlotsNeeded;
|
||||
if (slotMax > 0) {
|
||||
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
|
||||
} else if (ItemConstants.isRechargeable(itemid)) {
|
||||
numSlotsNeeded = 1;
|
||||
} else {
|
||||
numSlotsNeeded = 1;
|
||||
}
|
||||
|
||||
returnValue = ((numSlotsNeeded + usedSlots) << 1);
|
||||
returnValue += (numSlotsNeeded == 0 || !c.getPlayer().getInventory(type).isFullAfterSomeItems(numSlotsNeeded - 1, usedSlots)) ? 1 : 0;
|
||||
//System.out.print(" needed " + numSlotsNeeded + " used " + usedSlots + " rval " + returnValue);
|
||||
} else {
|
||||
returnValue = ((quantity + usedSlots) << 1);
|
||||
returnValue += (!c.getPlayer().getInventory(type).isFullAfterSomeItems(0, usedSlots)) ? 1 : 0;
|
||||
//System.out.print(" eqpneeded " + 1 + " used " + usedSlots + " rval " + returnValue);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public static void removeFromSlot(MapleClient c, MapleInventoryType type, short slot, short quantity, boolean fromDrop) {
|
||||
removeFromSlot(c, type, slot, quantity, fromDrop, false);
|
||||
}
|
||||
|
||||
public static void removeFromSlot(MapleClient c, MapleInventoryType type, short slot, short quantity, boolean fromDrop, boolean consume) {
|
||||
Item item = c.getPlayer().getInventory(type).getItem(slot);
|
||||
boolean allowZero = consume && ItemConstants.isRechargeable(item.getItemId());
|
||||
c.getPlayer().getInventory(type).removeItem(slot, quantity, allowZero);
|
||||
if (item.getQuantity() == 0 && !allowZero) {
|
||||
c.announce(MaplePacketCreator.modifyInventory(fromDrop, Collections.singletonList(new ModifyInventory(3, item))));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.modifyInventory(fromDrop, Collections.singletonList(new ModifyInventory(1, item))));
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeById(MapleClient c, MapleInventoryType type, int itemId, int quantity, boolean fromDrop, boolean consume) {
|
||||
int removeQuantity = quantity;
|
||||
MapleInventory inv = c.getPlayer().getInventory(type);
|
||||
int slotLimit = type == MapleInventoryType.EQUIPPED ? 128 : inv.getSlotLimit();
|
||||
|
||||
for (short i = 0; i <= slotLimit; i++) {
|
||||
Item item = inv.getItem((short) (type == MapleInventoryType.EQUIPPED ? -i : i));
|
||||
if (item != null) {
|
||||
if (item.getItemId() == itemId || item.getCashId() == itemId) {
|
||||
if (removeQuantity <= item.getQuantity()) {
|
||||
removeFromSlot(c, type, item.getPosition(), (short) removeQuantity, fromDrop, consume);
|
||||
removeQuantity = 0;
|
||||
break;
|
||||
} else {
|
||||
removeQuantity -= item.getQuantity();
|
||||
removeFromSlot(c, type, item.getPosition(), item.getQuantity(), fromDrop, consume);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removeQuantity > 0) {
|
||||
throw new RuntimeException("[HACK] Not enough items available of Item:" + itemId + ", Quantity (After Quantity/Over Current Quantity): " + (quantity - removeQuantity) + "/" + quantity);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSameOwner(Item source, Item target) {
|
||||
return source.getOwner().equals(target.getOwner());
|
||||
}
|
||||
|
||||
public static void move(MapleClient c, MapleInventoryType type, short src, short dst) {
|
||||
if (src < 0 || dst < 0) {
|
||||
return;
|
||||
}
|
||||
if(dst > c.getPlayer().getInventory(type).getSlotLimit()) {
|
||||
return;
|
||||
}
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
Item source = c.getPlayer().getInventory(type).getItem(src);
|
||||
Item initialTarget = c.getPlayer().getInventory(type).getItem(dst);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
short olddstQ = -1;
|
||||
if (initialTarget != null) {
|
||||
olddstQ = initialTarget.getQuantity();
|
||||
}
|
||||
short oldsrcQ = source.getQuantity();
|
||||
short slotMax = ii.getSlotMax(c, source.getItemId());
|
||||
c.getPlayer().getInventory(type).move(src, dst, slotMax);
|
||||
final List<ModifyInventory> mods = new ArrayList<>();
|
||||
if (!(type.equals(MapleInventoryType.EQUIP) || type.equals(MapleInventoryType.CASH)) && initialTarget != null && initialTarget.getItemId() == source.getItemId() && !ItemConstants.isRechargeable(source.getItemId()) && isSameOwner(source, initialTarget)) {
|
||||
if ((olddstQ + oldsrcQ) > slotMax) {
|
||||
mods.add(new ModifyInventory(1, source));
|
||||
mods.add(new ModifyInventory(1, initialTarget));
|
||||
} else {
|
||||
mods.add(new ModifyInventory(3, source));
|
||||
mods.add(new ModifyInventory(1, initialTarget));
|
||||
}
|
||||
} else {
|
||||
mods.add(new ModifyInventory(2, source, src));
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, mods));
|
||||
}
|
||||
|
||||
public static void equip(MapleClient c, short src, short dst) {
|
||||
Equip source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(src);
|
||||
if (source == null || !MapleItemInformationProvider.getInstance().canWearEquipment(c.getPlayer(), source, dst)) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
} else if ((((source.getItemId() >= 1902000 && source.getItemId() <= 1902002) || source.getItemId() == 1912000) && c.getPlayer().isCygnus()) || ((source.getItemId() >= 1902005 && source.getItemId() <= 1902007) || source.getItemId() == 1912005) && !c.getPlayer().isCygnus()) {// Adventurer taming equipment
|
||||
return;
|
||||
}
|
||||
boolean itemChanged = false;
|
||||
if (MapleItemInformationProvider.getInstance().isUntradeableOnEquip(source.getItemId())) {
|
||||
source.setFlag((byte) ItemConstants.UNTRADEABLE);
|
||||
itemChanged = true;
|
||||
}
|
||||
if (source.getRingId() > -1) {
|
||||
c.getPlayer().getRingById(source.getRingId()).equip();
|
||||
}
|
||||
if (dst == -6) { // unequip the overall
|
||||
Item top = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((short) -5);
|
||||
if (top != null && ItemConstants.isOverall(top.getItemId())) {
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return;
|
||||
}
|
||||
unequip(c, (byte) -5, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot());
|
||||
}
|
||||
} else if (dst == -5) {
|
||||
final Item bottom = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((short) -6);
|
||||
if (bottom != null && ItemConstants.isOverall(source.getItemId())) {
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return;
|
||||
}
|
||||
unequip(c, (byte) -6, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot());
|
||||
}
|
||||
} else if (dst == -10) {// check if weapon is two-handed
|
||||
Item weapon = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((short) -11);
|
||||
if (weapon != null && MapleItemInformationProvider.getInstance().isTwoHanded(weapon.getItemId())) {
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return;
|
||||
}
|
||||
unequip(c, (byte) -11, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot());
|
||||
}
|
||||
} else if (dst == -11) {
|
||||
Item shield = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((short) -10);
|
||||
if (shield != null && MapleItemInformationProvider.getInstance().isTwoHanded(source.getItemId())) {
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
c.announce(MaplePacketCreator.getShowInventoryFull());
|
||||
return;
|
||||
}
|
||||
unequip(c, (byte) -10, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot());
|
||||
}
|
||||
}
|
||||
if (dst == -18) {
|
||||
if (c.getPlayer().getMount() != null) {
|
||||
c.getPlayer().getMount().setItemId(source.getItemId());
|
||||
}
|
||||
}
|
||||
if (source.getItemId() == 1122017) {
|
||||
c.getPlayer().equipPendantOfSpirit();
|
||||
}
|
||||
//1112413, 1112414, 1112405 (Lilin's Ring)
|
||||
source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(src);
|
||||
Equip target = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(dst);
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeSlot(src);
|
||||
if (target != null) {
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).removeSlot(dst);
|
||||
}
|
||||
|
||||
final List<ModifyInventory> mods = new ArrayList<>();
|
||||
if (itemChanged) {
|
||||
mods.add(new ModifyInventory(3, source));
|
||||
mods.add(new ModifyInventory(0, source.copy()));//to prevent crashes
|
||||
}
|
||||
|
||||
source.setPosition(dst);
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(source);
|
||||
if (target != null) {
|
||||
target.setPosition(src);
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(target);
|
||||
}
|
||||
if (c.getPlayer().getBuffedValue(MapleBuffStat.BOOSTER) != null && ItemConstants.isWeapon(source.getItemId())) {
|
||||
c.getPlayer().cancelBuffStats(MapleBuffStat.BOOSTER);
|
||||
}
|
||||
|
||||
mods.add(new ModifyInventory(2, source, src));
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, mods));
|
||||
c.getPlayer().equipChanged();
|
||||
}
|
||||
|
||||
public static void unequip(MapleClient c, short src, short dst) {
|
||||
Equip source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(src);
|
||||
Equip target = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(dst);
|
||||
if (dst < 0) {
|
||||
return;
|
||||
}
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
if (target != null && src <= 0) {
|
||||
c.announce(MaplePacketCreator.getInventoryFull());
|
||||
return;
|
||||
}
|
||||
if (source.getItemId() == 1122017) {
|
||||
c.getPlayer().unequipPendantOfSpirit();
|
||||
}
|
||||
if (source.getRingId() > -1) {
|
||||
c.getPlayer().getRingById(source.getRingId()).unequip();
|
||||
}
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).removeSlot(src);
|
||||
if (target != null) {
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeSlot(dst);
|
||||
}
|
||||
source.setPosition(dst);
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(source);
|
||||
if (target != null) {
|
||||
target.setPosition(src);
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(target);
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(2, source, src))));
|
||||
c.getPlayer().equipChanged();
|
||||
}
|
||||
|
||||
public static void drop(MapleClient c, MapleInventoryType type, short src, short quantity) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
if (src < 0) {
|
||||
type = MapleInventoryType.EQUIPPED;
|
||||
}
|
||||
Item source = c.getPlayer().getInventory(type).getItem(src);
|
||||
|
||||
if (c.getPlayer().getTrade() != null || c.getPlayer().getMiniGame() != null || source == null) { //Only check needed would prob be merchants (to see if the player is in one)
|
||||
return;
|
||||
}
|
||||
int itemId = source.getItemId();
|
||||
if (ItemConstants.isPet(itemId)) {
|
||||
return;
|
||||
}
|
||||
if (type == MapleInventoryType.EQUIPPED && itemId == 1122017) {
|
||||
c.getPlayer().unequipPendantOfSpirit();
|
||||
}
|
||||
if (c.getPlayer().getItemEffect() == itemId && source.getQuantity() == 1) {
|
||||
c.getPlayer().setItemEffect(0);
|
||||
c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.itemEffect(c.getPlayer().getId(), 0));
|
||||
} else if (itemId == 5370000 || itemId == 5370001) {
|
||||
if (c.getPlayer().getItemQuantity(itemId, false) == 1) {
|
||||
c.getPlayer().setChalkboard(null);
|
||||
}
|
||||
}
|
||||
if ((!ItemConstants.isRechargeable(itemId) && source.getQuantity() < quantity) || quantity < 0) {
|
||||
return;
|
||||
}
|
||||
Point dropPos = new Point(c.getPlayer().getPosition());
|
||||
if (quantity < source.getQuantity() && !ItemConstants.isRechargeable(itemId)) {
|
||||
Item target = source.copy();
|
||||
target.setQuantity(quantity);
|
||||
source.setQuantity((short) (source.getQuantity() - quantity));
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(1, source))));
|
||||
|
||||
if(ItemConstants.isNewYearCardEtc(itemId)) {
|
||||
if(itemId == 4300000) {
|
||||
NewYearCardRecord.removeAllNewYearCard(true, c.getPlayer());
|
||||
c.getAbstractPlayerInteraction().removeAll(4300000);
|
||||
} else {
|
||||
NewYearCardRecord.removeAllNewYearCard(false, c.getPlayer());
|
||||
c.getAbstractPlayerInteraction().removeAll(4301000);
|
||||
}
|
||||
}
|
||||
|
||||
boolean weddingRing = source.getItemId() == 1112803 || source.getItemId() == 1112806 || source.getItemId() == 1112807 || source.getItemId() == 1112809;
|
||||
if (weddingRing) {
|
||||
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos);
|
||||
} else if (c.getPlayer().getMap().getEverlast()) {
|
||||
if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
|
||||
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos);
|
||||
} else {
|
||||
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos, true, true);
|
||||
}
|
||||
} else if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
|
||||
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos);
|
||||
} else {
|
||||
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos, true, true);
|
||||
}
|
||||
} else {
|
||||
c.getPlayer().getInventory(type).removeSlot(src);
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(3, source))));
|
||||
if (src < 0) {
|
||||
c.getPlayer().equipChanged();
|
||||
} else if(ItemConstants.isNewYearCardEtc(itemId)) {
|
||||
if(itemId == 4300000) {
|
||||
NewYearCardRecord.removeAllNewYearCard(true, c.getPlayer());
|
||||
c.getAbstractPlayerInteraction().removeAll(4300000);
|
||||
} else {
|
||||
NewYearCardRecord.removeAllNewYearCard(false, c.getPlayer());
|
||||
c.getAbstractPlayerInteraction().removeAll(4301000);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.getPlayer().getMap().getEverlast()) {
|
||||
if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
|
||||
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos);
|
||||
} else {
|
||||
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos, true, true);
|
||||
}
|
||||
} else if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
|
||||
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos);
|
||||
} else {
|
||||
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDroppedItemRestricted(Item it) {
|
||||
return ServerConstants.USE_ERASE_UNTRADEABLE_DROP && ((it.getFlag() & ItemConstants.UNTRADEABLE) == ItemConstants.UNTRADEABLE);
|
||||
}
|
||||
}
|
||||
@@ -1350,8 +1350,8 @@ public class MapleItemInformationProvider {
|
||||
return null;
|
||||
}
|
||||
scriptedItem script = new scriptedItem(MapleDataTool.getInt("spec/npc", getItemData(itemId), 0),
|
||||
MapleDataTool.getString("spec/script", getItemData(itemId), ""),
|
||||
MapleDataTool.getInt("spec/runOnPickup", getItemData(itemId), 0) == 1);
|
||||
MapleDataTool.getString("spec/script", getItemData(itemId), ""),
|
||||
MapleDataTool.getInt("spec/runOnPickup", getItemData(itemId), 0) == 1);
|
||||
scriptedItemCache.put(itemId, script);
|
||||
return scriptedItemCache.get(itemId);
|
||||
}
|
||||
@@ -1538,8 +1538,12 @@ public class MapleItemInformationProvider {
|
||||
public boolean canWearEquipment(MapleCharacter chr, Equip equip, int dst) {
|
||||
int id = equip.getItemId();
|
||||
|
||||
String islot = getEquipmentSlot(id);
|
||||
if(ItemConstants.isWeddingRing(id) && chr.hasJustMarried()) {
|
||||
chr.dropMessage(5, "The Wedding Ring cannot be equipped on this map."); // will dc everyone due to doubled couple effect
|
||||
return false;
|
||||
}
|
||||
|
||||
String islot = getEquipmentSlot(id);
|
||||
if (!EquipSlot.getFromTextSlot(islot).isAllowed(dst, isCash(id))) {
|
||||
equip.wear(false);
|
||||
String itemName = MapleItemInformationProvider.getInstance().getName(equip.getItemId());
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package server;
|
||||
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
@@ -89,11 +90,12 @@ public class MapleShop {
|
||||
}
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
if (item.getPrice() > 0) {
|
||||
if (c.getPlayer().getMeso() >= (long) item.getPrice() * quantity) {
|
||||
int amount = (int)Math.min((float) item.getPrice() * quantity, Integer.MAX_VALUE);
|
||||
if (c.getPlayer().getMeso() >= amount) {
|
||||
if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) {
|
||||
if (!ItemConstants.isRechargeable(itemId)) { //Pets can't be bought from shops
|
||||
MapleInventoryManipulator.addById(c, itemId, quantity);
|
||||
c.getPlayer().gainMeso(-(item.getPrice() * quantity), false);
|
||||
c.getPlayer().gainMeso(-amount, false);
|
||||
} else {
|
||||
short slotMax = ii.getSlotMax(c, item.getItemId());
|
||||
quantity = slotMax;
|
||||
@@ -108,16 +110,18 @@ public class MapleShop {
|
||||
c.announce(MaplePacketCreator.shopTransaction((byte) 2));
|
||||
|
||||
} else if (item.getPitch() > 0) {
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.ETC).countById(4310000) >= (long) item.getPitch() * quantity) {
|
||||
int amount = (int)Math.min((float) item.getPitch() * quantity, Integer.MAX_VALUE);
|
||||
|
||||
if (c.getPlayer().getInventory(MapleInventoryType.ETC).countById(4310000) >= amount) {
|
||||
if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) {
|
||||
if (!ItemConstants.isRechargeable(itemId)) {
|
||||
MapleInventoryManipulator.addById(c, itemId, quantity);
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, item.getPitch() * quantity, false, false);
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, amount, false, false);
|
||||
} else {
|
||||
short slotMax = ii.getSlotMax(c, item.getItemId());
|
||||
quantity = slotMax;
|
||||
MapleInventoryManipulator.addById(c, itemId, quantity);
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, item.getPitch() * quantity, false, false);
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, amount, false, false);
|
||||
}
|
||||
c.announce(MaplePacketCreator.shopTransaction((byte) 0));
|
||||
} else
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package server;
|
||||
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
|
||||
+25
-14
@@ -32,7 +32,9 @@ import client.MapleCharacter;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ItemConstants;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import tools.Pair;
|
||||
|
||||
@@ -57,22 +59,22 @@ public class MapleTrade {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
private static int getFee(int meso) {
|
||||
int fee = 0;
|
||||
private static int getFee(long meso) {
|
||||
long fee = 0;
|
||||
if (meso >= 100000000) {
|
||||
fee = (int) Math.round(0.06 * meso);
|
||||
fee = (meso * 6) / 100;
|
||||
} else if (meso >= 25000000) {
|
||||
fee = meso / 20;
|
||||
fee = (meso * 5) / 100;
|
||||
} else if (meso >= 10000000) {
|
||||
fee = meso / 25;
|
||||
fee = (meso * 4) / 100;
|
||||
} else if (meso >= 5000000) {
|
||||
fee = (int) Math.round(.03 * meso);
|
||||
fee = (meso * 3) / 100;
|
||||
} else if (meso >= 1000000) {
|
||||
fee = (int) Math.round(.018 * meso);
|
||||
fee = (meso * 18) / 1000;
|
||||
} else if (meso >= 100000) {
|
||||
fee = meso / 125;
|
||||
fee = (meso * 8) / 1000;
|
||||
}
|
||||
return fee;
|
||||
return (int) fee;
|
||||
}
|
||||
|
||||
private void lockTrade() {
|
||||
@@ -91,14 +93,23 @@ public class MapleTrade {
|
||||
items.clear();
|
||||
meso = 0;
|
||||
for (Item item : exchangeItems) {
|
||||
if ((item.getFlag() & ItemConstants.KARMA) == ItemConstants.KARMA)
|
||||
item.setFlag((byte) (item.getFlag() ^ ItemConstants.KARMA)); //items with scissors of karma used on them are reset once traded
|
||||
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
|
||||
MapleInventoryManipulator.addFromDrop(chr.getClient(), item, show);
|
||||
}
|
||||
|
||||
if (exchangeMeso > 0) {
|
||||
chr.gainMeso(exchangeMeso - getFee(exchangeMeso), show, true, show);
|
||||
int fee = getFee(exchangeMeso);
|
||||
|
||||
chr.gainMeso(exchangeMeso - fee, show, true, show);
|
||||
if(fee > 0) {
|
||||
chr.dropMessage(1, "Transaction completed. You received " + GameConstants.numberWithCommas(exchangeMeso - fee) + " mesos due to trade fees.");
|
||||
} else {
|
||||
chr.dropMessage(1, "Transaction completed. You received " + GameConstants.numberWithCommas(exchangeMeso) + " mesos.");
|
||||
}
|
||||
} else {
|
||||
chr.dropMessage(1, "Transaction completed.");
|
||||
}
|
||||
|
||||
exchangeMeso = 0;
|
||||
if (exchangeItems != null) {
|
||||
exchangeItems.clear();
|
||||
|
||||
@@ -38,13 +38,13 @@ public class ChangeableStats extends OverrideMonsterStats {
|
||||
final double mod = (double) newLevel / (double) stats.getLevel();
|
||||
final double hpRatio = (double) stats.getHp() / (double) stats.getExp();
|
||||
final double pqMod = (pqMob ? 1.5 : 1.0); // god damn
|
||||
hp = (int) Math.round((!stats.isBoss() ? GameConstants.getMonsterHP(newLevel) : (stats.getHp() * mod)) * pqMod); // right here lol
|
||||
exp = (int) Math.round((!stats.isBoss() ? (GameConstants.getMonsterHP(newLevel) / hpRatio) : (stats.getExp())) * pqMod);
|
||||
mp = (int) Math.round(stats.getMp() * mod * pqMod);
|
||||
watk = (int) Math.round(stats.getPADamage() * mod);
|
||||
matk = (int) Math.round(stats.getMADamage() * mod);
|
||||
wdef = Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getPDDamage() * mod));
|
||||
mdef = Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getMDDamage() * mod));
|
||||
hp = Math.min((int) Math.round((!stats.isBoss() ? GameConstants.getMonsterHP(newLevel) : (stats.getHp() * mod)) * pqMod), Integer.MAX_VALUE); // right here lol
|
||||
exp = Math.min((int) Math.round((!stats.isBoss() ? (GameConstants.getMonsterHP(newLevel) / hpRatio) : (stats.getExp())) * pqMod), Integer.MAX_VALUE);
|
||||
mp = Math.min((int) Math.round(stats.getMp() * mod * pqMod), Integer.MAX_VALUE);
|
||||
watk = Math.min((int) Math.round(stats.getPADamage() * mod), Integer.MAX_VALUE);
|
||||
matk = Math.min((int) Math.round(stats.getMADamage() * mod), Integer.MAX_VALUE);
|
||||
wdef = Math.min(Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getPDDamage() * mod)), Integer.MAX_VALUE);
|
||||
mdef = Math.min(Math.min(stats.isBoss() ? 30 : 20, (int) Math.round(stats.getMDDamage() * mod)), Integer.MAX_VALUE);
|
||||
level = newLevel;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private AtomicInteger hp = new AtomicInteger(1);
|
||||
private AtomicLong maxHpPlusHeal = new AtomicLong(1);
|
||||
private int mp;
|
||||
private long nextBasicSkillTime;
|
||||
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
||||
private boolean controllerHasAggro, controllerKnowsAboutAggro;
|
||||
private Collection<MonsterListener> listeners = new LinkedList<>();
|
||||
@@ -394,7 +395,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
MapleParty p = mc.getParty();
|
||||
if (p != null) {
|
||||
int pID = p.getId();
|
||||
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
|
||||
long pXP = (long) xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
|
||||
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
|
||||
} else {
|
||||
if(mc.getLevel() >= minThresholdLevel) {
|
||||
@@ -460,7 +461,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
|
||||
MapleCharacter controller = getController();
|
||||
if (controller != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||
controller.getClient().announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
controller.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
controller.stopControllingMonster(this);
|
||||
}
|
||||
|
||||
@@ -1138,6 +1139,14 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
}
|
||||
|
||||
public long getNextBasicSkillTime() {
|
||||
return nextBasicSkillTime;
|
||||
}
|
||||
|
||||
public void setNextBasicSkillTime(long time) {
|
||||
nextBasicSkillTime = time + 4200;
|
||||
}
|
||||
|
||||
public int getNoSkills() {
|
||||
return this.stats.getNoSkills();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
package server.life;
|
||||
|
||||
import server.life.positioner.MaplePlayerNPCPositioner;
|
||||
import server.life.positioner.MaplePlayerNPCPodium;
|
||||
import java.awt.Point;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@@ -41,6 +43,7 @@ import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.world.World;
|
||||
@@ -58,7 +61,7 @@ import tools.Pair;
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
private static final Map<Byte, AtomicInteger> runningPlayerNpcScriptIds = new HashMap<>();
|
||||
private static final Map<Byte, List<Integer>> availablePlayerNpcScriptIds = new HashMap<>();
|
||||
private static final AtomicInteger runningOverallRank = new AtomicInteger();
|
||||
private static final List<AtomicInteger> runningWorldRank = new ArrayList<>();
|
||||
private static final Map<Pair<Integer, Integer>, AtomicInteger> runningWorldJobRank = new HashMap<>();
|
||||
@@ -220,7 +223,6 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
|
||||
getRunningPlayerNpcScriptIds(con);
|
||||
getRunningOverallRanks(con);
|
||||
getRunningWorldRanks(con);
|
||||
getRunningWorldJobRanks(con);
|
||||
@@ -231,25 +233,6 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
private static void getRunningPlayerNpcScriptIds(Connection con) throws SQLException {
|
||||
PreparedStatement ps = con.prepareStatement("SELECT floor(scriptid / 100), max(scriptid) FROM playernpcs GROUP BY floor(scriptid / 100) ORDER BY floor(scriptid / 100)");
|
||||
ResultSet rs = ps.executeQuery();
|
||||
|
||||
while(rs.next()) {
|
||||
byte branch = (byte) (rs.getInt(1) % 100);
|
||||
int maxid = rs.getInt(2);
|
||||
|
||||
if(branch < 26) {
|
||||
runningPlayerNpcScriptIds.put(branch, new AtomicInteger(maxid));
|
||||
} else {
|
||||
runningPlayerNpcScriptIds.put((byte)(branch - ((branch - 26) % 4)), new AtomicInteger(maxid));
|
||||
}
|
||||
}
|
||||
|
||||
rs.close();
|
||||
ps.close();
|
||||
}
|
||||
|
||||
private static void getRunningOverallRanks(Connection con) throws SQLException {
|
||||
PreparedStatement ps = con.prepareStatement("SELECT max(overallrank) FROM playernpcs");
|
||||
ResultSet rs = ps.executeQuery();
|
||||
@@ -356,17 +339,69 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
private static MaplePlayerNPC createPlayerNPCInternal(MapleMap map, Point pos, MapleCharacter chr) {
|
||||
if(pos == null) {
|
||||
pos = map.getNextPlayerNpcPosition();
|
||||
if(pos == null) {
|
||||
return null;
|
||||
private static void fetchAvailableScriptIdsFromDb(byte branch, List<Integer> list) {
|
||||
try {
|
||||
int branchLen = (branch < 26) ? 100 : 400;
|
||||
int branchSid = 9900000 + (branch * 100);
|
||||
int nextBranchSid = branchSid + branchLen;
|
||||
Set<Integer> usedScriptIds = new HashSet<>();
|
||||
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT scriptid FROM playernpcs WHERE scriptid >= ? AND scriptid < ? ORDER BY scriptid");
|
||||
ps.setInt(1, branchSid);
|
||||
ps.setInt(2, nextBranchSid);
|
||||
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
usedScriptIds.add(rs.getInt(1));
|
||||
}
|
||||
|
||||
List<Integer> availables = new ArrayList<>(20);
|
||||
int j = 0;
|
||||
for(int i = branchSid; i < nextBranchSid; i++) {
|
||||
if(!usedScriptIds.contains(i)) {
|
||||
availables.add(i);
|
||||
j++;
|
||||
|
||||
if(j == 20) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rs.close();
|
||||
ps.close();
|
||||
con.close();
|
||||
|
||||
for(int i = availables.size() - 1; i >= 0; i--) {
|
||||
list.add(availables.get(i));
|
||||
}
|
||||
} catch(SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNextScriptId(byte branch) {
|
||||
List<Integer> availablesBranch = availablePlayerNpcScriptIds.get(branch);
|
||||
|
||||
if(availablesBranch == null) {
|
||||
availablesBranch = new ArrayList<>(20);
|
||||
availablePlayerNpcScriptIds.put(branch, availablesBranch);
|
||||
}
|
||||
|
||||
if(availablesBranch.isEmpty()) {
|
||||
fetchAvailableScriptIdsFromDb(branch, availablesBranch);
|
||||
|
||||
if(availablesBranch.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return availablesBranch.remove(availablesBranch.size() - 1);
|
||||
}
|
||||
|
||||
private static MaplePlayerNPC createPlayerNPCInternal(MapleMap map, Point pos, MapleCharacter chr) {
|
||||
int mapId = map.getId();
|
||||
int worldId = chr.getWorld();
|
||||
int jobId = (chr.getJob().getId() / 100) * 100;
|
||||
|
||||
/*
|
||||
if(!canSpawnPlayerNpc(chr.getName(), mapId)) {
|
||||
@@ -376,18 +411,28 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
|
||||
byte branch = GameConstants.getHallOfFameBranch(chr.getJob(), mapId);
|
||||
|
||||
int scriptId;
|
||||
try {
|
||||
scriptId = runningPlayerNpcScriptIds.get(branch).getAndIncrement();
|
||||
int scriptId = getNextScriptId(branch);
|
||||
if (scriptId == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(pos == null) {
|
||||
if(GameConstants.isPodiumHallOfFameMap(map.getId())) {
|
||||
pos = MaplePlayerNPCPodium.getNextPlayerNpcPosition(map);
|
||||
} else {
|
||||
pos = MaplePlayerNPCPositioner.getNextPlayerNpcPosition(map);
|
||||
}
|
||||
|
||||
if(!GameConstants.canPnpcBranchUseScriptId(branch, scriptId)) {
|
||||
if(pos == null) {
|
||||
return null;
|
||||
}
|
||||
} catch (NullPointerException npe) {
|
||||
scriptId = 9900000 + (branch * 100);
|
||||
runningPlayerNpcScriptIds.put(branch, new AtomicInteger(scriptId + 1));
|
||||
}
|
||||
|
||||
if(ServerConstants.USE_DEBUG) System.out.println("GOT SID " + scriptId + " POS " + pos);
|
||||
|
||||
int worldId = chr.getWorld();
|
||||
int jobId = (chr.getJob().getId() / 100) * 100;
|
||||
|
||||
MaplePlayerNPC ret;
|
||||
int npcId;
|
||||
try {
|
||||
@@ -516,8 +561,9 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public static boolean spawnPlayerNPC(int mapid, Point pos, MapleCharacter chr) {
|
||||
MaplePlayerNPC pn = processPlayerNPCInternal(chr.getClient().getChannelServer().getMapFactory().getMap(mapid), pos, chr, true).getLeft();
|
||||
if(chr == null) return false;
|
||||
|
||||
MaplePlayerNPC pn = processPlayerNPCInternal(chr.getClient().getChannelServer().getMapFactory().getMap(mapid), pos, chr, true).getLeft();
|
||||
if(pn != null) {
|
||||
for (Channel channel : Server.getInstance().getChannelsFromWorld(chr.getWorld())) {
|
||||
MapleMap m = channel.getMapFactory().getMap(mapid);
|
||||
@@ -547,6 +593,8 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public static void removePlayerNPC(MapleCharacter chr) {
|
||||
if(chr == null) return;
|
||||
|
||||
List<Integer> updateMapids = processPlayerNPCInternal(null, null, chr, false).getRight();
|
||||
int worldid = updateMapids.remove(0);
|
||||
|
||||
@@ -608,8 +656,10 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
PreparedStatement ps = con.prepareStatement("SELECT DISTINCT world, map FROM playernpcs");
|
||||
ResultSet rs = ps.executeQuery();
|
||||
|
||||
int wsize = Server.getInstance().getWorlds().size();
|
||||
while(rs.next()) {
|
||||
int world = rs.getInt("world"), map = rs.getInt("map");
|
||||
if(world >= wsize) continue;
|
||||
|
||||
World w = Server.getInstance().getWorld(world);
|
||||
for (Channel channel : w.getChannels()) {
|
||||
@@ -636,6 +686,14 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
|
||||
ps = con.prepareStatement("DELETE FROM playernpcs_field");
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
|
||||
for(World w : Server.getInstance().getWorlds()) {
|
||||
w.resetPlayerNpcMapData();
|
||||
}
|
||||
|
||||
con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
*/
|
||||
package server.life;
|
||||
|
||||
import constants.GameConstants;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import net.server.Server;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
@@ -52,7 +52,7 @@ public class MaplePlayerNPCFactory {
|
||||
if(thisData != null) {
|
||||
MapleData md = thisData.getChildByPath("anthem/brazil");
|
||||
if(md != null) {
|
||||
GameConstants.setAvailableDeveloperRoom();
|
||||
Server.getInstance().setAvailableDeveloperRoom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package server.life.positioner;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import server.life.MaplePlayerNPC;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*
|
||||
* Note: the podium uses getGroundBelow that in its turn uses inputted posY decremented by 7.
|
||||
* Podium system will implement increase-by-7 to negate that behaviour.
|
||||
*/
|
||||
public class MaplePlayerNPCPodium {
|
||||
private static int getPlatformPosX(int platform) {
|
||||
switch(platform) {
|
||||
case 0:
|
||||
return -50;
|
||||
|
||||
case 1:
|
||||
return -170;
|
||||
|
||||
default:
|
||||
return 70;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getPlatformPosY(int platform) {
|
||||
switch(platform) {
|
||||
case 0:
|
||||
return -47;
|
||||
|
||||
default:
|
||||
return 40;
|
||||
}
|
||||
}
|
||||
|
||||
private static Point calcNextPos(int rank, int step) {
|
||||
int podiumPlatform = rank / step;
|
||||
int relativePos = (rank % step) + 1;
|
||||
|
||||
Point pos = new Point(getPlatformPosX(podiumPlatform) + ((100 * relativePos) / (step + 1)), getPlatformPosY(podiumPlatform));
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static Point rearrangePlayerNpcs(MapleMap map, int newStep, List<MaplePlayerNPC> pnpcs) {
|
||||
int i = 0;
|
||||
for(MaplePlayerNPC pn : pnpcs) {
|
||||
pn.updatePlayerNPCPosition(map, calcNextPos(i, newStep));
|
||||
i++;
|
||||
}
|
||||
|
||||
return calcNextPos(i, newStep);
|
||||
}
|
||||
|
||||
private static Point reorganizePlayerNpcs(MapleMap map, int newStep, List<MapleMapObject> mmoList) {
|
||||
if(!mmoList.isEmpty()) {
|
||||
if(ServerConstants.USE_DEBUG) System.out.println("Reorganizing pnpc map, step " + newStep);
|
||||
|
||||
List<MaplePlayerNPC> playerNpcs = new ArrayList<>(mmoList.size());
|
||||
for(MapleMapObject mmo : mmoList) {
|
||||
playerNpcs.add((MaplePlayerNPC) mmo);
|
||||
}
|
||||
|
||||
Collections.sort(playerNpcs, new Comparator<MaplePlayerNPC>() {
|
||||
@Override
|
||||
public int compare(MaplePlayerNPC p1, MaplePlayerNPC p2) {
|
||||
return p1.getScriptId() - p2.getScriptId(); // scriptid as playernpc history
|
||||
}
|
||||
});
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(map.getWorld())) {
|
||||
MapleMap m = ch.getMapFactory().getMap(map.getId());
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
m.removeMapObject(pn);
|
||||
m.broadcastMessage(MaplePacketCreator.removeNPCController(pn.getObjectId()));
|
||||
m.broadcastMessage(MaplePacketCreator.removePlayerNPC(pn.getObjectId()));
|
||||
}
|
||||
}
|
||||
|
||||
Point ret = rearrangePlayerNpcs(map, newStep, playerNpcs);
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(map.getWorld())) {
|
||||
MapleMap m = ch.getMapFactory().getMap(map.getId());
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
m.addPlayerNPCMapObject(pn);
|
||||
m.broadcastMessage(MaplePacketCreator.spawnPlayerNPC(pn));
|
||||
m.broadcastMessage(MaplePacketCreator.getPlayerNPC(pn));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int encodePodiumData(int podiumStep, int podiumCount) {
|
||||
return (podiumCount * (1 << 5)) + podiumStep;
|
||||
}
|
||||
|
||||
private static Point getNextPlayerNpcPosition(MapleMap map, int podiumData) { // automated playernpc position thanks to Ronan
|
||||
int podiumStep = podiumData % (1 << 5), podiumCount = (podiumData / (1 << 5));
|
||||
|
||||
if(podiumCount >= 3 * podiumStep) {
|
||||
if(podiumStep >= ServerConstants.PLAYERNPC_AREA_STEPS) return null;
|
||||
|
||||
List<MapleMapObject> mmoList = map.getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER_NPC));
|
||||
Server.getInstance().getWorld(map.getWorld()).setPlayerNpcMapPodiumData(map.getId(), encodePodiumData(podiumStep + 1, podiumCount + 1));
|
||||
return reorganizePlayerNpcs(map, podiumStep + 1, mmoList);
|
||||
} else {
|
||||
Server.getInstance().getWorld(map.getWorld()).setPlayerNpcMapPodiumData(map.getId(), encodePodiumData(podiumStep, podiumCount + 1));
|
||||
return calcNextPos(podiumCount, podiumStep);
|
||||
}
|
||||
}
|
||||
|
||||
public static Point getNextPlayerNpcPosition(MapleMap map) {
|
||||
Point pos = getNextPlayerNpcPosition(map, Server.getInstance().getWorld(map.getWorld()).getPlayerNpcMapPodiumData(map.getId()));
|
||||
if(pos == null) return null;
|
||||
|
||||
return map.getGroundBelow(pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package server.life.positioner;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import server.life.MaplePlayerNPC;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*
|
||||
*/
|
||||
public class MaplePlayerNPCPositioner {
|
||||
|
||||
private static boolean isPlayerNpcNearby(List<Point> otherPos, Point searchPos, int xLimit, int yLimit) {
|
||||
int xLimit2 = xLimit / 2, yLimit2 = yLimit / 2;
|
||||
|
||||
Rectangle searchRect = new Rectangle(searchPos.x - xLimit2, searchPos.y - yLimit2, xLimit, yLimit);
|
||||
for(Point pos : otherPos) {
|
||||
Rectangle otherRect = new Rectangle(pos.x - xLimit2, pos.y - yLimit2, xLimit, yLimit);
|
||||
|
||||
if(otherRect.intersects(searchRect)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int calcDx(int newStep) {
|
||||
return ServerConstants.PLAYERNPC_AREA_X / (newStep + 1);
|
||||
}
|
||||
|
||||
private static int calcDy(int newStep) {
|
||||
return (ServerConstants.PLAYERNPC_AREA_Y / 2) + (ServerConstants.PLAYERNPC_AREA_Y / (1 << (newStep + 1)));
|
||||
}
|
||||
|
||||
private static List<Point> rearrangePlayerNpcPositions(MapleMap map, int newStep, int pnpcsSize) {
|
||||
Rectangle mapArea = map.getMapArea();
|
||||
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
int cx = calcDx(newStep), cy = calcDy(newStep);
|
||||
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = map.getPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
otherPlayerNpcs.add(searchPos);
|
||||
|
||||
if(otherPlayerNpcs.size() == pnpcsSize) {
|
||||
return otherPlayerNpcs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Point rearrangePlayerNpcs(MapleMap map, int newStep, List<MaplePlayerNPC> pnpcs) {
|
||||
Rectangle mapArea = map.getMapArea();
|
||||
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
int cx = calcDx(newStep), cy = calcDy(newStep);
|
||||
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
int i = 0;
|
||||
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = map.getPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
if(i == pnpcs.size()) {
|
||||
return searchPos;
|
||||
}
|
||||
|
||||
MaplePlayerNPC pn = pnpcs.get(i);
|
||||
i++;
|
||||
|
||||
pn.updatePlayerNPCPosition(map, searchPos);
|
||||
otherPlayerNpcs.add(searchPos);
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
return null; // this area should not be reached under any scenario
|
||||
}
|
||||
|
||||
private static Point reorganizePlayerNpcs(MapleMap map, int newStep, List<MapleMapObject> mmoList) {
|
||||
if(!mmoList.isEmpty()) {
|
||||
if(ServerConstants.USE_DEBUG) System.out.println("Reorganizing pnpc map, step " + newStep);
|
||||
|
||||
List<MaplePlayerNPC> playerNpcs = new ArrayList<>(mmoList.size());
|
||||
for(MapleMapObject mmo : mmoList) {
|
||||
playerNpcs.add((MaplePlayerNPC) mmo);
|
||||
}
|
||||
|
||||
Collections.sort(playerNpcs, new Comparator<MaplePlayerNPC>() {
|
||||
@Override
|
||||
public int compare(MaplePlayerNPC p1, MaplePlayerNPC p2) {
|
||||
return p1.getScriptId() - p2.getScriptId(); // scriptid as playernpc history
|
||||
}
|
||||
});
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(map.getWorld())) {
|
||||
MapleMap m = ch.getMapFactory().getMap(map.getId());
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
m.removeMapObject(pn);
|
||||
m.broadcastMessage(MaplePacketCreator.removeNPCController(pn.getObjectId()));
|
||||
m.broadcastMessage(MaplePacketCreator.removePlayerNPC(pn.getObjectId()));
|
||||
}
|
||||
}
|
||||
|
||||
Point ret = rearrangePlayerNpcs(map, newStep, playerNpcs);
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(map.getWorld())) {
|
||||
MapleMap m = ch.getMapFactory().getMap(map.getId());
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
m.addPlayerNPCMapObject(pn);
|
||||
m.broadcastMessage(MaplePacketCreator.spawnPlayerNPC(pn));
|
||||
m.broadcastMessage(MaplePacketCreator.getPlayerNPC(pn));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Point getNextPlayerNpcPosition(MapleMap map, int initStep) { // automated playernpc position thanks to Ronan
|
||||
List<MapleMapObject> mmoList = map.getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER_NPC));
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
for(MapleMapObject mmo : mmoList) {
|
||||
otherPlayerNpcs.add(mmo.getPosition());
|
||||
}
|
||||
|
||||
int cx = calcDx(initStep), cy = calcDy(initStep);
|
||||
Rectangle mapArea = map.getMapArea();
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
boolean reorganize = false;
|
||||
|
||||
int i = initStep;
|
||||
while(i < ServerConstants.PLAYERNPC_AREA_STEPS) {
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = map.getPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
if(i > initStep) {
|
||||
Server.getInstance().getWorld(map.getWorld()).setPlayerNpcMapStep(map.getId(), i);
|
||||
}
|
||||
|
||||
if(reorganize && ServerConstants.PLAYERNPC_ORGANIZE_AREA) {
|
||||
return reorganizePlayerNpcs(map, i, mmoList);
|
||||
}
|
||||
|
||||
return searchPos;
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
reorganize = true;
|
||||
i++;
|
||||
|
||||
cx = calcDx(i);
|
||||
cy = calcDy(i);
|
||||
if(ServerConstants.PLAYERNPC_ORGANIZE_AREA) {
|
||||
otherPlayerNpcs = rearrangePlayerNpcPositions(map, i, mmoList.size());
|
||||
}
|
||||
}
|
||||
|
||||
if(i > initStep) {
|
||||
Server.getInstance().getWorld(map.getWorld()).setPlayerNpcMapStep(map.getId(), ServerConstants.PLAYERNPC_AREA_STEPS - 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Point getNextPlayerNpcPosition(MapleMap map) {
|
||||
return getNextPlayerNpcPosition(map, Server.getInstance().getWorld(map.getWorld()).getPlayerNpcMapStep(map.getId()));
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,9 @@ import client.inventory.Item;
|
||||
import client.inventory.ItemFactory;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import com.mysql.jdbc.Statement;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -41,7 +42,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.Server;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -214,11 +214,9 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((newItem.getFlag() & ItemConstants.KARMA) == ItemConstants.KARMA) {
|
||||
newItem.setFlag((byte) (newItem.getFlag() ^ ItemConstants.KARMA));
|
||||
}
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(newItem);
|
||||
|
||||
int price = (int) Math.min((long)pItem.getPrice() * quantity, Integer.MAX_VALUE);
|
||||
int price = (int) Math.min((float) pItem.getPrice() * quantity, Integer.MAX_VALUE);
|
||||
if (c.getPlayer().getMeso() >= price) {
|
||||
if (canBuy(c, newItem)) {
|
||||
c.getPlayer().gainMeso(-price, false);
|
||||
|
||||
+51
-236
@@ -83,6 +83,7 @@ import server.life.SpawnPoint;
|
||||
import server.partyquest.MonsterCarnival;
|
||||
import server.partyquest.MonsterCarnivalParty;
|
||||
//import server.partyquest.Pyramid;
|
||||
import scripting.event.EventManager;
|
||||
import scripting.event.EventInstanceManager;
|
||||
import server.life.MaplePlayerNPC;
|
||||
import server.life.MonsterListener;
|
||||
@@ -191,6 +192,14 @@ public class MapleMap {
|
||||
return event;
|
||||
}
|
||||
|
||||
public Rectangle getMapArea() {
|
||||
return mapArea;
|
||||
}
|
||||
|
||||
public int getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public void broadcastMessage(MapleCharacter source, final byte[] packet) {
|
||||
chrRLock.lock();
|
||||
try {
|
||||
@@ -596,7 +605,9 @@ public class MapleMap {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
for (final MonsterDropEntry de : dropEntry) {
|
||||
if (Randomizer.nextInt(999999) < (long) de.chance * chRate) {
|
||||
int dropChance = (int) Math.min((float) de.chance * chRate, Integer.MAX_VALUE);
|
||||
|
||||
if (Randomizer.nextInt(999999) < dropChance) {
|
||||
if (droptype == 3) {
|
||||
pos.x = (int) (mobpos + ((d % 2 == 0) ? (40 * ((d + 1) / 2)) : -(40 * (d / 2))));
|
||||
} else {
|
||||
@@ -1147,35 +1158,19 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void broadcastBalrogVictory(String leaderName) {
|
||||
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
|
||||
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
|
||||
player.dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive.");
|
||||
}
|
||||
}
|
||||
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive.");
|
||||
}
|
||||
|
||||
public void broadcastHorntailVictory() {
|
||||
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
|
||||
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
|
||||
player.dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!");
|
||||
}
|
||||
}
|
||||
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!");
|
||||
}
|
||||
|
||||
public void broadcastZakumVictory() {
|
||||
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
|
||||
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
|
||||
player.dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!");
|
||||
}
|
||||
}
|
||||
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!");
|
||||
}
|
||||
|
||||
public void broadcastPinkBeanVictory(int channel) {
|
||||
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
|
||||
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
|
||||
player.dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!");
|
||||
}
|
||||
}
|
||||
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!");
|
||||
}
|
||||
|
||||
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) {
|
||||
@@ -1742,6 +1737,10 @@ public class MapleMap {
|
||||
spos.y--;//shouldn't be null!
|
||||
return spos;
|
||||
}
|
||||
|
||||
public Point getPointBelow(Point pos) {
|
||||
return calcPointBelow(pos);
|
||||
}
|
||||
|
||||
public void spawnRevives(final MapleMonster monster) {
|
||||
monster.setMap(this);
|
||||
@@ -2279,10 +2278,13 @@ public class MapleMap {
|
||||
chr.cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING);
|
||||
chr.cancelBuffStats(MapleBuffStat.MONSTER_RIDING);
|
||||
}
|
||||
if (mapid == 923010000 && getMonsterById(9300102) == null) { // Kenta's Mount Quest
|
||||
spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300102), new Point(77, 426));
|
||||
if (mapid == 923010000) { // Kenta's Mount Quest
|
||||
if(getMonsterById(9300102) == null) {
|
||||
spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9300102), new Point(77, 426));
|
||||
}
|
||||
} else if (mapid == 200090060) { // To Rien
|
||||
chr.announce(MaplePacketCreator.getClock(60));
|
||||
int travelTime = EventManager.getTransportationTime(1 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2291,9 +2293,10 @@ public class MapleMap {
|
||||
chr.changeMap(140020300, 0);
|
||||
}
|
||||
}
|
||||
}, 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 200090070) { // To Lith Harbor
|
||||
chr.announce(MaplePacketCreator.getClock(60));
|
||||
int travelTime = EventManager.getTransportationTime(1 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2302,9 +2305,10 @@ public class MapleMap {
|
||||
chr.changeMap(104000000, 3);
|
||||
}
|
||||
}
|
||||
}, 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 200090030) { // To Ereve (SkyFerry)
|
||||
chr.getClient().announce(MaplePacketCreator.getClock(2 * 60));
|
||||
int travelTime = EventManager.getTransportationTime(2 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2313,9 +2317,10 @@ public class MapleMap {
|
||||
chr.changeMap(130000210, 0);
|
||||
}
|
||||
}
|
||||
}, 2 * 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 200090031) { // To Victoria Island (SkyFerry)
|
||||
chr.getClient().announce(MaplePacketCreator.getClock(2 * 60));
|
||||
int travelTime = EventManager.getTransportationTime(2 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2324,9 +2329,10 @@ public class MapleMap {
|
||||
chr.changeMap(101000400, 0);
|
||||
}
|
||||
}
|
||||
}, 2 * 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 200090021) { // To Orbis (SkyFerry)
|
||||
chr.getClient().announce(MaplePacketCreator.getClock(8 * 60));
|
||||
int travelTime = EventManager.getTransportationTime(8 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2335,9 +2341,10 @@ public class MapleMap {
|
||||
chr.changeMap(200000161, 0);
|
||||
}
|
||||
}
|
||||
}, 8 * 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 200090020) { // To Ereve From Orbis (SkyFerry)
|
||||
chr.getClient().announce(MaplePacketCreator.getClock(8 * 60));
|
||||
int travelTime = EventManager.getTransportationTime(8 * 60 * 1000);
|
||||
chr.announce(MaplePacketCreator.getClock(travelTime / 1000));
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -2346,7 +2353,7 @@ public class MapleMap {
|
||||
chr.changeMap(130000210, 0);
|
||||
}
|
||||
}
|
||||
}, 8 * 60 * 1000);
|
||||
}, travelTime);
|
||||
} else if (mapid == 103040400) {
|
||||
if (chr.getEventInstance() != null) {
|
||||
chr.getEventInstance().movePlayer(chr);
|
||||
@@ -2366,13 +2373,13 @@ public class MapleMap {
|
||||
}
|
||||
}
|
||||
if (chr.isHidden()) {
|
||||
broadcastGMMessage(chr, MaplePacketCreator.spawnPlayerMapObject(chr), false);
|
||||
broadcastGMMessage(chr, MaplePacketCreator.spawnEnterPlayerMapObject(chr), false);
|
||||
chr.announce(MaplePacketCreator.getGMEffect(0x10, (byte) 1));
|
||||
|
||||
List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DARKSIGHT, 0));
|
||||
broadcastGMMessage(chr, MaplePacketCreator.giveForeignBuff(chr.getId(), dsstat), false);
|
||||
} else {
|
||||
broadcastMessage(chr, MaplePacketCreator.spawnPlayerMapObject(chr), false);
|
||||
broadcastMessage(chr, MaplePacketCreator.spawnEnterPlayerMapObject(chr), false);
|
||||
}
|
||||
|
||||
sendObjectPlacement(chr.getClient());
|
||||
@@ -2699,7 +2706,7 @@ public class MapleMap {
|
||||
broadcastMessage(MaplePacketCreator.serverNotice(type, message));
|
||||
}
|
||||
|
||||
private boolean isNonRangedType(MapleMapObjectType type) {
|
||||
private static boolean isNonRangedType(MapleMapObjectType type) {
|
||||
switch (type) {
|
||||
case NPC:
|
||||
case PLAYER:
|
||||
@@ -2726,7 +2733,11 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
for (MapleMapObject o : objects) {
|
||||
if (o.getType() == MapleMapObjectType.SUMMON) {
|
||||
if (isNonRangedType(o.getType())) {
|
||||
o.sendSpawnData(mapleClient);
|
||||
} else if (o.getType() == MapleMapObjectType.MONSTER) {
|
||||
updateMonsterController((MapleMonster) o);
|
||||
} else if (o.getType() == MapleMapObjectType.SUMMON) {
|
||||
MapleSummon summon = (MapleSummon) o;
|
||||
if (summon.getOwner() == chr) {
|
||||
if (chr.isSummonsEmpty() || !chr.containsSummon(summon)) {
|
||||
@@ -2737,15 +2748,10 @@ public class MapleMap {
|
||||
objectWLock.unlock();
|
||||
}
|
||||
|
||||
continue;
|
||||
//continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isNonRangedType(o.getType())) {
|
||||
o.sendSpawnData(mapleClient);
|
||||
} else if (o.getType() == MapleMapObjectType.MONSTER) {
|
||||
updateMonsterController((MapleMonster) o);
|
||||
}
|
||||
}
|
||||
|
||||
if (chr != null) {
|
||||
@@ -3789,195 +3795,4 @@ public class MapleMap {
|
||||
spawnMonsterOnGroundBelow(m, targetPoint);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPlayerNpcNearby(List<Point> otherPos, Point searchPos, int xLimit, int yLimit) {
|
||||
int xLimit2 = xLimit / 2, yLimit2 = yLimit / 2;
|
||||
|
||||
Rectangle searchRect = new Rectangle(searchPos.x - xLimit2, searchPos.y - yLimit2, xLimit, yLimit);
|
||||
for(Point pos : otherPos) {
|
||||
Rectangle otherRect = new Rectangle(pos.x - xLimit2, pos.y - yLimit2, xLimit, yLimit);
|
||||
|
||||
if(otherRect.intersects(searchRect)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int calcDx(int newStep) {
|
||||
return ServerConstants.PLAYERNPC_AREA_X / (newStep + 1);
|
||||
}
|
||||
|
||||
private static int calcDy(int newStep) {
|
||||
return (ServerConstants.PLAYERNPC_AREA_Y / 2) + (ServerConstants.PLAYERNPC_AREA_Y / (1 << (newStep + 1)));
|
||||
}
|
||||
|
||||
private List<Point> rearrangePlayerNpcPositions(int newStep, int pnpcsSize) {
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
int cx = calcDx(newStep), cy = calcDy(newStep);
|
||||
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = calcPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
otherPlayerNpcs.add(searchPos);
|
||||
|
||||
if(otherPlayerNpcs.size() == pnpcsSize) {
|
||||
return otherPlayerNpcs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Point rearrangePlayerNpcs(int newStep, List<MaplePlayerNPC> pnpcs) {
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
int cx = calcDx(newStep), cy = calcDy(newStep);
|
||||
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
int i = 0;
|
||||
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = calcPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
if(i == pnpcs.size()) {
|
||||
return searchPos;
|
||||
}
|
||||
|
||||
MaplePlayerNPC pn = pnpcs.get(i);
|
||||
i++;
|
||||
|
||||
pn.updatePlayerNPCPosition(this, searchPos);
|
||||
otherPlayerNpcs.add(searchPos);
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
return null; // this area should not be reached under any scenario
|
||||
}
|
||||
|
||||
private Point reorganizePlayerNpcs(int newStep, List<MapleMapObject> mmoList) {
|
||||
if(!mmoList.isEmpty()) {
|
||||
List<MaplePlayerNPC> playerNpcs = new ArrayList<>(mmoList.size());
|
||||
for(MapleMapObject mmo : mmoList) {
|
||||
playerNpcs.add((MaplePlayerNPC) mmo);
|
||||
}
|
||||
|
||||
Collections.sort(playerNpcs, new Comparator<MaplePlayerNPC>() {
|
||||
@Override
|
||||
public int compare(MaplePlayerNPC p1, MaplePlayerNPC p2) {
|
||||
return p1.getScriptId() - p2.getScriptId(); // scriptid as playernpc history
|
||||
}
|
||||
});
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(world)) {
|
||||
MapleMap map = ch.getMapFactory().getMap(mapid);
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
map.removeMapObject(pn);
|
||||
map.broadcastMessage(MaplePacketCreator.removeNPCController(pn.getObjectId()));
|
||||
map.broadcastMessage(MaplePacketCreator.removePlayerNPC(pn.getObjectId()));
|
||||
}
|
||||
}
|
||||
|
||||
Point ret = rearrangePlayerNpcs(newStep, playerNpcs);
|
||||
|
||||
for(Channel ch : Server.getInstance().getChannelsFromWorld(world)) {
|
||||
MapleMap map = ch.getMapFactory().getMap(mapid);
|
||||
|
||||
for(MaplePlayerNPC pn : playerNpcs) {
|
||||
map.addPlayerNPCMapObject(pn);
|
||||
map.broadcastMessage(MaplePacketCreator.spawnPlayerNPC(pn));
|
||||
map.broadcastMessage(MaplePacketCreator.getPlayerNPC(pn));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Point getNextPlayerNpcPosition() {
|
||||
return getNextPlayerNpcPosition(Server.getInstance().getWorld(world).getPlayerNpcMapStep(mapid));
|
||||
}
|
||||
|
||||
private Point getNextPlayerNpcPosition(int initStep) { // automated playernpc position thanks to Ronan
|
||||
List<MapleMapObject> mmoList = getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER_NPC));
|
||||
List<Point> otherPlayerNpcs = new LinkedList<>();
|
||||
for(MapleMapObject mmo : mmoList) {
|
||||
otherPlayerNpcs.add(mmo.getPosition());
|
||||
}
|
||||
|
||||
int cx = calcDx(initStep), cy = calcDy(initStep);
|
||||
int outx = mapArea.x + mapArea.width - ServerConstants.PLAYERNPC_INITIAL_X, outy = mapArea.y + mapArea.height;
|
||||
boolean reorganize = false;
|
||||
|
||||
int i = initStep;
|
||||
while(i < ServerConstants.PLAYERNPC_AREA_STEPS) {
|
||||
int leftPx = mapArea.x + ServerConstants.PLAYERNPC_INITIAL_X, px, py = mapArea.y + ServerConstants.PLAYERNPC_INITIAL_Y;
|
||||
|
||||
while(py < outy) {
|
||||
px = leftPx;
|
||||
|
||||
while(px < outx) {
|
||||
Point searchPos = calcPointBelow(new Point(px, py));
|
||||
if(searchPos != null) {
|
||||
if(!isPlayerNpcNearby(otherPlayerNpcs, searchPos, cx, cy)) {
|
||||
if(i > initStep) {
|
||||
Server.getInstance().getWorld(world).setPlayerNpcMapStep(mapid, i);
|
||||
}
|
||||
|
||||
if(reorganize && ServerConstants.PLAYERNPC_ORGANIZE_AREA) {
|
||||
return reorganizePlayerNpcs(i, mmoList);
|
||||
}
|
||||
|
||||
return searchPos;
|
||||
}
|
||||
}
|
||||
|
||||
px += cx;
|
||||
}
|
||||
|
||||
py += cy;
|
||||
}
|
||||
|
||||
reorganize = true;
|
||||
i++;
|
||||
|
||||
cx = calcDx(i);
|
||||
cy = calcDy(i);
|
||||
if(ServerConstants.PLAYERNPC_ORGANIZE_AREA) {
|
||||
otherPlayerNpcs = rearrangePlayerNpcPositions(i, mmoList.size());
|
||||
}
|
||||
}
|
||||
|
||||
if(i > initStep) {
|
||||
Server.getInstance().getWorld(world).setPlayerNpcMapStep(mapid, ServerConstants.PLAYERNPC_AREA_STEPS - 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ItemConstants;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import constants.ServerConstants;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -38,7 +39,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.SendOpcode;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -237,13 +237,11 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((newItem.getFlag() & ItemConstants.KARMA) == ItemConstants.KARMA) {
|
||||
newItem.setFlag((byte) (newItem.getFlag() ^ ItemConstants.KARMA));
|
||||
}
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(newItem);
|
||||
|
||||
visitorLock.lock();
|
||||
try {
|
||||
int price = (int) Math.min((long)pItem.getPrice() * quantity, Integer.MAX_VALUE);
|
||||
int price = (int) Math.min((float)pItem.getPrice() * quantity, Integer.MAX_VALUE);
|
||||
|
||||
if (c.getPlayer().getMeso() >= price) {
|
||||
if (canBuy(c, newItem)) {
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataTool;
|
||||
import server.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import server.quest.MapleQuest;
|
||||
import server.quest.MapleQuestActionType;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
Reference in New Issue
Block a user