Autosave feature + Pet Ignore fix
Added experimental autosaver feature. Fixed pet ignore feature not saving/loading data in some cases. Added concurrency protection for inventory classes and monster book.
This commit is contained in:
@@ -4529,26 +4529,31 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement ps2;
|
||||
ResultSet rs2;
|
||||
for(byte i = 0; i < 3; i++) {
|
||||
MaplePet pet = ret.getPet(i);
|
||||
if(pet == null) continue;
|
||||
|
||||
int petId = pet.getUniqueId();
|
||||
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?"); // Get pet details..
|
||||
PreparedStatement ps2, ps3;
|
||||
ResultSet rs2, rs3;
|
||||
|
||||
ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1");
|
||||
ps3.setInt(1, charid);
|
||||
rs3 = ps3.executeQuery();
|
||||
while(rs3.next()) {
|
||||
int petId = rs3.getInt("petid");
|
||||
|
||||
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?");
|
||||
ps2.setInt(1, petId);
|
||||
|
||||
|
||||
ret.resetExcluded(petId);
|
||||
|
||||
rs2 = ps2.executeQuery();
|
||||
while(rs2.next()) {
|
||||
ret.addExcluded(petId, rs2.getInt("itemid"));
|
||||
}
|
||||
|
||||
|
||||
ps2.close();
|
||||
rs2.close();
|
||||
}
|
||||
ps3.close();
|
||||
rs3.close();
|
||||
|
||||
ret.commitExcludedItems();
|
||||
|
||||
if (channelserver) {
|
||||
@@ -5525,10 +5530,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
// synchronize this call instead of trying to give access all at once (?)
|
||||
public synchronized void saveToDB() {
|
||||
public void saveToDB() {
|
||||
if(ServerConstants.USE_AUTOSAVE) {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
saveToDB(true);
|
||||
}
|
||||
};
|
||||
|
||||
Thread t = new Thread(r); //spawns a new thread to deal with this
|
||||
t.start();
|
||||
} else {
|
||||
saveToDB(true);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void saveToDB(boolean notAutosave) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString());
|
||||
|
||||
if(notAutosave) FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString());
|
||||
else FilePrinter.print(FilePrinter.AUTOSAVING_CHARACTER, "Attempting to autosave " + name + " at " + c.getTime().toString());
|
||||
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
@@ -5577,7 +5600,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
ps.setInt(22, meso.get());
|
||||
ps.setInt(23, hpMpApUsed);
|
||||
if (map == null || map.getId() == 610020000 || map.getId() == 610020001) {
|
||||
if (map == null || map.getId() == 610020000 || map.getId() == 610020001) { // reset to first spawnpoint on those maps
|
||||
ps.setInt(24, 0);
|
||||
} else {
|
||||
MaplePortal closest = map.findClosestPlayerSpawnpoint(getPosition());
|
||||
@@ -5648,7 +5671,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
petLock.unlock();
|
||||
}
|
||||
|
||||
for(Entry<Integer, Set<Integer>> es: getExcluded().entrySet()) {
|
||||
for(Entry<Integer, Set<Integer>> es: getExcluded().entrySet()) { // this set is already protected
|
||||
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) {
|
||||
ps2.setInt(1, es.getKey());
|
||||
ps2.executeUpdate();
|
||||
@@ -5667,8 +5690,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?");
|
||||
ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
|
||||
ps.setInt(1, id);
|
||||
for (Entry<Integer, MapleKeyBinding> keybinding : keymap.entrySet()) {
|
||||
ps.setInt(2, keybinding.getKey().intValue());
|
||||
|
||||
Set<Entry<Integer, MapleKeyBinding>> keybindingItems = Collections.unmodifiableSet(keymap.entrySet());
|
||||
for (Entry<Integer, MapleKeyBinding> keybinding : keybindingItems) {
|
||||
ps.setInt(2, keybinding.getKey());
|
||||
ps.setInt(3, keybinding.getValue().getType());
|
||||
ps.setInt(4, keybinding.getValue().getAction());
|
||||
ps.addBatch();
|
||||
@@ -5691,14 +5716,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
ps.executeBatch();
|
||||
|
||||
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
|
||||
|
||||
for (MapleInventory iv : inventory) {
|
||||
for (Item item : iv.list()) {
|
||||
itemsWithType.add(new Pair<>(item, iv.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
ItemFactory.INVENTORY.saveItems(itemsWithType, id, con);
|
||||
|
||||
deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?");
|
||||
@@ -6283,7 +6307,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
if (slots <= 96) {
|
||||
inventory[type].setSlotLimit(slots);
|
||||
|
||||
saveToDB();
|
||||
this.saveToDB();
|
||||
if (update) {
|
||||
client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots));
|
||||
}
|
||||
@@ -6552,6 +6576,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true);
|
||||
|
||||
removePet(pet, shift_left);
|
||||
commitExcludedItems();
|
||||
|
||||
client.announce(MaplePacketCreator.petStatUpdate(this));
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
|
||||
+99
-40
@@ -25,9 +25,13 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
@@ -36,85 +40,140 @@ public final class MonsterBook {
|
||||
private int normalCard = 0;
|
||||
private int bookLevel = 1;
|
||||
private Map<Integer, Integer> cards = new LinkedHashMap<>();
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
private Set<Entry<Integer, Integer>> getCardSet() {
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableSet(cards.entrySet());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addCard(final MapleClient c, final int cardid) {
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignCardEffect(c.getPlayer().getId()), false);
|
||||
for (Entry<Integer, Integer> all : cards.entrySet()) {
|
||||
if (all.getKey() == cardid) {
|
||||
if (all.getValue() > 4) {
|
||||
c.announce(MaplePacketCreator.addCard(true, cardid, all.getValue()));
|
||||
|
||||
Integer qty;
|
||||
lock.lock();
|
||||
try {
|
||||
qty = cards.get(cardid);
|
||||
|
||||
if(qty != null) {
|
||||
if(qty < 5) {
|
||||
cards.put(cardid, qty + 1);
|
||||
}
|
||||
} else {
|
||||
cards.put(cardid, 1);
|
||||
qty = 0;
|
||||
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
} else {
|
||||
all.setValue(all.getValue() + 1);
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, all.getValue()));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
calculateLevel();
|
||||
normalCard++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
cards.put(cardid, 1);
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, 1));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
calculateLevel();
|
||||
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
if(qty < 5) {
|
||||
calculateLevel(); // current leveling system only accounts unique cards...
|
||||
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, qty + 1));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
} else {
|
||||
normalCard++;
|
||||
c.announce(MaplePacketCreator.addCard(true, cardid, 5));
|
||||
}
|
||||
|
||||
//c.getPlayer().saveToDB(); //is it REALLY needed to save to DB every new entry?
|
||||
}
|
||||
|
||||
private void calculateLevel() {
|
||||
bookLevel = (int) Math.max(1, Math.sqrt((normalCard + specialCard) / 5));
|
||||
lock.lock();
|
||||
try {
|
||||
bookLevel = (int) Math.max(1, Math.sqrt((normalCard + specialCard) / 5));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getBookLevel() {
|
||||
return bookLevel;
|
||||
lock.lock();
|
||||
try {
|
||||
return bookLevel;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getCards() {
|
||||
return cards;
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableMap(cards);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalCards() {
|
||||
return specialCard + normalCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return specialCard + normalCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getNormalCard() {
|
||||
return normalCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return normalCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSpecialCard() {
|
||||
return specialCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return specialCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadCards(final int charid) throws SQLException {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) {
|
||||
ps.setInt(1, charid);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
int cardid, level;
|
||||
while (rs.next()) {
|
||||
cardid = rs.getInt("cardid");
|
||||
level = rs.getInt("level");
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
} else {
|
||||
normalCard++;
|
||||
lock.lock();
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) {
|
||||
ps.setInt(1, charid);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
int cardid, level;
|
||||
while (rs.next()) {
|
||||
cardid = rs.getInt("cardid");
|
||||
level = rs.getInt("level");
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
} else {
|
||||
normalCard++;
|
||||
}
|
||||
cards.put(cardid, level);
|
||||
}
|
||||
cards.put(cardid, level);
|
||||
}
|
||||
}
|
||||
|
||||
con.close();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
con.close();
|
||||
calculateLevel();
|
||||
}
|
||||
|
||||
public void saveCards(final int charid) {
|
||||
if (cards.isEmpty()) {
|
||||
Set<Entry<Integer, Integer>> cardSet = getCardSet();
|
||||
|
||||
if (cardSet.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -125,7 +184,7 @@ public final class MonsterBook {
|
||||
ps.close();
|
||||
boolean first = true;
|
||||
StringBuilder query = new StringBuilder();
|
||||
for (Entry<Integer, Integer> all : cards.entrySet()) {
|
||||
for (Entry<Integer, Integer> all : cardSet) {
|
||||
if (first) {
|
||||
query.append("INSERT INTO monsterbook VALUES (");
|
||||
first = false;
|
||||
|
||||
@@ -141,7 +141,6 @@ public enum ItemFactory {
|
||||
ResultSet rs = null;
|
||||
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("DELETE `inventoryitems`, `inventoryequipment` FROM `inventoryitems` LEFT JOIN `inventoryequipment` USING(`inventoryitemid`) WHERE `type` = ? AND `");
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import tools.Pair;
|
||||
import client.MapleCharacter;
|
||||
@@ -36,6 +38,7 @@ import client.MapleClient;
|
||||
import constants.ItemConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleInventoryManipulator;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -47,6 +50,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
private byte slotLimit;
|
||||
private MapleInventoryType type;
|
||||
private boolean checked = false;
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
|
||||
this.owner = mc;
|
||||
@@ -64,15 +68,34 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public byte getSlotLimit() {
|
||||
return slotLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
return slotLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSlotLimit(int newLimit) {
|
||||
slotLimit = (byte) newLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
slotLimit = (byte) newLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Item> list() {
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableCollection(inventory.values());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Item findById(int itemId) {
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
return item;
|
||||
}
|
||||
@@ -81,10 +104,10 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public Item findByName(String name) {
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
|
||||
if(itemName == null) {
|
||||
System.out.println("[CRITICAL] Item " + item.getItemId() + " has no name.");
|
||||
FilePrinter.printError(FilePrinter.EXCEPTION, "[CRITICAL] Item " + item.getItemId() + " has no name.");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -97,7 +120,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
public int countById(int itemId) {
|
||||
int qty = 0;
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
qty += item.getQuantity();
|
||||
}
|
||||
@@ -138,7 +161,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
public List<Item> listById(int itemId) {
|
||||
List<Item> ret = new ArrayList<>();
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
ret.add(item);
|
||||
}
|
||||
@@ -149,10 +172,6 @@ public class MapleInventory implements Iterable<Item> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Collection<Item> list() {
|
||||
return inventory.values();
|
||||
}
|
||||
|
||||
public short addItem(Item item) {
|
||||
short slotId = getNextFreeSlot();
|
||||
if (slotId < 0 || item == null) {
|
||||
@@ -171,29 +190,34 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public void move(short sSlot, short dSlot, short slotMax) {
|
||||
Item source = (Item) inventory.get(sSlot);
|
||||
Item target = (Item) inventory.get(dSlot);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
if (target == null) {
|
||||
source.setPosition(dSlot);
|
||||
inventory.put(dSlot, source);
|
||||
inventory.remove(sSlot);
|
||||
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) {
|
||||
if (type.getType() == MapleInventoryType.EQUIP.getType()) {
|
||||
lock.lock();
|
||||
try {
|
||||
Item source = (Item) inventory.get(sSlot);
|
||||
Item target = (Item) inventory.get(dSlot);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
if (target == null) {
|
||||
source.setPosition(dSlot);
|
||||
inventory.put(dSlot, source);
|
||||
inventory.remove(sSlot);
|
||||
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) {
|
||||
if (type.getType() == MapleInventoryType.EQUIP.getType()) {
|
||||
swap(target, source);
|
||||
}
|
||||
if (source.getQuantity() + target.getQuantity() > slotMax) {
|
||||
short rest = (short) ((source.getQuantity() + target.getQuantity()) - slotMax);
|
||||
source.setQuantity(rest);
|
||||
target.setQuantity(slotMax);
|
||||
} else {
|
||||
target.setQuantity((short) (source.getQuantity() + target.getQuantity()));
|
||||
inventory.remove(sSlot);
|
||||
}
|
||||
} else {
|
||||
swap(target, source);
|
||||
}
|
||||
if (source.getQuantity() + target.getQuantity() > slotMax) {
|
||||
short rest = (short) ((source.getQuantity() + target.getQuantity()) - slotMax);
|
||||
source.setQuantity(rest);
|
||||
target.setQuantity(slotMax);
|
||||
} else {
|
||||
target.setQuantity((short) (source.getQuantity() + target.getQuantity()));
|
||||
inventory.remove(sSlot);
|
||||
}
|
||||
} else {
|
||||
swap(target, source);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +232,12 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public Item getItem(short slot) {
|
||||
return inventory.get(slot);
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.get(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(short slot) {
|
||||
@@ -216,7 +245,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public void removeItem(short slot, short quantity, boolean allowZero) {
|
||||
Item item = inventory.get(slot);
|
||||
Item item = getItem(slot);
|
||||
if (item == null) {// TODO is it ok not to throw an exception here?
|
||||
return;
|
||||
}
|
||||
@@ -230,7 +259,12 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public void addSlot(short slot, Item item) {
|
||||
inventory.put(slot, item);
|
||||
lock.lock();
|
||||
try {
|
||||
inventory.put(slot, item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
if(ItemConstants.isRateCoupon(item.getItemId())) {
|
||||
owner.updateCouponRates();
|
||||
@@ -238,7 +272,13 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public void removeSlot(short slot) {
|
||||
Item item = inventory.remove(slot);
|
||||
Item item;
|
||||
lock.lock();
|
||||
try {
|
||||
item = inventory.remove(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
if(item != null && ItemConstants.isRateCoupon(item.getItemId())) {
|
||||
owner.updateCouponRates();
|
||||
@@ -246,40 +286,67 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return inventory.size() >= slotLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size() >= slotLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFull(int margin) {
|
||||
return inventory.size() + margin >= slotLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size() + margin >= slotLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFullAfterSomeItems(int margin, int used) {
|
||||
return inventory.size() + margin >= slotLimit - used;
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size() + margin >= slotLimit - used;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public short getNextFreeSlot() {
|
||||
if (isFull()) {
|
||||
return -1;
|
||||
}
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.keySet().contains(i)) {
|
||||
return i;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.containsKey(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public short getNumFreeSlot() {
|
||||
if (isFull()) {
|
||||
return 0;
|
||||
}
|
||||
short free = 0;
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.keySet().contains(i)) {
|
||||
free++;
|
||||
}
|
||||
}
|
||||
return free;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
short free = 0;
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.containsKey(i)) {
|
||||
free++;
|
||||
}
|
||||
}
|
||||
return free;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkSpot(MapleCharacter chr, Item item) {
|
||||
@@ -394,7 +461,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
@Override
|
||||
public Iterator<Item> iterator() {
|
||||
return Collections.unmodifiableCollection(inventory.values()).iterator();
|
||||
return Collections.unmodifiableCollection(list()).iterator();
|
||||
}
|
||||
|
||||
public Collection<MapleInventory> allInventories() {
|
||||
@@ -404,7 +471,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
public Item findByCashId(int cashId) {
|
||||
boolean isRing = false;
|
||||
Equip equip = null;
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getType() == MapleInventoryType.EQUIP.getType()) {
|
||||
equip = (Equip) item;
|
||||
isRing = equip.getRingId() > -1;
|
||||
@@ -417,10 +484,20 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public boolean checked() {
|
||||
return checked;
|
||||
lock.lock();
|
||||
try {
|
||||
return checked;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void checked(boolean yes) {
|
||||
checked = yes;
|
||||
lock.lock();
|
||||
try {
|
||||
checked = yes;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ public class ServerConstants {
|
||||
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
|
||||
public static final boolean USE_PARTY_SEARCH = false;
|
||||
public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
|
||||
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
|
||||
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly to required secondary stat on equipments.
|
||||
public static final boolean USE_REFRESH_RANK_MOVE = true;
|
||||
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 net.server;
|
||||
|
||||
import net.server.world.World;
|
||||
import client.MapleCharacter;
|
||||
import constants.ServerConstants;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class CharacterAutosaverWorker implements Runnable {
|
||||
private World wserv;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if(!ServerConstants.USE_AUTOSAVE) return;
|
||||
|
||||
PlayerStorage ps = wserv.getPlayerStorage();
|
||||
for(MapleCharacter chr: ps.getAllCharacters()) {
|
||||
if(chr != null && chr.isLoggedin()) {
|
||||
chr.saveToDB(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CharacterAutosaverWorker(World world) {
|
||||
wserv = world;
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,6 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
|
||||
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
|
||||
chr.cancelExpirationTask();
|
||||
chr.saveToDB();
|
||||
System.out.println("STRANGE SAVE TO DB");
|
||||
chr.getMap().removePlayer(c.getPlayer());
|
||||
try {
|
||||
c.announce(MaplePacketCreator.openCashShop(c, true));
|
||||
|
||||
@@ -90,7 +90,8 @@ public final class SpawnPetHandler extends AbstractMaplePacketHandler {
|
||||
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
|
||||
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
|
||||
chr.commitExcludedItems();
|
||||
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ import java.util.HashSet;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import server.TimerManager;
|
||||
import net.server.PetFullnessWorker;
|
||||
import net.server.CharacterAutosaverWorker;
|
||||
import net.server.MountTirednessWorker;
|
||||
import net.server.PetFullnessWorker;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
@@ -82,7 +83,9 @@ public class World {
|
||||
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> mountsSchedule;
|
||||
private long mountUpdate;
|
||||
|
||||
|
||||
private ScheduledFuture<?> charactersSchedule;
|
||||
|
||||
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
|
||||
this.id = world;
|
||||
this.flag = flag;
|
||||
@@ -99,6 +102,7 @@ public class World {
|
||||
|
||||
petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
|
||||
mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
|
||||
charactersSchedule = TimerManager.getInstance().register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
public List<Channel> getChannels() {
|
||||
|
||||
+33
-12
@@ -30,6 +30,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
@@ -43,6 +45,7 @@ import client.inventory.ItemFactory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.ItemConstants;
|
||||
import java.util.Collections;
|
||||
|
||||
/*
|
||||
* @author Flav
|
||||
@@ -99,12 +102,13 @@ public class CashShop {
|
||||
item = new Item(itemId, (byte) 0, count, petid);
|
||||
}
|
||||
|
||||
if (ItemConstants.EXPIRING_ITEMS)
|
||||
if(itemId == 5211048 || itemId == 5360042) { // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
|
||||
}
|
||||
if (ItemConstants.EXPIRING_ITEMS) {
|
||||
if(itemId == 5211048 || itemId == 5360042) { // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
|
||||
}
|
||||
}
|
||||
item.setSN(sn);
|
||||
return item;
|
||||
}
|
||||
@@ -237,6 +241,7 @@ public class CashShop {
|
||||
private List<Item> inventory = new ArrayList<>();
|
||||
private List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
@@ -325,13 +330,18 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public List<Item> getInventory() {
|
||||
return inventory;
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableList(inventory);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Item findByCashId(int cashId) {
|
||||
boolean isRing = false;
|
||||
Equip equip = null;
|
||||
for (Item item : inventory) {
|
||||
for (Item item : getInventory()) {
|
||||
if (item.getType() == 1) {
|
||||
equip = (Equip) item;
|
||||
isRing = equip.getRingId() > -1;
|
||||
@@ -345,11 +355,21 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public void addToInventory(Item item) {
|
||||
inventory.add(item);
|
||||
lock.lock();
|
||||
try {
|
||||
inventory.add(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromInventory(Item item) {
|
||||
inventory.remove(item);
|
||||
lock.lock();
|
||||
try {
|
||||
inventory.remove(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Integer> getWishList() {
|
||||
@@ -458,7 +478,8 @@ public class CashShop {
|
||||
ps.close();
|
||||
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
|
||||
|
||||
for (Item item : inventory) {
|
||||
List<Item> inv = getInventory();
|
||||
for (Item item : inv) {
|
||||
itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId())));
|
||||
}
|
||||
|
||||
@@ -466,7 +487,7 @@ public class CashShop {
|
||||
ps = con.prepareStatement("DELETE FROM `wishlists` WHERE `charid` = ?");
|
||||
ps.setInt(1, characterId);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
ps.close();
|
||||
ps = con.prepareStatement("INSERT INTO `wishlists` VALUES (DEFAULT, ?, ?)");
|
||||
ps.setInt(1, characterId);
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -47,10 +49,11 @@ import tools.Pair;
|
||||
public class MapleStorage {
|
||||
|
||||
private int id;
|
||||
private List<Item> items;
|
||||
private int meso;
|
||||
private byte slots;
|
||||
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
|
||||
private List<Item> items;
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
private MapleStorage(int id, byte slots, int meso) {
|
||||
this.id = id;
|
||||
@@ -135,7 +138,8 @@ public class MapleStorage {
|
||||
}
|
||||
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
|
||||
|
||||
for (Item item : items) {
|
||||
List<Item> list = getItems();
|
||||
for (Item item : list) {
|
||||
itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId())));
|
||||
}
|
||||
|
||||
@@ -146,30 +150,56 @@ public class MapleStorage {
|
||||
}
|
||||
|
||||
public Item getItem(byte slot) {
|
||||
return items.get(slot);
|
||||
lock.lock();
|
||||
try {
|
||||
return items.get(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Item takeOut(byte slot) {
|
||||
Item ret = items.remove(slot);
|
||||
Item ret;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
ret = items.remove(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(ret.getItemId());
|
||||
typeItems.put(type, new ArrayList<>(filterItems(type)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void store(Item item) {
|
||||
items.add(item);
|
||||
lock.lock();
|
||||
try {
|
||||
items.add(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId());
|
||||
typeItems.put(type, new ArrayList<>(filterItems(type)));
|
||||
}
|
||||
|
||||
public List<Item> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableList(items);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Item> filterItems(MapleInventoryType type) {
|
||||
List<Item> storageItems = getItems();
|
||||
List<Item> ret = new LinkedList<>();
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
for (Item item : items) {
|
||||
|
||||
for (Item item : storageItems) {
|
||||
if (ii.getInventoryType(item.getItemId()) == type) {
|
||||
ret.add(item);
|
||||
}
|
||||
@@ -179,7 +209,8 @@ public class MapleStorage {
|
||||
|
||||
public byte getSlot(MapleInventoryType type, byte slot) {
|
||||
byte ret = 0;
|
||||
for (Item item : items) {
|
||||
List<Item> storageItems = getItems();
|
||||
for (Item item : storageItems) {
|
||||
if (item == typeItems.get(type).get(slot)) {
|
||||
return ret;
|
||||
}
|
||||
@@ -190,21 +221,29 @@ public class MapleStorage {
|
||||
|
||||
public void sendStorage(MapleClient c, int npcId) {
|
||||
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
Collections.sort(items, new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(Item o1, Item o2) {
|
||||
if (ii.getInventoryType(o1.getItemId()).getType() < ii.getInventoryType(o2.getItemId()).getType()) {
|
||||
return -1;
|
||||
} else if (ii.getInventoryType(o1.getItemId()) == ii.getInventoryType(o2.getItemId())) {
|
||||
return 0;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
Collections.sort(items, new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(Item o1, Item o2) {
|
||||
if (ii.getInventoryType(o1.getItemId()).getType() < ii.getInventoryType(o2.getItemId()).getType()) {
|
||||
return -1;
|
||||
} else if (ii.getInventoryType(o1.getItemId()) == ii.getInventoryType(o2.getItemId())) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
for (MapleInventoryType type : MapleInventoryType.values()) {
|
||||
typeItems.put(type, new ArrayList<>(items));
|
||||
});
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
c.announce(MaplePacketCreator.getStorage(npcId, slots, items, meso));
|
||||
|
||||
List<Item> storageItems = getItems();
|
||||
for (MapleInventoryType type : MapleInventoryType.values()) {
|
||||
typeItems.put(type, new ArrayList<>(storageItems));
|
||||
}
|
||||
c.announce(MaplePacketCreator.getStorage(npcId, slots, storageItems, meso));
|
||||
}
|
||||
|
||||
public void sendStored(MapleClient c, MapleInventoryType type) {
|
||||
@@ -231,7 +270,12 @@ public class MapleStorage {
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return items.size() >= slots;
|
||||
lock.lock();
|
||||
try {
|
||||
return items.size() >= slots;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
@@ -55,100 +55,107 @@ public class MapleLifeFactory {
|
||||
}
|
||||
|
||||
public static MapleMonster getMonster(int mid) {
|
||||
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
|
||||
if (stats == null) {
|
||||
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
|
||||
if (monsterData == null) {
|
||||
return null;
|
||||
}
|
||||
MapleData monsterInfoData = monsterData.getChildByPath("info");
|
||||
stats = new MapleMonsterStats();
|
||||
stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData));
|
||||
stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1);
|
||||
stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData));
|
||||
stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData));
|
||||
stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData));
|
||||
stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData));
|
||||
stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0));
|
||||
stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0));
|
||||
stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData));
|
||||
stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0));
|
||||
stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0);
|
||||
stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0);
|
||||
stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0);
|
||||
stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0);
|
||||
stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO"));
|
||||
stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1));
|
||||
stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0));
|
||||
stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0);
|
||||
|
||||
MapleData special = monsterInfoData.getChildByPath("coolDamage");
|
||||
if (special != null) {
|
||||
int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData);
|
||||
int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0);
|
||||
stats.setCool(new Pair<>(coolDmg, coolProb));
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("loseItem");
|
||||
if (special != null) {
|
||||
for (MapleData liData : special.getChildren()) {
|
||||
stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x"))));
|
||||
try {
|
||||
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
|
||||
if (stats == null) {
|
||||
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
|
||||
if (monsterData == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("selfDestruction");
|
||||
if (special != null) {
|
||||
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
|
||||
}
|
||||
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
|
||||
int firstAttack = 0;
|
||||
if (firstAttackData != null) {
|
||||
if (firstAttackData.getType() == MapleDataType.FLOAT) {
|
||||
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
|
||||
} else {
|
||||
firstAttack = MapleDataTool.getInt(firstAttackData);
|
||||
}
|
||||
}
|
||||
stats.setFirstAttack(firstAttack > 0);
|
||||
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000);
|
||||
|
||||
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
|
||||
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
|
||||
MapleData monsterInfoData = monsterData.getChildByPath("info");
|
||||
stats = new MapleMonsterStats();
|
||||
stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData));
|
||||
stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1);
|
||||
stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData));
|
||||
stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData));
|
||||
stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData));
|
||||
stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData));
|
||||
stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0));
|
||||
stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0));
|
||||
stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData));
|
||||
stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0));
|
||||
stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0);
|
||||
stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0);
|
||||
stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0);
|
||||
stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0);
|
||||
stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO"));
|
||||
stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1));
|
||||
stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0));
|
||||
stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0);
|
||||
|
||||
for (MapleData idata : monsterData) {
|
||||
if (!idata.getName().equals("info")) {
|
||||
int delay = 0;
|
||||
for (MapleData pic : idata.getChildren()) {
|
||||
delay += MapleDataTool.getIntConvert("delay", pic, 0);
|
||||
MapleData special = monsterInfoData.getChildByPath("coolDamage");
|
||||
if (special != null) {
|
||||
int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData);
|
||||
int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0);
|
||||
stats.setCool(new Pair<>(coolDmg, coolProb));
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("loseItem");
|
||||
if (special != null) {
|
||||
for (MapleData liData : special.getChildren()) {
|
||||
stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x"))));
|
||||
}
|
||||
stats.setAnimationTime(idata.getName(), delay);
|
||||
}
|
||||
}
|
||||
MapleData reviveInfo = monsterInfoData.getChildByPath("revive");
|
||||
if (reviveInfo != null) {
|
||||
List<Integer> revives = new LinkedList<>();
|
||||
for (MapleData data_ : reviveInfo) {
|
||||
revives.add(MapleDataTool.getInt(data_));
|
||||
special = monsterInfoData.getChildByPath("selfDestruction");
|
||||
if (special != null) {
|
||||
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
|
||||
}
|
||||
stats.setRevives(revives);
|
||||
}
|
||||
decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, ""));
|
||||
MapleData monsterSkillData = monsterInfoData.getChildByPath("skill");
|
||||
if (monsterSkillData != null) {
|
||||
int i = 0;
|
||||
List<Pair<Integer, Integer>> skills = new ArrayList<>();
|
||||
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
|
||||
skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0))));
|
||||
i++;
|
||||
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
|
||||
int firstAttack = 0;
|
||||
if (firstAttackData != null) {
|
||||
if (firstAttackData.getType() == MapleDataType.FLOAT) {
|
||||
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
|
||||
} else {
|
||||
firstAttack = MapleDataTool.getInt(firstAttackData);
|
||||
}
|
||||
}
|
||||
stats.setSkills(skills);
|
||||
stats.setFirstAttack(firstAttack > 0);
|
||||
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000);
|
||||
|
||||
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
|
||||
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
|
||||
|
||||
for (MapleData idata : monsterData) {
|
||||
if (!idata.getName().equals("info")) {
|
||||
int delay = 0;
|
||||
for (MapleData pic : idata.getChildren()) {
|
||||
delay += MapleDataTool.getIntConvert("delay", pic, 0);
|
||||
}
|
||||
stats.setAnimationTime(idata.getName(), delay);
|
||||
}
|
||||
}
|
||||
MapleData reviveInfo = monsterInfoData.getChildByPath("revive");
|
||||
if (reviveInfo != null) {
|
||||
List<Integer> revives = new LinkedList<>();
|
||||
for (MapleData data_ : reviveInfo) {
|
||||
revives.add(MapleDataTool.getInt(data_));
|
||||
}
|
||||
stats.setRevives(revives);
|
||||
}
|
||||
decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, ""));
|
||||
MapleData monsterSkillData = monsterInfoData.getChildByPath("skill");
|
||||
if (monsterSkillData != null) {
|
||||
int i = 0;
|
||||
List<Pair<Integer, Integer>> skills = new ArrayList<>();
|
||||
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
|
||||
skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0))));
|
||||
i++;
|
||||
}
|
||||
stats.setSkills(skills);
|
||||
}
|
||||
MapleData banishData = monsterInfoData.getChildByPath("ban");
|
||||
if (banishData != null) {
|
||||
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp")));
|
||||
}
|
||||
monsterStats.put(Integer.valueOf(mid), stats);
|
||||
}
|
||||
MapleData banishData = monsterInfoData.getChildByPath("ban");
|
||||
if (banishData != null) {
|
||||
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp")));
|
||||
}
|
||||
monsterStats.put(Integer.valueOf(mid), stats);
|
||||
MapleMonster ret = new MapleMonster(mid, stats);
|
||||
return ret;
|
||||
} catch(NullPointerException npe) {
|
||||
System.out.println("[SEVERE] MOB " + mid + " failed to load. Issue: " + npe.getMessage() + "\n\n");
|
||||
npe.printStackTrace();
|
||||
|
||||
return null;
|
||||
}
|
||||
MapleMonster ret = new MapleMonster(mid, stats);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) {
|
||||
|
||||
@@ -2325,11 +2325,11 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void setMapPointBoundings(int px, int py, int h, int w) {
|
||||
mapArea.setBounds(px, py, w, h);
|
||||
mapArea.setBounds(px + 7, py, w - 14, h);
|
||||
}
|
||||
|
||||
public void setMapLineBoundings(int vrTop, int vrBottom, int vrLeft, int vrRight) {
|
||||
mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop);
|
||||
mapArea.setBounds(vrLeft + 7, vrTop, vrRight - vrLeft - 14, vrBottom - vrTop);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,6 +41,7 @@ public class FilePrinter {
|
||||
FREDRICK = "fredrick/",
|
||||
NPC_UNCODED = "uncodedNPCs.txt",
|
||||
QUEST_UNCODED = "uncodedQuests.txt",
|
||||
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
||||
SAVING_CHARACTER = "saveChar.txt",
|
||||
USED_COMMANDS = "usedCommands.txt";//more to come (maps)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user