diff --git a/.gitignore b/.gitignore
index c477dc6a51..232f549d1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,10 @@
/tools/MapleBossHpBarFetcher/build/
/tools/MapleBossHpBarFetcher/dist/
+/tools/MapleCashDropFetcher/nbproject/private/
+/tools/MapleCashDropFetcher/build/
+/tools/MapleCashDropFetcher/dist/
+
/tools/MapleCouponInstaller/build/
/tools/MapleCouponInstaller/dist/
/tools/MapleCouponInstaller/nbproject/private/
diff --git a/README.md b/README.md
index 2dbaad7385..7e3b4d68ad 100644
--- a/README.md
+++ b/README.md
@@ -20,9 +20,15 @@ Server files: https://github.com/ronancpl/HeavenMS
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk
-Recommended localhost: https://hostr.co/r5QDmhlxpp8M
+Recommended localhost: https://hostr.co/fuzm4X9j7TWh
-* MapleSilver's starting on window-mode, with some string fixes. This is a variation of Fraysa's https://hostr.co/gJbLZITRVHmv
+* Current revision: 'n' problem fixed and removed caps for WATK, WDEF, MDEF, ACC, AVOID.
+
+ * 'n' problem fixed https://hostr.co/r5QDmhlxpp8M
+
+ * Fraysa's https://hostr.co/gJbLZITRVHmv
+
+ * MapleSilver's starting on window-mode
---
### Support us
diff --git a/docs/feature_list.md b/docs/feature_list.md
index 749dd01f3c..39984d3ac4 100644
--- a/docs/feature_list.md
+++ b/docs/feature_list.md
@@ -118,6 +118,7 @@ External tools:
* MapleArrowFetcher - Updates min/max quantity dropped on all arrows drop data, calculations based on mob level and whether it's a boss or not.
* MapleBossHpBarFetcher - Searches the quest WZ files and reports in all relevant data regarding mobs that has a boss HP bar whilst not having a proper "boss" label.
+* MapleCashDropFetcher - Searches the DB for any CASH drop data entry and lists them on a report file.
* MapleCouponInstaller - Retrieves coupon info from the WZ and makes a SQL table with it. The server will use that table to gather info regarding rates and intervals.
* MapleIdRetriever - Two behaviors: generates a SQL table with relation (id, name) of the handbook given as input. Given a file with names, outputs a file with ids.
* MapleInvalidItemIdFetcher - Generates a file listing all inexistent itemid's currently laying on the DB.
@@ -140,4 +141,9 @@ Project:
* Heavily reviewed future task management inside the project. Way less trivial schedules are spawned now, relieving task overload on the TimerManager.
* ThreadTracker: embedded auditing tool for run-time deadlock scanning throughout the server source (relies heavily on memory usage, designed only for debugging purposes).
+Localhost:
+
+* Removed the 'n' problem within NPC dialog.
+* Removed caps for MATK, WDEF, MDEF, ACC and AVOID.
+
---------------------------
\ No newline at end of file
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 22dc2cf5fe..82be832739 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -859,4 +859,11 @@ Corrigido NPC de guild tirando mesos do jogador sem efetuar a ação alguma caso
11 - 12 Março 2018,
Localhost melhorado: retirado caps de Matk, Mdef, Wdef, Acc e Avoid.
Balanceado Ninja Ambush, agora dando uma quantidade de dano justificável.
-Implementado questline do Dyle.
\ No newline at end of file
+Implementado questline do Dyle.
+Corrigido possível exploit com sistema de quests, onde jogador podia começar e completar quaisquer quests livremente.
+Nova ferramenta: MapleCashDropFetcher. Aplicação busca por drop data de cash na DB e reporta.
+
+13 Merço 2018,
+Adicionado feature de anúncio de mudança de classe.
+Adicionado drops faltando da questline Puppeteer de Aran.
+Movimentação de GM rank para alguns comandos.
\ No newline at end of file
diff --git a/scripts/npc/PupeteerPassword.js b/scripts/npc/PupeteerPassword.js
index 78e414d5d5..462f8157fb 100644
--- a/scripts/npc/PupeteerPassword.js
+++ b/scripts/npc/PupeteerPassword.js
@@ -18,10 +18,17 @@ function action(mode, type, selection){
if(status == 0){
+ if(cm.isQuestStarted(21728)) {
+ cm.sendOk("You search for any hints of the Puppeteer, but it seems a powerful force blocks the path... Better return to #b#p1061019##k.");
+ cm.setQuestProgress(21728, 0, 1);
+ cm.dispose();
+ return;
+ }
+
cm.sendGetText("A suspicious voice pierces through the silence. #bPassword#k!");
}
else if(status == 1){
- if(cm.getText() == "Francis is a genius Puppeteer!"){
+ if(cm.getText() == "Francis is a genius Puppeteer!"){
if(cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) == 0)
cm.warp(910510001, 1);
else if(cm.isQuestStarted(21731) && cm.getQuestProgress(21731, 9300346) == 0)
diff --git a/scripts/npc/commands.js b/scripts/npc/commands.js
index 20f6e5bb40..a355847ffb 100644
--- a/scripts/npc/commands.js
+++ b/scripts/npc/commands.js
@@ -152,6 +152,7 @@ function writeSolaxiaCommandsLv2() { //JrGM
comm_cursor = comm_lv2;
desc_cursor = desc_lv2;
+ addCommand("whereami", "");
addCommand("hide", "");
addCommand("unhide", "");
addCommand("sp", "");
@@ -188,10 +189,13 @@ function writeSolaxiaCommandsLv1() { //Donator
comm_cursor = comm_lv1;
desc_cursor = desc_lv1;
+ addCommand("bosshp", "");
+ addCommand("mobhp", "");
+ addCommand("whatdropsfrom", "");
+ addCommand("whodrops", "");
addCommand("buffme", "");
addCommand("goto", "");
addCommand("recharge", "");
- addCommand("whereami", "");
}
function writeSolaxiaCommandsLv0() { //Common
@@ -204,21 +208,21 @@ function writeSolaxiaCommandsLv0() { //Common
addCommand("credits", "");
addCommand("uptime", "");
addCommand("gacha", "");
- addCommand("whatdropsfrom", "");
- addCommand("whodrops", "");
addCommand("dispose", "");
addCommand("equiplv", "");
addCommand("showrates", "");
addCommand("rates", "");
addCommand("online", "");
addCommand("gm", "");
- addCommand("bug", "");
+ addCommand("reportbug", "");
//addCommand("points", "");
addCommand("joinevent", "");
addCommand("leaveevent", "");
- addCommand("bosshp", "");
- addCommand("mobhp", "");
addCommand("ranks", "");
+ addCommand("str", "");
+ addCommand("int", "");
+ addCommand("luk", "");
+ addCommand("dex", "");
}
function writeSolaxiaCommands() {
diff --git a/scripts/quest/21728.js b/scripts/quest/21728.js
new file mode 100644
index 0000000000..88bb7ba1fe
--- /dev/null
+++ b/scripts/quest/21728.js
@@ -0,0 +1,49 @@
+/*
+ This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
+ Copyleft (L) 2017 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 .
+*/
+
+var status = -1;
+
+function end(mode, type, selection) {
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ if(qm.getQuestProgress(21728, 0) == 0) {
+ qm.sendNext("You haven't found the #rPuppeteer's cave#k yet, did you?");
+ } else {
+ qm.sendNext("Hm, so the entrance is blocked by a powerful force? I see, gimme a time to think now...");
+ qm.gainExp(200 * qm.getPlayer().getExpRate());
+ qm.forceCompleteQuest();
+ }
+
+ qm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/quest/21729.js b/scripts/quest/21729.js
new file mode 100644
index 0000000000..f56e2b7172
--- /dev/null
+++ b/scripts/quest/21729.js
@@ -0,0 +1,44 @@
+/*
+ This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
+ Copyleft (L) 2017 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 .
+*/
+
+var status = -1;
+
+function start(mode, type, selection) {
+ if (mode == -1) {
+ qm.dispose();
+ } else {
+ if(mode == 0 && type > 0) {
+ qm.dispose();
+ return;
+ }
+
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if (status == 0) {
+ qm.sendNext("Okay, you should not return to #bTru#k for further details on your next steps. ... Oh wait!! I remembered something. See the #rMysterious Statue#k over there? That statue has it's origins unknwown, and there's something scribbled onto it that resembles something big, it probably is the password for the cave? #rGet the password there#k, it may help you on your journey.");
+ qm.forceStartQuest();
+
+ qm.dispose();
+ }
+ }
+}
diff --git a/scripts/quest/2214.js b/scripts/quest/2214.js
index b1f2f33075..10ade811f9 100644
--- a/scripts/quest/2214.js
+++ b/scripts/quest/2214.js
@@ -25,6 +25,8 @@
Quest ID: 2214
*/
+importPackage(java.util);
+
var status = -1;
function end(mode, type, selection) {
@@ -42,6 +44,13 @@ function end(mode, type, selection) {
status--;
if (status == 0) {
+ var hourDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
+ if(!(hourDay >= 17 && hourDay < 20)) {
+ qm.sendNext("(Hmm, I'm searching the trash can but can't find the #t4031894# JM was talking about, maybe it's not time yet...)");
+ qm.dispose();
+ return;
+ }
+
if(!qm.canHold(4031894, 1)) {
qm.sendNext("(Eh, I can't hold the #t4031894# right now, I need an ETC slot available.)");
qm.dispose();
diff --git a/scripts/quest/2215.js b/scripts/quest/2215.js
index edb50c6a13..bea586d10e 100644
--- a/scripts/quest/2215.js
+++ b/scripts/quest/2215.js
@@ -25,6 +25,8 @@
Quest ID: 2215
*/
+importPackage(java.util);
+
var status = -1;
function end(mode, type, selection) {
@@ -42,6 +44,13 @@ function end(mode, type, selection) {
status--;
if (status == 0) {
+ var hourDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
+ if(!(hourDay >= 17 && hourDay < 20)) {
+ qm.sendNext("(Hmm, I'm searching the trash can but can't find the #t4031894# JM was talking about, maybe it's not time yet...)");
+ qm.dispose();
+ return;
+ }
+
if(qm.getMeso() < 2000) {
qm.sendNext("(Oh, I don't have the combined fee amount yet.)");
qm.dispose();
diff --git a/sql/db_database.sql b/sql/db_database.sql
index ddfc68660b..b4775a491b 100644
--- a/sql/db_database.sql
+++ b/sql/db_database.sql
@@ -10830,9 +10830,6 @@ INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`,
(10608, 9302010, 2022524, 1, 1, 0, 100000),
(10609, 9400256, 4032192, 1, 1, 0, 50000),
(10610, 9400257, 4032192, 1, 1, 0, 50000),
-(10611, 9410066, 5490001, 1, 1, 0, 700000),
-(10612, 9410066, 5490001, 1, 1, 0, 700000),
-(10613, 9410066, 5490000, 1, 1, 0, 300000),
(10614, 9410066, 4000306, 1, 1, 0, 700000),
(10615, 9410066, 4000306, 1, 1, 0, 700000),
(10616, 9410066, 4000306, 1, 1, 0, 700000),
diff --git a/sql/db_drops.sql b/sql/db_drops.sql
index 27e0fadcca..2a83061591 100644
--- a/sql/db_drops.sql
+++ b/sql/db_drops.sql
@@ -1107,7 +1107,6 @@ USE `heavenms`;
(9300063, 1052101, 1, 1, 0, 700),
(9300082, 1052101, 1, 1, 0, 700),
(9400503, 1052101, 1, 1, 0, 40000),
-(2100100, 5240005, 1, 1, 0, 7000),
(2100100, 4003004, 1, 1, 0, 7000),
(2100100, 2000001, 1, 1, 0, 40000),
(2100100, 2000003, 1, 1, 0, 40000),
@@ -10022,7 +10021,6 @@ USE `heavenms`;
(9500326, 1372000, 1, 1, 0, 40000),
(9500345, 1372000, 1, 1, 0, 40000),
(9303004, 1372000, 1, 1, 0, 700),
-(6130103, 1702131, 1, 1, 0, 700),
(6130103, 2000006, 1, 1, 0, 40000),
(6130103, 2000004, 1, 1, 0, 40000),
(6130103, 2040401, 1, 1, 0, 750),
@@ -20183,7 +20181,11 @@ USE `heavenms`;
(9400114, 2022063, 10, 30, 0, 200000),
(9400114, 2022064, 10, 30, 0, 200000),
(9400120, 4000094, 1, 1, 0, 400000),
-(9400122, 4000094, 1, 1, 0, 400000);
+(9400122, 4000094, 1, 1, 0, 400000),
+(1110130, 4032317, 1, 1, 21717, 40000),
+(1110130, 4032318, 1, 1, 21718, 40000),
+(1140130, 4032319, 1, 1, 21723, 100000),
+(2230131, 4032321, 1, 1, 21727, 20000);
# (dropperid, itemid, minqty, maxqty, questid, chance)
diff --git a/src/client/BuddyList.java b/src/client/BuddyList.java
index c2e3dc0a11..1a5d77b626 100644
--- a/src/client/BuddyList.java
+++ b/src/client/BuddyList.java
@@ -26,10 +26,12 @@ import java.sql.ResultSet;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
+import java.util.Collections;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
+import net.server.PlayerStorage;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
@@ -50,15 +52,22 @@ public class BuddyList {
}
public boolean contains(int characterId) {
- return buddies.containsKey(Integer.valueOf(characterId));
+ synchronized(buddies) {
+ return buddies.containsKey(Integer.valueOf(characterId));
+ }
}
public boolean containsVisible(int characterId) {
- BuddylistEntry ble = buddies.get(characterId);
+ BuddylistEntry ble;
+ synchronized(buddies) {
+ ble = buddies.get(characterId);
+ }
+
if (ble == null) {
return false;
}
return ble.isVisible();
+
}
public int getCapacity() {
@@ -70,42 +79,65 @@ public class BuddyList {
}
public BuddylistEntry get(int characterId) {
- return buddies.get(Integer.valueOf(characterId));
+ synchronized(buddies) {
+ return buddies.get(Integer.valueOf(characterId));
+ }
}
public BuddylistEntry get(String characterName) {
String lowerCaseName = characterName.toLowerCase();
- for (BuddylistEntry ble : buddies.values()) {
+ for (BuddylistEntry ble : getBuddies()) {
if (ble.getName().toLowerCase().equals(lowerCaseName)) {
return ble;
}
}
+
return null;
}
public void put(BuddylistEntry entry) {
- buddies.put(Integer.valueOf(entry.getCharacterId()), entry);
+ synchronized(buddies) {
+ buddies.put(Integer.valueOf(entry.getCharacterId()), entry);
+ }
}
public void remove(int characterId) {
- buddies.remove(Integer.valueOf(characterId));
+ synchronized(buddies) {
+ buddies.remove(Integer.valueOf(characterId));
+ }
}
public Collection getBuddies() {
- return buddies.values();
+ synchronized(buddies) {
+ return Collections.unmodifiableCollection(buddies.values());
+ }
}
public boolean isFull() {
- return buddies.size() >= capacity;
+ synchronized(buddies) {
+ return buddies.size() >= capacity;
+ }
}
public int[] getBuddyIds() {
- int buddyIds[] = new int[buddies.size()];
- int i = 0;
- for (BuddylistEntry ble : buddies.values()) {
- buddyIds[i++] = ble.getCharacterId();
+ synchronized(buddies) {
+ int buddyIds[] = new int[buddies.size()];
+ int i = 0;
+ for (BuddylistEntry ble : buddies.values()) {
+ buddyIds[i++] = ble.getCharacterId();
+ }
+ return buddyIds;
+ }
+ }
+
+ public void broadcast(byte[] packet, PlayerStorage pstorage) {
+ for(int bid : getBuddyIds()) {
+ MapleCharacter chr = pstorage.getCharacterById(bid);
+
+ if(chr != null && chr.isLoggedin() && !chr.isAwayFromWorld()) {
+ chr.announce(packet);
+ }
}
- return buddyIds;
}
public void loadFromDb(int characterId) {
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index 25f7109243..1904fc7e83 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -199,7 +199,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private int expRate = 1, mesoRate = 1, dropRate = 1, expCoupon = 1, mesoCoupon = 1, dropCoupon = 1;
private int omokwins, omokties, omoklosses, matchcardwins, matchcardties, matchcardlosses;
private int owlSearch;
- private int married;
private long lastfametime, lastUsedCashItem, lastHealed, lastMesoDrop = -1, jailExpiration = -1;
private transient int localmaxhp, localmaxmp, localstr, localdex, localluk, localint_, magic, watk;
private boolean hidden, canDoor = true, berserk, hasMerchant, whiteChat = false;
@@ -1093,6 +1092,36 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
createDragon();
}
+
+ if(ServerConstants.USE_ANNOUNCE_CHANGEJOB) {
+ if(gmLevel > 1) {
+ broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + newJob.name() + ".");
+ }
+ }
+ }
+
+ public void broadcastAcquaintances(int type, String message) {
+ broadcastAcquaintances(MaplePacketCreator.serverNotice(type, message));
+ }
+
+ public void broadcastAcquaintances(byte[] packet) {
+ buddylist.broadcast(packet, client.getWorldServer().getPlayerStorage());
+
+ if(family != null) {
+ //family.broadcast(packet, id); not yet implemented
+ }
+
+ MapleGuild guild = getGuild();
+ if(guild != null) {
+ guild.broadcast(packet, id);
+ }
+
+ /*
+ if(partnerid > 0) {
+ partner.announce(packet); not yet implemented
+ }
+ */
+ announce(packet);
}
public void changeKeybinding(int key, MapleKeyBinding keybinding) {
@@ -3955,10 +3984,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return marriageRing;
}
- public int getMarried() {
- return married;
- }
-
public int getMasterLevel(Skill skill) {
if (skills.get(skill) == null) {
return 0;
diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java
index b3fcea7ad7..ed77335191 100644
--- a/src/client/command/Commands.java
+++ b/src/client/command/Commands.java
@@ -351,7 +351,7 @@ public class Commands {
case "playercommands":
c.getAbstractPlayerInteraction().openNpc(9201143, "commands");
break;
-
+
case "droplimit":
int dropCount = c.getPlayer().getMap().getDroppedItemCount();
if(((float) dropCount) / ServerConstants.ITEM_LIMIT_ON_MAP < 0.75f) {
@@ -402,90 +402,14 @@ public class Commands {
}
break;
}
- String output = "The #b" + gachaName + "#k Gachapon contains the following items.\r\n\r\n";
+ String talkStr = "The #b" + gachaName + "#k Gachapon contains the following items.\r\n\r\n";
for (int i = 0; i < 2; i++){
for (int id : gacha.getItems(i)){
- output += "-" + MapleItemInformationProvider.getInstance().getName(id) + "\r\n";
+ talkStr += "-" + MapleItemInformationProvider.getInstance().getName(id) + "\r\n";
}
}
- output += "\r\nPlease keep in mind that there are items that are in all gachapons and are not listed here.";
- c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
- break;
-
- case "whatdropsfrom":
- if (sub.length < 2) {
- player.dropMessage(5, "Please do @whatdropsfrom ");
- break;
- }
- String monsterName = joinStringFrom(sub, 1);
- output = "";
- int limit = 3;
- Iterator> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
- for (int i = 0; i < limit; i++) {
- if(listIterator.hasNext()) {
- Pair data = listIterator.next();
- int mobId = data.getLeft();
- String mobName = data.getRight();
- output += mobName + " drops the following items:\r\n\r\n";
- for (MonsterDropEntry drop : MapleMonsterInformationProvider.getInstance().retrieveDrop(mobId)){
- try {
- String name = MapleItemInformationProvider.getInstance().getName(drop.itemId);
- if (name.equals("null") || drop.chance == 0){
- continue;
- }
- float chance = 1000000 / drop.chance / player.getDropRate();
- output += "- " + name + " (1/" + (int) chance + ")\r\n";
- } catch (Exception ex){
- ex.printStackTrace();
- continue;
- }
- }
- output += "\r\n";
- }
- }
- c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
- break;
-
- case "whodrops":
- if (sub.length < 2) {
- player.dropMessage(5, "Please do @whodrops - ");
- break;
- }
- String searchString = joinStringFrom(sub, 1);
- output = "";
- listIterator = MapleItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
- if(listIterator.hasNext()) {
- int count = 1;
- while(listIterator.hasNext() && count <= 3) {
- Pair data = listIterator.next();
- output += "#b" + data.getRight() + "#k is dropped by:\r\n";
- try {
- Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
- ps.setInt(1, data.getLeft());
- ResultSet rs = ps.executeQuery();
- while(rs.next()) {
- String resultName = MapleMonsterInformationProvider.getMobNameFromID(rs.getInt("dropperid"));
- if (resultName != null) {
- output += resultName + ", ";
- }
- }
- rs.close();
- ps.close();
- con.close();
- } catch (Exception e) {
- player.dropMessage(6, "There was a problem retrieving the required data. Please try again.");
- e.printStackTrace();
- break;
- }
- output += "\r\n\r\n";
- count++;
- }
- } else {
- player.dropMessage(5, "The item you searched for doesn't exist.");
- break;
- }
- c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
+ talkStr += "\r\nPlease keep in mind that there are items that are in all gachapons and are not listed here.";
+ c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, talkStr, "00 00", (byte) 0));
break;
case "dispose":
@@ -560,7 +484,7 @@ public class Commands {
player.dropMessage(5, tips[Randomizer.nextInt(tips.length)]);
break;
- case "bug":
+ case "reportbug":
if (sub.length < 2) {
player.dropMessage(5, "Message too short and not sent. Please do @bug ");
@@ -636,30 +560,6 @@ public class Commands {
}
break;
- case "bosshp":
- for(MapleMonster monster : player.getMap().getMonsters()) {
- if(monster != null && monster.isBoss() && monster.getHp() > 0) {
- long percent = monster.getHp() * 100L / monster.getMaxHp();
- String bar = "[";
- for (int i = 0; i < 100; i++){
- bar += i < percent ? "|" : ".";
- }
- bar += "]";
- player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
- player.yellowMessage("HP: " + bar);
- }
- }
- break;
-
- case "mobhp":
- for(MapleMonster monster : player.getMap().getMonsters()) {
- if(monster != null && monster.getHp() > 0) {
- player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + monster.getHp() + " / " + monster.getMaxHp() + " HP.");
-
- }
- }
- break;
-
case "ranks":
PreparedStatement ps = null;
ResultSet rs = null;
@@ -691,6 +591,47 @@ public class Commands {
}
}
break;
+
+ // stat autoassigning command credited to HeliosMS dev team
+ case "str":
+ case "int":
+ case "luk":
+ case "dex":
+ int amount = (sub.length > 1) ? Integer.parseInt(sub[1]) : player.getRemainingAp();
+ boolean str = sub[0].equalsIgnoreCase("str");
+ boolean Int = sub[0].equalsIgnoreCase("int");
+ boolean luk = sub[0].equalsIgnoreCase("luk");
+ boolean dex = sub[0].equalsIgnoreCase("dex");
+
+ if (amount > 0 && amount <= player.getRemainingAp() && amount <= 32763 || amount < 0 && amount >= -32763 && Math.abs(amount) + player.getRemainingAp() <= 32767) {
+ if (str && amount + player.getStr() <= 32767 && amount + player.getStr() >= 4) {
+ player.setStr(player.getStr() + amount);
+ player.updateSingleStat(MapleStat.STR, player.getStr());
+ player.setRemainingAp(player.getRemainingAp() - amount);
+ player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
+ } else if (Int && amount + player.getInt() <= 32767 && amount + player.getInt() >= 4) {
+ player.setInt(player.getInt() + amount);
+ player.updateSingleStat(MapleStat.INT, player.getInt());
+ player.setRemainingAp(player.getRemainingAp() - amount);
+ player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
+ } else if (luk && amount + player.getLuk() <= 32767 && amount + player.getLuk() >= 4) {
+ player.setLuk(player.getLuk() + amount);
+ player.updateSingleStat(MapleStat.LUK, player.getLuk());
+ player.setRemainingAp(player.getRemainingAp() - amount);
+ player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
+ } else if (dex && amount + player.getDex() <= 32767 && amount + player.getDex() >= 4) {
+ player.setDex(player.getDex() + amount);
+ player.updateSingleStat(MapleStat.DEX, player.getDex());
+ player.setRemainingAp(player.getRemainingAp() - amount);
+ player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
+ } else {
+ player.dropMessage("Please make sure the stat you are trying to raise is not over 32,767 or under 4.");
+ }
+ } else {
+ player.dropMessage("Please make sure your AP is not over 32,767 and you have enough to distribute.");
+ }
+
+ break;
default:
return false;
@@ -702,8 +643,113 @@ public class Commands {
public static boolean executeHeavenMsCommandLv1(Channel cserv, Server srv, MapleClient c, String[] sub) { //Donator
MapleCharacter player = c.getPlayer();
- switch(sub[0]) {
+ switch(sub[0]) {
+ case "bosshp":
+ for(MapleMonster monster : player.getMap().getMonsters()) {
+ if(monster != null && monster.isBoss() && monster.getHp() > 0) {
+ long percent = monster.getHp() * 100L / monster.getMaxHp();
+ String bar = "[";
+ for (int i = 0; i < 100; i++){
+ bar += i < percent ? "|" : ".";
+ }
+ bar += "]";
+ player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
+ player.yellowMessage("HP: " + bar);
+ }
+ }
+ break;
+
+ case "mobhp":
+ for(MapleMonster monster : player.getMap().getMonsters()) {
+ if(monster != null && monster.getHp() > 0) {
+ player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + monster.getHp() + " / " + monster.getMaxHp() + " HP.");
+
+ }
+ }
+ break;
+
+ case "whatdropsfrom":
+ if (sub.length < 2) {
+ player.dropMessage(5, "Please do @whatdropsfrom ");
+ break;
+ }
+ String monsterName = joinStringFrom(sub, 1);
+ String output = "";
+ int limit = 3;
+ Iterator> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
+ for (int i = 0; i < limit; i++) {
+ if(listIterator.hasNext()) {
+ Pair data = listIterator.next();
+ int mobId = data.getLeft();
+ String mobName = data.getRight();
+ output += mobName + " drops the following items:\r\n\r\n";
+ for (MonsterDropEntry drop : MapleMonsterInformationProvider.getInstance().retrieveDrop(mobId)){
+ try {
+ String name = MapleItemInformationProvider.getInstance().getName(drop.itemId);
+ if (name.equals("null") || drop.chance == 0){
+ continue;
+ }
+ float chance = 1000000 / drop.chance / player.getDropRate();
+ output += "- " + name + " (1/" + (int) chance + ")\r\n";
+ } catch (Exception ex){
+ ex.printStackTrace();
+ continue;
+ }
+ }
+ output += "\r\n";
+ }
+ }
+ c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
+ break;
+
+ case "whodrops":
+ if (sub.length < 2) {
+ player.dropMessage(5, "Please do @whodrops
- ");
+ break;
+ }
+ String searchString = joinStringFrom(sub, 1);
+ output = "";
+ listIterator = MapleItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
+ if(listIterator.hasNext()) {
+ int count = 1;
+ while(listIterator.hasNext() && count <= 3) {
+ Pair data = listIterator.next();
+ output += "#b" + data.getRight() + "#k is dropped by:\r\n";
+ try {
+ Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
+ ps.setInt(1, data.getLeft());
+ ResultSet rs = ps.executeQuery();
+ while(rs.next()) {
+ String resultName = MapleMonsterInformationProvider.getMobNameFromID(rs.getInt("dropperid"));
+ if (resultName != null) {
+ output += resultName + ", ";
+ }
+ }
+ rs.close();
+ ps.close();
+ con.close();
+ } catch (Exception e) {
+ player.dropMessage(6, "There was a problem retrieving the required data. Please try again.");
+ e.printStackTrace();
+ break;
+ }
+ output += "\r\n\r\n";
+ count++;
+ }
+ } else {
+ player.dropMessage(5, "The item you searched for doesn't exist.");
+ break;
+ }
+ c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
+ break;
+
case "buffme":
+ if(!player.isGM()) {
+ player.dropMessage(5, "You are already dead.");
+ break;
+ }
+
//GM Skills : Haste(Super) - Holy Symbol - Bless - Hyper Body - Echo of Hero
SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player);
@@ -753,7 +799,20 @@ public class Commands {
}
player.dropMessage(5, "USE Recharged.");
break;
-
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean executeHeavenMsCommandLv2(Channel cserv, Server srv, MapleClient c, String[] sub) { //JrGM
+ MapleCharacter player = c.getPlayer();
+ MapleCharacter victim;
+ Skill skill;
+
+ switch(sub[0]) {
case "whereami":
player.yellowMessage("Map ID: " + player.getMap().getId());
player.yellowMessage("Players on this map:");
@@ -777,21 +836,8 @@ public class Commands {
}
}
}
- break;
-
- default:
- return false;
- }
-
- return true;
- }
-
- public static boolean executeHeavenMsCommandLv2(Channel cserv, Server srv, MapleClient c, String[] sub) { //JrGM
- MapleCharacter player = c.getPlayer();
- MapleCharacter victim;
- Skill skill;
-
- switch(sub[0]) {
+ break;
+
case "hide":
SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player);
break;
diff --git a/src/constants/GameConstants.java b/src/constants/GameConstants.java
index 2f4269c4c7..5899106a36 100644
--- a/src/constants/GameConstants.java
+++ b/src/constants/GameConstants.java
@@ -62,26 +62,36 @@ public class GameConstants {
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000,
530000, 550000, 570000, 590000, 610000, 630000, 650000, 670000, 690000, 710000, 730000, 750000, 770000, 790000, 810000, 830000, 850000, 870000, 890000, 910000};
- public static int getJobMaxLevel(MapleJob job) {
- if(job.getId() % 1000 == 0) { // beginner
- return 10;
-
- } else if(job.getId() % 100 == 0) { // 1st job
- return 30;
-
+ public static int getJobBranch(MapleJob job) {
+ int jobid = job.getId();
+
+ if(jobid % 1000 == 0) {
+ return 0;
+ } else if(jobid % 100 == 0) {
+ return 1;
} else {
- int jobBranch = job.getId() % 10;
-
- switch(jobBranch) {
- case 0:
- return 70; // 2nd job
-
- case 1:
- return 120; // 3rd job
-
- default:
- return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
- }
+ return 2 + (jobid % 10);
+ }
+ }
+
+ public static int getJobMaxLevel(MapleJob job) {
+ int jobBranch = getJobBranch(job);
+
+ switch(jobBranch) {
+ case 0:
+ return 10; // beginner
+
+ case 1:
+ return 30; // 1st job
+
+ case 2:
+ return 70; // 2nd job
+
+ case 3:
+ return 120; // 3rd job
+
+ default:
+ return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
}
}
@@ -225,4 +235,17 @@ public class GameConstants {
}
return mobHpVal[level];
}
+
+ public static String ordinal(int i) {
+ String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
+ switch (i % 100) {
+ case 11:
+ case 12:
+ case 13:
+ return i + "th";
+
+ default:
+ return i + sufixes[i % 10];
+ }
+ }
}
diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java
index d0efb470a5..8e466a79c5 100644
--- a/src/constants/ServerConstants.java
+++ b/src/constants/ServerConstants.java
@@ -73,6 +73,10 @@ public class ServerConstants {
public static final boolean USE_QUEST_RATE = false; //Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
+
+ //Announcement Configuration
+ public static final boolean USE_ANNOUNCE_CHANGEJOB = true; //Automatic message sent to acquantainces when changing jobs.
+
//Server Rates And Experience
public static final int EXP_RATE = 10;
public static final int MESO_RATE = 10;
@@ -158,7 +162,7 @@ public class ServerConstants {
public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
-
+
//Event End Timestamp
public static final long EVENT_END_TIMESTAMP = 1428897600000L;
diff --git a/src/net/server/channel/handlers/GeneralChatHandler.java b/src/net/server/channel/handlers/GeneralChatHandler.java
index e304e2dae4..8583404248 100644
--- a/src/net/server/channel/handlers/GeneralChatHandler.java
+++ b/src/net/server/channel/handlers/GeneralChatHandler.java
@@ -32,6 +32,14 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
+ private static boolean isCommandIssue(char heading, MapleCharacter chr) {
+ if(chr.gmLevel() > 1 && heading == '!') {
+ return true;
+ } else {
+ return heading == '@';
+ }
+ }
+
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
String s = slea.readMapleAsciiString();
@@ -47,7 +55,7 @@ public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
return;
}
char heading = s.charAt(0);
- if (heading == '!' || heading == '@') {
+ if (isCommandIssue(heading, chr)) {
String[] sp = s.split(" ");
sp[0] = sp[0].toLowerCase().substring(1);
diff --git a/src/net/server/channel/handlers/QuestActionHandler.java b/src/net/server/channel/handlers/QuestActionHandler.java
index 69eb70f4d0..f57490edba 100644
--- a/src/net/server/channel/handlers/QuestActionHandler.java
+++ b/src/net/server/channel/handlers/QuestActionHandler.java
@@ -44,15 +44,21 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
if (slea.available() >= 4) {
slea.readInt();
}
- quest.start(player, npc);
+
+ if(quest.canStart(player, npc)) {
+ quest.start(player, npc);
+ }
} else if (action == 2) { // Complete Quest
int npc = slea.readInt();
slea.readInt();
- if (slea.available() >= 2) {
- int selection = slea.readShort();
- quest.complete(player, npc, selection);
- } else {
- quest.complete(player, npc);
+
+ if(quest.canComplete(player, npc)) {
+ if (slea.available() >= 2) {
+ int selection = slea.readShort();
+ quest.complete(player, npc, selection);
+ } else {
+ quest.complete(player, npc);
+ }
}
} else if (action == 3) {// forfeit quest
quest.forfeit(player);
diff --git a/src/scripting/event/EventManager.java b/src/scripting/event/EventManager.java
index cd7a4be21d..def406db73 100644
--- a/src/scripting/event/EventManager.java
+++ b/src/scripting/event/EventManager.java
@@ -34,6 +34,7 @@ import javax.script.Invocable;
import javax.script.ScriptException;
import constants.ServerConstants;
+import constants.GameConstants;
import client.MapleCharacter;
import net.server.Server;
import net.server.world.World;
@@ -499,19 +500,6 @@ public class EventManager {
return(MapleLifeFactory.getMonster(mid));
}
- private static String ordinal(int i) {
- String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
- switch (i % 100) {
- case 11:
- case 12:
- case 13:
- return i + "th";
-
- default:
- return i + sufixes[i % 10];
- }
- }
-
private void exportReadyGuild(Integer guildId) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
@@ -524,7 +512,7 @@ public class EventManager {
private void exportMovedQueueToGuild(Integer guildId, int place) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
- + " and is currently on the " + ordinal(place) + " place on the waiting queue.";
+ + " and is currently on the " + GameConstants.ordinal(place) + " place on the waiting queue.";
mg.dropMessage(6, callout);
}
diff --git a/src/scripting/quest/QuestScriptManager.java b/src/scripting/quest/QuestScriptManager.java
index 22782c71d0..5f647213c5 100644
--- a/src/scripting/quest/QuestScriptManager.java
+++ b/src/scripting/quest/QuestScriptManager.java
@@ -61,7 +61,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
- FilePrinter.printError(FilePrinter.QUEST_UNCODED, "Quest " + questid + " is uncoded.\r\n");
+ FilePrinter.printError(FilePrinter.QUEST_UNCODED, "START Quest " + questid + " is uncoded.\r\n");
}
if (iv == null || QuestScriptManager.getInstance() == null) {
qm.dispose();
@@ -112,6 +112,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
+ FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.\r\n");
qm.dispose();
return;
}
diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java
index d07e56e318..15d67082eb 100644
--- a/src/server/life/MapleMonster.java
+++ b/src/server/life/MapleMonster.java
@@ -535,8 +535,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}, getAnimationTime("die1"));
}
- }
- else { // is this even necessary?
+ } else { // is this even necessary?
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
}
diff --git a/tools/MapleCashDropFetcher/build.xml b/tools/MapleCashDropFetcher/build.xml
new file mode 100644
index 0000000000..a34b8b10a7
--- /dev/null
+++ b/tools/MapleCashDropFetcher/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project MapleCashDropFetcher.
+
+
+
diff --git a/tools/MapleCashDropFetcher/lib/CashDropReport.txt b/tools/MapleCashDropFetcher/lib/CashDropReport.txt
new file mode 100644
index 0000000000..b60c817722
--- /dev/null
+++ b/tools/MapleCashDropFetcher/lib/CashDropReport.txt
@@ -0,0 +1,11 @@
+ # Report File autogenerated from the MapleCashDropFetcher feature by Ronan Lana.
+ # Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls.
+
+NX DROPS ON drop_data
+5240005 : 2100100
+5490000 : 9410066
+5490001 : 9410066
+
+
+
+
diff --git a/tools/MapleCashDropFetcher/manifest.mf b/tools/MapleCashDropFetcher/manifest.mf
new file mode 100644
index 0000000000..328e8e5bc3
--- /dev/null
+++ b/tools/MapleCashDropFetcher/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/tools/MapleCashDropFetcher/nbproject/build-impl.xml b/tools/MapleCashDropFetcher/nbproject/build-impl.xml
new file mode 100644
index 0000000000..a6ae1f8964
--- /dev/null
+++ b/tools/MapleCashDropFetcher/nbproject/build-impl.xml
@@ -0,0 +1,1448 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set platform.home
+ Must set platform.bootcp
+ Must set platform.java
+ Must set platform.javac
+
+ The J2SE Platform is not correctly set up.
+ Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files.
+ Either open the project in the IDE and setup the Platform with the same name or add it manually.
+ For example like this:
+ ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file)
+ or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ ${platform.java} -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/MapleCashDropFetcher/nbproject/genfiles.properties b/tools/MapleCashDropFetcher/nbproject/genfiles.properties
new file mode 100644
index 0000000000..f63836edd2
--- /dev/null
+++ b/tools/MapleCashDropFetcher/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=928d5bb0
+build.xml.script.CRC32=27a7b03c
+build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=928d5bb0
+nbproject/build-impl.xml.script.CRC32=34e6e8ba
+nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
diff --git a/tools/MapleCashDropFetcher/nbproject/project.properties b/tools/MapleCashDropFetcher/nbproject/project.properties
new file mode 100644
index 0000000000..a6bd84f5da
--- /dev/null
+++ b/tools/MapleCashDropFetcher/nbproject/project.properties
@@ -0,0 +1,77 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=MapleCashDropFetcher
+application.vendor=USER
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Os arquivos em build.classes.dir que devem ser exclu\u00eddos do jar de distribui\u00e7\u00e3o
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/MapleCashDropFetcher.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.mysql-connector-java-bin.jar=../../cores/mysql-connector-java-bin.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+ ${file.reference.mysql-connector-java-bin.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=maplecashdropfetcher.MapleCashDropFetcher
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=JDK_1.7
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/tools/MapleCashDropFetcher/nbproject/project.xml b/tools/MapleCashDropFetcher/nbproject/project.xml
new file mode 100644
index 0000000000..ea33fc5939
--- /dev/null
+++ b/tools/MapleCashDropFetcher/nbproject/project.xml
@@ -0,0 +1,16 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ MapleCashDropFetcher
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/MapleCashDropFetcher/src/maplecashdropfetcher/MapleCashDropFetcher.java b/tools/MapleCashDropFetcher/src/maplecashdropfetcher/MapleCashDropFetcher.java
new file mode 100644
index 0000000000..3c9509f89d
--- /dev/null
+++ b/tools/MapleCashDropFetcher/src/maplecashdropfetcher/MapleCashDropFetcher.java
@@ -0,0 +1,406 @@
+/*
+ This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
+ Copyleft (L) 2017 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 .
+*/
+package maplecashdropfetcher;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+
+import java.io.File;
+
+import tools.Pair;
+
+/**
+ *
+ * @author RonanLana
+
+ This application gets info from the WZ.XML files regarding cash itemids then searches the drop data on the DB
+ after any NX (cash item) drops and reports them.
+
+ Estimated parse time: 2 minutes
+ */
+public class MapleCashDropFetcher {
+ static String host = "jdbc:mysql://localhost:3306/heavenms";
+ static String driver = "com.mysql.jdbc.Driver";
+ static String username = "root";
+ static String password = "";
+
+ static String wzPath = "../../wz";
+
+ static String directoryName = "../..";
+ static String newFile = "lib/CashDropReport.txt";
+
+ static Connection con = null;
+ static PrintWriter printWriter = null;
+ static InputStreamReader fileReader = null;
+ static BufferedReader bufferedReader = null;
+
+ static int initialLength = 200;
+ static int initialStringLength = 50;
+ static int itemFileNameSize = 13;
+
+ static Set nxItems = new HashSet<>();
+ static Set nxDrops = new HashSet<>();
+
+ static byte status = 0;
+ static int currentItemid = 0;
+
+ private static String getName(String token) {
+ int i, j;
+ char[] dest;
+ String d;
+
+ i = token.lastIndexOf("name");
+ i = token.indexOf("\"", i) + 1; //lower bound of the string
+ j = token.indexOf("\"", i); //upper bound
+
+ if(j < i) return "0"; //node value containing 'name' in it's scope, cheap fix since we don't deal with strings anyway
+
+ dest = new char[initialStringLength];
+ token.getChars(i, j, dest, 0);
+
+ d = new String(dest);
+ return(d.trim());
+ }
+
+ private static String getValue(String token) {
+ int i, j;
+ char[] dest;
+ String d;
+
+ i = token.lastIndexOf("value");
+ i = token.indexOf("\"", i) + 1; //lower bound of the string
+ j = token.indexOf("\"", i); //upper bound
+
+ dest = new char[initialStringLength];
+ token.getChars(i, j, dest, 0);
+
+ d = new String(dest);
+ return(d.trim());
+ }
+
+ private static void forwardCursor(int st) {
+ String line = null;
+
+ try {
+ while(status >= st && (line = bufferedReader.readLine()) != null) {
+ simpleToken(line);
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void simpleToken(String token) {
+ if(token.contains("/imgdir")) {
+ status -= 1;
+ }
+ else if(token.contains("imgdir")) {
+ status += 1;
+ }
+ }
+
+
+ private static void inspectEquipWzEntry() {
+ String line = null;
+
+ try {
+ while((line = bufferedReader.readLine()) != null) {
+ translateEquipToken(line);
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void translateEquipToken(String token) {
+ if(token.contains("/imgdir")) {
+ status -= 1;
+ }
+ else if(token.contains("imgdir")) {
+ if(status == 1) {
+ if(!getName(token).equals("info")) {
+ forwardCursor(status);
+ }
+ }
+
+ status += 1;
+ }
+ else {
+ if(status == 2) {
+ String d = getName(token);
+
+ if(d.equals("cash")) {
+ if(!getValue(token).equals("0")) {
+ nxItems.add(currentItemid);
+ }
+
+ forwardCursor(status);
+ }
+ }
+ }
+ }
+
+ private static void inspectItemWzEntry() {
+ String line = null;
+
+ try {
+ while((line = bufferedReader.readLine()) != null) {
+ translateItemToken(line);
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void translateItemToken(String token) {
+ if(token.contains("/imgdir")) {
+ status -= 1;
+ }
+ else if(token.contains("imgdir")) {
+ if(status == 1) {
+ currentItemid = Integer.valueOf(getName(token));
+ }
+ else if(status == 2) {
+ if(!getName(token).equals("info")) {
+ forwardCursor(status);
+ }
+ }
+
+ status += 1;
+ }
+ else {
+ if(status == 3) {
+ String d = getName(token);
+
+ if(d.equals("cash")) {
+ if(!getValue(token).equals("0")) {
+ nxItems.add(currentItemid);
+ }
+
+ forwardCursor(status);
+ }
+ }
+ }
+ }
+
+ private static void printReportFileHeader() {
+ printWriter.println(" # Report File autogenerated from the MapleCashDropFetcher feature by Ronan Lana.");
+ printWriter.println(" # Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls.");
+ printWriter.println();
+ }
+
+ private static void listFiles(String directoryName, ArrayList files) {
+ File directory = new File(directoryName);
+
+ // get all the files from a directory
+ File[] fList = directory.listFiles();
+ for (File file : fList) {
+ if (file.isFile()) {
+ files.add(file);
+ } else if (file.isDirectory()) {
+ listFiles(file.getAbsolutePath(), files);
+ }
+ }
+ }
+
+ private static int getItemIdFromFilename(String name) {
+ try {
+ return Integer.valueOf(name.substring(0, name.indexOf('.')));
+ } catch(Exception e) {
+ return -1;
+ }
+ }
+
+ private static String getDropTableName(boolean dropdata) {
+ return (dropdata ? "drop_data" : "reactordrops");
+ }
+
+ private static String getDropElementName(boolean dropdata) {
+ return (dropdata ? "dropperid" : "reactorid");
+ }
+
+ private static void filterNxDropsOnDB(boolean dropdata) throws SQLException {
+ nxDrops.clear();
+
+ PreparedStatement ps = con.prepareStatement("SELECT DISTINCT itemid FROM " + getDropTableName(dropdata));
+ ResultSet rs = ps.executeQuery();
+
+ while(rs.next()) {
+ int itemid = rs.getInt("itemid");
+
+ if(nxItems.contains(itemid)) {
+ nxDrops.add(itemid);
+ }
+ }
+
+ rs.close();
+ ps.close();
+ }
+
+ private static List> getNxDropsEntries(boolean dropdata) throws SQLException {
+ List> entries = new ArrayList<>();
+
+ List sortedNxDrops = new ArrayList<>(nxDrops);
+ Collections.sort(sortedNxDrops);
+
+ for(Integer nx : sortedNxDrops) {
+ PreparedStatement ps = con.prepareStatement("SELECT " + getDropElementName(dropdata) + " FROM " + getDropTableName(dropdata) + " WHERE itemid = ?");
+ ps.setInt(1, nx);
+
+ ResultSet rs = ps.executeQuery();
+ while(rs.next()) {
+ entries.add(new Pair<>(nx, rs.getInt(getDropElementName(dropdata))));
+ }
+
+ rs.close();
+ ps.close();
+ }
+
+ return entries;
+ }
+
+ private static void reportNxDropResults(boolean dropdata) throws SQLException {
+ filterNxDropsOnDB(dropdata);
+
+ if(!nxDrops.isEmpty()) {
+ List> nxEntries = getNxDropsEntries(dropdata);
+
+ printWriter.println("NX DROPS ON " + getDropTableName(dropdata));
+ for(Pair nx : nxEntries) {
+ printWriter.println(nx.left + " : " + nx.right);
+ }
+ printWriter.println("\n\n\n");
+ }
+ }
+
+ private static void ReportNxDropData() {
+ try {
+ Class.forName(driver).newInstance();
+
+ System.out.println("Reading Character.wz ...");
+ ArrayList files = new ArrayList<>();
+ listFiles(wzPath + "/Character.wz", files);
+
+ for(File f : files) {
+ //System.out.println("Parsing " + f.getAbsolutePath());
+ int itemid = getItemIdFromFilename(f.getName());
+ if(itemid < 0) {
+ continue;
+ }
+
+ fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+ bufferedReader = new BufferedReader(fileReader);
+
+ currentItemid = itemid;
+ inspectEquipWzEntry();
+
+ bufferedReader.close();
+ fileReader.close();
+ }
+
+ System.out.println("Reading Item.wz ...");
+ files = new ArrayList<>();
+ listFiles(wzPath + "/Item.wz", files);
+
+ for(File f : files) {
+ //System.out.println("Parsing " + f.getAbsolutePath());
+ fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+ bufferedReader = new BufferedReader(fileReader);
+
+ if(f.getName().length() <= itemFileNameSize) {
+ inspectItemWzEntry();
+ } else { // pet file structure is similar to equips, maybe there are other item-types following this behaviour?
+ int itemid = getItemIdFromFilename(f.getName());
+ if(itemid < 0) {
+ continue;
+ }
+
+ currentItemid = itemid;
+ inspectEquipWzEntry();
+ }
+
+ bufferedReader.close();
+ fileReader.close();
+ }
+
+ System.out.println("Reporting results...");
+
+ // filter drop data on DB
+ con = DriverManager.getConnection(host, username, password);
+
+ // report suspects of missing quest drop data, as well as those drop data that may have incorrect questids.
+ printWriter = new PrintWriter(newFile, "UTF-8");
+ printReportFileHeader();
+
+ reportNxDropResults(true);
+ reportNxDropResults(false);
+
+ /*
+ printWriter.println("NX LIST"); // list of all cash items found
+ for(Integer nx : nxItems) {
+ printWriter.println(nx);
+ }
+ */
+
+ con.close();
+ printWriter.close();
+ System.out.println("Done!");
+ }
+
+ catch(SQLException e) {
+ System.out.println("Warning: Could not establish connection to database to report quest data.");
+ System.out.println(e.getMessage());
+ }
+
+ catch(ClassNotFoundException e) {
+ System.out.println("Error: could not find class");
+ System.out.println(e.getMessage());
+ }
+
+ catch(InstantiationException e) {
+ System.out.println("Error: instantiation failure");
+ System.out.println(e.getMessage());
+ }
+
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ ReportNxDropData();
+ }
+
+}
diff --git a/tools/MapleCashDropFetcher/src/tools/DatabaseConnection.java b/tools/MapleCashDropFetcher/src/tools/DatabaseConnection.java
new file mode 100644
index 0000000000..9dcd4e6545
--- /dev/null
+++ b/tools/MapleCashDropFetcher/src/tools/DatabaseConnection.java
@@ -0,0 +1,51 @@
+package tools;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * @author Frz (Big Daddy)
+ * @author The Real Spookster (some modifications to this beautiful code)
+ */
+public class DatabaseConnection {
+ private static String DB_URL = "jdbc:mysql://localhost:3306/heavenms";
+ private static String DB_USER = "root";
+ private static String DB_PASS = "";
+
+ public static final int RETURN_GENERATED_KEYS = 1;
+
+ private static ThreadLocal con = new ThreadLocalConnection();
+
+ public static Connection getConnection() {
+ Connection c = con.get();
+ try {
+ c.getMetaData();
+ } catch (SQLException e) { // connection is dead, therefore discard old object 5ever
+ con.remove();
+ c = con.get();
+ }
+ return c;
+ }
+
+ private static class ThreadLocalConnection extends ThreadLocal {
+
+ @Override
+ protected Connection initialValue() {
+ try {
+ Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver
+ } catch (ClassNotFoundException e) {
+ System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams.");
+ e.printStackTrace();
+ return null;
+ }
+ try {
+ return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
+ } catch (SQLException e) {
+ System.out.println("[SEVERE] Unable to make database connection.");
+ e.printStackTrace();
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleCashDropFetcher/src/tools/Pair.java b/tools/MapleCashDropFetcher/src/tools/Pair.java
new file mode 100644
index 0000000000..f88718cbe3
--- /dev/null
+++ b/tools/MapleCashDropFetcher/src/tools/Pair.java
@@ -0,0 +1,121 @@
+/*
+This file is part of the OdinMS Maple Story Server
+Copyright (C) 2008 ~ 2010 Patrick Huy
+Matthias Butz
+Jan Christian Meyer
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License 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 .
+ */
+package tools;
+
+/**
+ * Represents a pair of values.
+ *
+ * @author Frz
+ * @since Revision 333
+ * @version 1.0
+ *
+ * @param The type of the left value.
+ * @param The type of the right value.
+ */
+public class Pair {
+
+ public E left;
+ public F right;
+
+ /**
+ * Class constructor - pairs two objects together.
+ *
+ * @param left The left object.
+ * @param right The right object.
+ */
+ public Pair(E left, F right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Gets the left value.
+ *
+ * @return The left value.
+ */
+ public E getLeft() {
+ return left;
+ }
+
+ /**
+ * Gets the right value.
+ *
+ * @return The right value.
+ */
+ public F getRight() {
+ return right;
+ }
+
+ /**
+ * Turns the pair into a string.
+ *
+ * @return Each value of the pair as a string joined by a colon.
+ */
+ @Override
+ public String toString() {
+ return left.toString() + ":" + right.toString();
+ }
+
+ /**
+ * Gets the hash code of this pair.
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((left == null) ? 0 : left.hashCode());
+ result = prime * result + ((right == null) ? 0 : right.hashCode());
+ return result;
+ }
+
+ /**
+ * Checks to see if two pairs are equal.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Pair other = (Pair) obj;
+ if (left == null) {
+ if (other.left != null) {
+ return false;
+ }
+ } else if (!left.equals(other.left)) {
+ return false;
+ }
+ if (right == null) {
+ if (other.right != null) {
+ return false;
+ }
+ } else if (!right.equals(other.right)) {
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleMesoFetcher/nbproject/private/private.xml b/tools/MapleMesoFetcher/nbproject/private/private.xml
index f02aee0624..6807a2ba19 100644
--- a/tools/MapleMesoFetcher/nbproject/private/private.xml
+++ b/tools/MapleMesoFetcher/nbproject/private/private.xml
@@ -2,8 +2,6 @@
-
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java
-
+
diff --git a/tools/MapleQuestItemFetcher/dist/MapleQuestItemFetcher.jar b/tools/MapleQuestItemFetcher/dist/MapleQuestItemFetcher.jar
index eecb39f117..a81e6a6878 100644
Binary files a/tools/MapleQuestItemFetcher/dist/MapleQuestItemFetcher.jar and b/tools/MapleQuestItemFetcher/dist/MapleQuestItemFetcher.jar differ
diff --git a/tools/MapleQuestItemFetcher/lib/QuestReport.txt b/tools/MapleQuestItemFetcher/lib/QuestReport.txt
index 23c39d930f..0d20e38d85 100644
--- a/tools/MapleQuestItemFetcher/lib/QuestReport.txt
+++ b/tools/MapleQuestItemFetcher/lib/QuestReport.txt
@@ -2,33 +2,28 @@
# Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls.
INCORRECT QUESTIDS ON DB
-4001342 : 7777 -> 28175
+2022055 : -1 -> 9330 EXPIRED
+2022056 : -1 -> 9330 EXPIRED
+4001352 : 28205 -> 28206
+4001366 : 28194 -> 28195
4001367 : 28257 -> 28262
4001368 : 28258 -> 28262
4001369 : 28259 -> 28262
4001370 : 28260 -> 28262
4001371 : 28261 -> 28262
+4001372 : 28344 -> 28282
+4031107 : -1 -> 3409
+4031116 : -1 -> 3419
4031130 : 0 -> 3238
4031164 : 0 -> 2084
-4031171 : 0 -> 7101
-4031172 : 7103 -> 7106
4031189 : 0 -> 3448
4031218 : 0 -> 3071
4031223 : 3607 -> 3608
-4031343 : 6904 -> 6905
-4031344 : 6904 -> 6905
-4031405 : 0 -> 4207
+4031405 : 0 -> 4207 EXPIRED
4031511 : 6904 -> 6914
-4031512 : 6914 -> 6915
-4031514 : 6924 -> 6925
-4031515 : 6924 -> 6925
-4031517 : 6934 -> 6935
-4031518 : 6934 -> 6935
4031856 : 0 -> 2191
4031857 : 0 -> 2192
-4031860 : 6944 -> 6945
-4031861 : 6944 -> 6945
-4031871 : 6350 -> 28344
+4032319 : -1 -> 21723
4032324 : 21736 -> 21737
4032339 : 0 -> 21303
@@ -38,283 +33,195 @@ INCORRECT QUESTIDS ON DB
ITEMS WITH NO QUEST DROP DATA ON DB
-1002436 - 2075
-1102057 - 7103
-1102061 - 3066
1302014 - 2048
-2022053 - 9330
-2022054 - 9330
-2022055 - 9330
-2022056 - 9330
-2022057 - 9332
-2022281 - 8569
-2100016 - 3223
-2100017 - 3419
-2100018 - 3236
-2100019 - 3238
-3994139 - 10360
-4001118 - 3814
-4001340 - 28167
-4001347 - 28229
-4001348 - 28231
-4001349 - 28235
-4001350 - 28235
-4001351 - 28237
-4001352 - 28206
+2022053 - 9330 EXPIRED
+2022054 - 9330 EXPIRED
+2022057 - 9332 EXPIRED
+3994139 - 10360 EXPIRED
+4000142 - 1018
4001353 - 28227
-4001366 - 28195
4031014 - 2020
-4031015 - 2022
-4031019 - 9411
+4031015 - 2020
4031020 - 2050
+4031025 - 2052
+4031026 - 2053
+4031028 - 2054
4031032 - 2051
4031039 - 2055
4031040 - 2056
4031041 - 2057
4031042 - 2035
-4031063 - 9260
+4031063 - 9260 EXPIRED
4031064 - 8012
-4031107 - 3409
-4031116 - 3419
4031117 - 3421
-4031122 - 9340
-4031124 - 9340
-4031134 - 3443
-4031136 - 3439
-4031141 - 3407
-4031142 - 3407
-4031143 - 3407
+4031122 - 9340 EXPIRED
+4031124 - 9340 EXPIRED
4031144 - 2047
-4031150 - 2067
-4031157 - 2074
-4031158 - 2074
-4031165 - 2086
-4031167 - 9052
-4031168 - 9055
-4031169 - 9058
+4031167 - 9052 EXPIRED
+4031168 - 9055 EXPIRED
+4031169 - 9058 EXPIRED
4031180 - 8020
-4031181 - 9140
-4031182 - 9140
-4031183 - 9140
-4031184 - 9150
-4031185 - 9150
-4031186 - 9150
-4031190 - 3054
+4031181 - 9140 EXPIRED
+4031182 - 9140 EXPIRED
+4031183 - 9140 EXPIRED
+4031184 - 9150 EXPIRED
+4031185 - 9150 EXPIRED
+4031186 - 9150 EXPIRED
+4031190 - 3055
4031191 - 3063
-4031192 - 8700
-4031198 - 3043
-4031199 - 3046
-4031200 - 3069
+4031192 - 8700 EXPIRED
+4031199 - 3045
4031201 - 3048
4031202 - 3050
4031207 - 3443
-4031220 - 9210
-4031225 - 3606
-4031226 - 9321
+4031220 - 9210 EXPIRED
+4031226 - 9321 EXPIRED
4031227 - 4103 EXPIRED
4031230 - 3619
-4031231 - 3620
-4031235 - 3607
+4031235 - 3615
4031236 - 3616
-4031237 - 3605
-4031238 - 3611
+4031237 - 3617
+4031238 - 3618
4031243 - 3443
-4031257 - 9350
-4031258 - 9351
-4031270 - 3629
-4031271 - 9351
-4031272 - 9352
-4031274 - 3083
-4031275 - 3083
-4031276 - 3083
-4031277 - 3083
-4031278 - 3083
-4031280 - 3632
-4031290 - 4106
-4031291 - 4006
-4031292 - 4009
-4031293 - 4010
-4031296 - 4010
-4031297 - 9386
-4031298 - 3636
-4031301 - 9391
-4031302 - 9503
-4031303 - 4008
-4031304 - 9392
-4031321 - 9504
-4031352 - 4005
-4031354 - 4013
-4031388 - 4218
-4031418 - 8823
-4031419 - 8823
-4031420 - 8823
-4031421 - 8823
-4031425 - 8822
+4031257 - 9350 EXPIRED
+4031270 - 3630
+4031271 - 9351 EXPIRED
+4031272 - 9352 EXPIRED
+4031280 - 3633
+4031290 - 4104 EXPIRED
+4031291 - 4006 EXPIRED
+4031292 - 4006 EXPIRED
+4031293 - 4006 EXPIRED
+4031296 - 4010 EXPIRED
+4031297 - 9386 EXPIRED
+4031298 - 3639
+4031301 - 9391 EXPIRED
+4031302 - 9503 EXPIRED
+4031303 - 4007 EXPIRED
+4031304 - 9392 EXPIRED
+4031321 - 9504 EXPIRED
+4031352 - 4005 EXPIRED
+4031354 - 4013 EXPIRED
+4031388 - 4218 EXPIRED
+4031418 - 8823 EXPIRED
+4031419 - 8823 EXPIRED
+4031420 - 8823 EXPIRED
+4031421 - 8823 EXPIRED
4031448 - 6134
-4031450 - 6263
-4031452 - 6201
-4031454 - 6281
4031455 - 6280
4031456 - 6230
4031462 - 6210
4031468 - 6222
-4031471 - 6153
4031478 - 6210
4031488 - 6312
-4031495 - 6192
-4031504 - 9640
-4031505 - 9641
-4031506 - 9642
-4031507 - 6002
-4031508 - 6002
+4031504 - 9640 EXPIRED
+4031505 - 9641 EXPIRED
+4031506 - 9642 EXPIRED
4031554 - 3821
-4031557 - 9710
-4031558 - 9711
-4031559 - 9712
-4031560 - 9713
-4031561 - 9714
-4031563 - 8850
-4031564 - 8851
-4031565 - 8852
-4031566 - 8853
-4031567 - 8854
-4031568 - 3911
-4031570 - 3939
-4031571 - 3941
-4031574 - 3935
+4031557 - 9710 EXPIRED
+4031558 - 9711 EXPIRED
+4031559 - 9712 EXPIRED
+4031560 - 9713 EXPIRED
+4031561 - 9714 EXPIRED
+4031563 - 8855
+4031564 - 8856
+4031565 - 8857
+4031566 - 8858
+4031567 - 8859
+4031570 - 3938
+4031571 - 3940
4031578 - 3923
-4031581 - 3937
-4031582 - 3901
-4031584 - 9731
-4031585 - 9732
-4031586 - 9740
-4031587 - 9741
-4031588 - 9742
-4031590 - 8881
-4031608 - 9803
-4031611 - 9804
-4031612 - 9805
+4031582 - 3949
+4031584 - 9731 EXPIRED
+4031585 - 9732 EXPIRED
+4031586 - 9740 EXPIRED
+4031587 - 9741 EXPIRED
+4031588 - 9742 EXPIRED
+4031590 - 8881 EXPIRED
+4031608 - 9803 EXPIRED
+4031611 - 9804 EXPIRED
+4031612 - 9805 EXPIRED
4031625 - 9820
-4031661 - 9861
-4031662 - 9866
-4031667 - 9863
-4031683 - 1115
-4031684 - 1116
-4031685 - 1117
-4031686 - 1118
-4031687 - 1119
-4031688 - 1120
-4031689 - 1121
-4031690 - 1122
-4031691 - 1123
-4031692 - 1124
-4031695 - 3335
+4031661 - 9861 EXPIRED
+4031662 - 9866 EXPIRED
+4031667 - 9863 EXPIRED
4031696 - 3334
4031697 - 3322
-4031703 - 3302
4031708 - 3309
-4031709 - 3310
-4031737 - 3343
-4031764 - 4949
-4031766 - 4959
-4031767 - 4947
-4031768 - 4953
-4031769 - 4946
-4031770 - 4946
-4031771 - 4944
+4031764 - 4949 EXPIRED
+4031766 - 4959 EXPIRED
+4031767 - 4947 EXPIRED
+4031769 - 4946 EXPIRED
+4031770 - 4946 EXPIRED
4031772 - 4942
4031774 - 3361
4031785 - 3376
-4031789 - 3844
4031796 - 3362
4031797 - 3367
-4031798 - 3366
-4031801 - 1040
-4031806 - 3380
-4031812 - 4950
-4031833 - 9946
-4031837 - 9945
+4031806 - 3379
+4031812 - 4950 EXPIRED
+4031837 - 9942 EXPIRED
4031839 - 2162
-4031881 - 4484
-4031894 - 2214
+4031850 - 2180
+4031881 - 4484 EXPIRED
4031921 - 4646
-4031927 - 3454
-4031928 - 3454
-4031945 - 9987
-4032037 - 9154
-4032038 - 9154
-4032039 - 9154
-4032055 - 4675
-4032087 - 10081
-4032092 - 28003
-4032119 - 28109
+4032037 - 9154 EXPIRED
+4032038 - 9154 EXPIRED
+4032039 - 9154 EXPIRED
+4032087 - 10081 EXPIRED
+4032119 - 28109 EXPIRED
4032136 - 20710
-4032138 - 20713
+4032138 - 20712
4032142 - 20716
-4032143 - 20717
4032196 - 20528
4032197 - 20528
4032198 - 20528
-4032233 - 8298
-4032234 - 8299
-4032235 - 8299
-4032236 - 8299
-4032237 - 8299
-4032238 - 8299
-4032239 - 8299
-4032247 - 28103
-4032248 - 28108
-4032264 - 10240
-4032265 - 10241
-4032266 - 10240
-4032270 - 10241
-4032271 - 10260
-4032272 - 10268
-4032273 - 10268
-4032275 - 10261
-4032276 - 10262
-4032277 - 10263
-4032278 - 10270
-4032279 - 10271
-4032280 - 10272
-4032281 - 10270
-4032282 - 10271
-4032283 - 10272
-4032284 - 10264
-4032285 - 10265
-4032286 - 10266
-4032287 - 10267
-4032307 - 28121
-4032308 - 28122
-4032317 - 21717
-4032318 - 21718
-4032319 - 21723
-4032321 - 21727
-4032325 - 21752
+4032233 - 8298 EXPIRED
+4032234 - 8299 EXPIRED
+4032235 - 8299 EXPIRED
+4032236 - 8299 EXPIRED
+4032237 - 8299 EXPIRED
+4032238 - 8299 EXPIRED
+4032239 - 8298 EXPIRED
+4032248 - 28108 EXPIRED
+4032264 - 10240 EXPIRED
+4032265 - 10241 EXPIRED
+4032266 - 10240 EXPIRED
+4032270 - 10241 EXPIRED
+4032271 - 10260 EXPIRED
+4032272 - 10268 EXPIRED
+4032273 - 10268 EXPIRED
+4032275 - 10261 EXPIRED
+4032276 - 10262 EXPIRED
+4032277 - 10263 EXPIRED
+4032278 - 10270 EXPIRED
+4032279 - 10271 EXPIRED
+4032280 - 10272 EXPIRED
+4032281 - 10270 EXPIRED
+4032282 - 10271 EXPIRED
+4032283 - 10272 EXPIRED
+4032284 - 10264 EXPIRED
+4032285 - 10265 EXPIRED
+4032286 - 10266 EXPIRED
+4032287 - 10267 EXPIRED
+4032306 - 28120 EXPIRED
+4032307 - 28121 EXPIRED
+4032308 - 28122 EXPIRED
+4032325 - 21751
4032326 - 21752
4032331 - 21601
4032333 - 21608
-4032335 - 21617
-4032342 - 21743
-4032348 - 10300
-4032349 - 10301
-4032350 - 10302
-4032374 - 2405
-4032376 - 2406
-4032377 - 2407
-4032378 - 2408
-4032379 - 2409
+4032348 - 10300 EXPIRED
+4032349 - 10301 EXPIRED
+4032350 - 10302 EXPIRED
4032401 - 2261
4032402 - 2263
-4032404 - 28128
+4032404 - 28128 EXPIRED
4032423 - 21767
-4032435 - 28307
-4032436 - 28314
-4032437 - 28321
-4032443 - 28317
-4032496 - 28238
-4032512 - 3720
-4161000 - 9322
+4032435 - 28307 EXPIRED
+4032436 - 28314 EXPIRED
+4032437 - 28321 EXPIRED
+4161000 - 9322 EXPIRED
@@ -322,87 +229,27 @@ ITEMS WITH NO QUEST DROP DATA ON DB
COMPLETE QUEST ITEMS WITH ZERO QUANTITY
-1018:
- 4000142
-
-2052:
- 4031025
-
-2053:
- 4031026
-
-2054:
- 4031028
-
-2167:
- 4031841
-
-2168:
- 4031842
-
-2169:
- 4031843
-
-2173:
- 4031846
-
-2180:
- 4031850
-
-2183:
- 4031851
-
-2185:
- 4031852
-
-3010:
- 4031050
-
-6340:
- 4031872
-
-6350:
- 4031871
-
-6360:
- 4031869
-
-6361:
- 4031870
-
-6380:
- 4031873
-
-6390:
- 4031874
-
8142:
4000300
4000301
-8218:
+8218 EXPIRED:
4031664
4031665
4031666
-8886:
+8886 EXPIRED:
4031659
-8887:
+8887 EXPIRED:
4031658
-8888:
+8888 EXPIRED:
4031660
-10430:
- 4220152
-
28104:
4032247
-28120:
- 4032306
-
diff --git a/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java b/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java
index 8231c38585..e6879b655a 100644
--- a/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java
+++ b/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java
@@ -72,7 +72,6 @@ public class MapleQuestItemFetcher {
static String password = "";
static String wzPath = "../../wz";
- static String fileName = "../../wz/Quest.wz/Act.img.xml";
static String directoryName = "../..";
static String newFile = "lib/QuestReport.txt";
@@ -134,6 +133,28 @@ public class MapleQuestItemFetcher {
return(d.trim());
}
+ private static void forwardCursor(int st) {
+ String line = null;
+
+ try {
+ while(status >= st && (line = bufferedReader.readLine()) != null) {
+ simpleToken(line);
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void simpleToken(String token) {
+ if(token.contains("/imgdir")) {
+ status -= 1;
+ }
+ else if(token.contains("imgdir")) {
+ status += 1;
+ }
+ }
+
private static void inspectQuestItemList(int st) {
String line = null;
@@ -152,24 +173,28 @@ public class MapleQuestItemFetcher {
if(ii.isQuestItem(currentItemid)) {
if(currentCount != 0) {
if(isCompleteState == 1) {
- Set qi = completeQuestItems.get(questId);
- if(qi == null) {
- Set newSet = new HashSet<>();
- newSet.add(currentItemid);
+ if(currentCount < 0) {
+ Set qi = completeQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
- completeQuestItems.put(questId, newSet);
- } else {
- qi.add(currentItemid);
+ completeQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
}
} else {
- Set qi = startQuestItems.get(questId);
- if(qi == null) {
- Set newSet = new HashSet<>();
- newSet.add(currentItemid);
+ if(currentCount > 0) {
+ Set qi = startQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
- startQuestItems.put(questId, newSet);
- } else {
- qi.add(currentItemid);
+ startQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
}
}
} else {
@@ -222,7 +247,7 @@ public class MapleQuestItemFetcher {
}
}
- private static void translateToken(String token) {
+ private static void translateActToken(String token) {
String d;
int temp;
@@ -244,6 +269,8 @@ public class MapleQuestItemFetcher {
if(d.contains("item")) {
temp = status;
inspectQuestItemList(temp);
+ } else {
+ forwardCursor(status);
}
}
@@ -258,6 +285,37 @@ public class MapleQuestItemFetcher {
}
}
}
+
+ private static void translateCheckToken(String token) {
+ String d;
+
+ if(token.contains("/imgdir")) {
+ status -= 1;
+ }
+ else if(token.contains("imgdir")) {
+ if(status == 1) { //getting QuestId
+ d = getName(token);
+ questId = Integer.parseInt(d);
+ }
+ else if(status == 2) { //start/complete
+ d = getName(token);
+ isCompleteState = Integer.parseInt(d);
+ }
+ else if(status == 3) {
+ forwardCursor(status);
+ }
+
+ status += 1;
+ } else {
+ if(status == 3) {
+ d = getName(token);
+
+ if(d.equals("end")) {
+ limitedQuestids.add(questId);
+ }
+ }
+ }
+ }
private static void calculateQuestItemDiff() {
// This will remove started quest items from the "to complete" item set.
@@ -289,32 +347,46 @@ public class MapleQuestItemFetcher {
return list;
}
+ private static String getTableName(boolean dropdata) {
+ return dropdata ? "drop_data" : "reactordrops";
+ }
+
+ private static void filterQuestDropsOnTable(Pair iq, List> itemsWithQuest, boolean dropdata) throws SQLException {
+ PreparedStatement ps = con.prepareStatement("SELECT questid FROM " + getTableName(dropdata) + " WHERE itemid = ?;");
+ ps.setInt(1, iq.getLeft());
+ ResultSet rs = ps.executeQuery();
+
+ if (rs.isBeforeFirst()) {
+ while(rs.next()) {
+ int curQuest = rs.getInt(1);
+ if(curQuest != iq.getRight()) {
+ Set sqSet = startQuestItems.get(curQuest);
+ if(sqSet != null && sqSet.contains(iq.getLeft())) {
+ continue;
+ }
+
+ int[] mixed = new int[3];
+ mixed[0] = iq.getLeft();
+ mixed[1] = curQuest;
+ mixed[2] = iq.getRight();
+
+ mixedQuestidItems.put(iq.getLeft(), mixed);
+ }
+ }
+
+ itemsWithQuest.remove(iq);
+ }
+
+ rs.close();
+ ps.close();
+ }
+
private static void filterQuestDropsOnDB(List> itemsWithQuest) throws SQLException {
List> copyItemsWithQuest = new ArrayList<>(itemsWithQuest);
try {
for(Pair iq : copyItemsWithQuest) {
- PreparedStatement ps = con.prepareStatement("SELECT questid FROM drop_data WHERE itemid = ?;");
- ps.setInt(1, iq.getLeft());
- ResultSet rs = ps.executeQuery();
-
- if (rs.isBeforeFirst()) {
- while(rs.next()) {
- int curQuest = rs.getInt(1);
- if(curQuest != iq.getRight()) {
- int[] mixed = new int[3];
- mixed[0] = iq.getLeft();
- mixed[1] = curQuest;
- mixed[2] = iq.getRight();
-
- mixedQuestidItems.put(iq.getLeft(), mixed);
- }
- }
-
- itemsWithQuest.remove(iq);
- }
-
- rs.close();
- ps.close();
+ filterQuestDropsOnTable(iq, itemsWithQuest, true);
+ filterQuestDropsOnTable(iq, itemsWithQuest, false);
}
}
catch(SQLException e) {
@@ -431,17 +503,30 @@ public class MapleQuestItemFetcher {
private static void ReportQuestItemData() {
// This will reference one line at a time
String line = null;
+ String fileName = null;
try {
Class.forName(driver).newInstance();
System.out.println("Reading WZs...");
-
+
+ fileName = wzPath + "/Quest.wz/Check.img.xml";
fileReader = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
- translateToken(line);
+ translateCheckToken(line); // fetch expired quests through here as well
+ }
+
+ bufferedReader.close();
+ fileReader.close();
+
+ fileName = wzPath + "/Quest.wz/Act.img.xml";
+ fileReader = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
+ bufferedReader = new BufferedReader(fileReader);
+
+ while((line = bufferedReader.readLine()) != null) {
+ translateActToken(line);
}
bufferedReader.close();
diff --git a/wz/Quest.wz/Check.img.xml b/wz/Quest.wz/Check.img.xml
index 98a6cc7275..149571986a 100644
--- a/wz/Quest.wz/Check.img.xml
+++ b/wz/Quest.wz/Check.img.xml
@@ -22139,12 +22139,7 @@
-
-
-
-
-
-
+
diff --git a/wz/String.wz/Consume.img.xml b/wz/String.wz/Consume.img.xml
index 0cc87d7222..1c3100271c 100644
--- a/wz/String.wz/Consume.img.xml
+++ b/wz/String.wz/Consume.img.xml
@@ -4743,510 +4743,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -9204,4 +8700,508 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+