diff --git a/src/main/java/tools/mapletools/QuestItemCountFetcher.java b/src/main/java/tools/mapletools/QuestItemCountFetcher.java
new file mode 100644
index 0000000000..fb0a453a92
--- /dev/null
+++ b/src/main/java/tools/mapletools/QuestItemCountFetcher.java
@@ -0,0 +1,268 @@
+package tools.mapletools;
+
+import provider.wz.WZFiles;
+import tools.Pair;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+/**
+ * @author RonanLana
+ *
+ * This application parses the Quest.wz file inputted and generates a report showing
+ * all cases where a quest requires an item, but doesn't take them, which may happen
+ * because the node representing the item doesn't have a "count" clause.
+ *
+ * Running it should generate a report file under "output" folder with the search results.
+ */
+public class QuestItemCountFetcher {
+ private static final File OUTPUT_FILE = ToolConstants.getOutputFile("quest_item_count_report.txt");
+ private static final String ACT_NAME = WZFiles.QUEST.getFilePath() + "/Act.img.xml";
+ private static final String CHECK_NAME = WZFiles.QUEST.getFilePath() + "/Check.img.xml";
+ private static final int INITIAL_STRING_LENGTH = 50;
+
+ private static final Map> checkItems = new HashMap<>();
+ private static final Map> actItems = new HashMap<>();
+
+ private static PrintWriter printWriter = null;
+ private static BufferedReader bufferedReader = null;
+ private static byte status = 0;
+ private static int questId = -1;
+ private static int isCompleteState = 0;
+ private static int curItemId;
+ private static int curItemCount;
+
+ 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
+
+ dest = new char[INITIAL_STRING_LENGTH];
+ 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[INITIAL_STRING_LENGTH];
+ 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 readItemLabel(String token) {
+ String name = getName(token);
+ String value = getValue(token);
+
+ switch (name) {
+ case "id" -> curItemId = Integer.parseInt(value);
+ case "count" -> curItemCount = Integer.parseInt(value);
+ }
+ }
+
+ private static void commitQuestItemPair(Map> map) {
+ Map list = map.get(questId);
+ if (list == null) {
+ list = new LinkedHashMap<>();
+ map.put(questId, list);
+ }
+
+ list.put(curItemId, curItemCount);
+ }
+
+ private static void translateTokenAct(String token) {
+ String d;
+
+ if (token.contains("/imgdir")) {
+ status -= 1;
+
+ if (status == 4) {
+ if (curItemCount == Integer.MAX_VALUE && isCompleteState == 1) {
+ commitQuestItemPair(actItems);
+ }
+ }
+ } 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) {
+ if (!token.contains("item")) {
+ forwardCursor(status);
+ }
+ } else if (status == 4) {
+ curItemId = Integer.MAX_VALUE;
+ curItemCount = Integer.MAX_VALUE;
+ }
+
+ status += 1;
+ } else {
+ if (status == 5) {
+ readItemLabel(token);
+ }
+ }
+ }
+
+ private static void translateTokenCheck(String token) {
+ String d;
+
+ if (token.contains("/imgdir")) {
+ status -= 1;
+
+ if (status == 4) {
+ Map missedItems = actItems.get(questId);
+
+ if (missedItems != null && missedItems.containsKey(curItemId) && isCompleteState == 1) {
+ commitQuestItemPair(checkItems);
+ }
+ }
+ } 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) {
+ if (!token.contains("item")) {
+ forwardCursor(status);
+ }
+ } else if (status == 4) {
+ curItemId = Integer.MAX_VALUE;
+ curItemCount = Integer.MAX_VALUE;
+ }
+
+ status += 1;
+ } else {
+ if (status == 5) {
+ readItemLabel(token);
+ }
+ }
+ }
+
+ private static void readQuestItemCountData() throws IOException {
+ String line;
+
+ InputStreamReader fileReader = new InputStreamReader(new FileInputStream(ACT_NAME), StandardCharsets.UTF_8);
+ bufferedReader = new BufferedReader(fileReader);
+
+ while ((line = bufferedReader.readLine()) != null) {
+ translateTokenAct(line);
+ }
+
+ bufferedReader.close();
+ fileReader.close();
+
+ fileReader = new InputStreamReader(new FileInputStream(CHECK_NAME), StandardCharsets.UTF_8);
+ bufferedReader = new BufferedReader(fileReader);
+
+ while ((line = bufferedReader.readLine()) != null) {
+ translateTokenCheck(line);
+ }
+
+ bufferedReader.close();
+ fileReader.close();
+ }
+
+ private static void printReportFileHeader() {
+ printWriter.println(" # Report File autogenerated from the MapleQuestItemCountFetcher feature by Ronan Lana.");
+ printWriter.println(" # Generated data takes into account several data info from the server-side WZ.xmls.");
+ printWriter.println();
+ }
+
+ private static void printReportFileResults() {
+ List>> reports = new ArrayList<>();
+ List> notChecked = new ArrayList<>();
+
+ for (Map.Entry> actItem : actItems.entrySet()) {
+ int questid = actItem.getKey();
+
+ for (Map.Entry actData : actItem.getValue().entrySet()) {
+ int itemid = actData.getKey();
+
+ Map checkData = checkItems.get(questid);
+ if (checkData != null) {
+ Integer count = checkData.get(itemid);
+ if (count != null) {
+ reports.add(new Pair<>(questid, new Pair<>(itemid, -count)));
+ }
+ } else {
+ notChecked.add(new Pair<>(questid, itemid));
+ }
+ }
+ }
+
+ for (Pair> r : reports) {
+ printWriter.println("Questid " + r.left + " : Itemid " + r.right.left + " should have qty " + r.right.right);
+ }
+
+ for (Pair r : notChecked) {
+ printWriter.println("Questid " + r.left + " : Itemid " + r.right + " is unchecked");
+ }
+ }
+
+ private static void reportQuestItemCountData() {
+ // This will reference one line at a time
+
+ try {
+ System.out.println("Reading WZs...");
+ readQuestItemCountData();
+
+ System.out.println("Reporting results...");
+ printWriter = new PrintWriter(OUTPUT_FILE, StandardCharsets.UTF_8);
+
+ printReportFileHeader();
+ printReportFileResults();
+
+ printWriter.close();
+ System.out.println("Done!");
+ } catch (FileNotFoundException ex) {
+ System.out.println("Unable to open quest file.");
+ } catch (IOException ex) {
+ System.out.println("Error reading quest file.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ reportQuestItemCountData();
+ }
+}
diff --git a/tools/MapleQuestItemCountFetcher/lib/QuestReport.txt b/tools/MapleQuestItemCountFetcher/lib/QuestReport.txt
deleted file mode 100644
index 2ac6bb6388..0000000000
--- a/tools/MapleQuestItemCountFetcher/lib/QuestReport.txt
+++ /dev/null
@@ -1,22 +0,0 @@
- # Report File autogenerated from the MapleQuestItemCountFetcher feature by Ronan Lana.
- # Generated data takes into account several data info from the server-side WZ.xmls.
-
-Questid 2167 : Itemid 4031841 should have qty -1
-Questid 1018 : Itemid 4000142 should have qty -1
-Questid 6361 : Itemid 4031870 should have qty -1
-Questid 6360 : Itemid 4031869 should have qty -1
-Questid 10430 : Itemid 4220152 should have qty -1
-Questid 6390 : Itemid 4031874 should have qty -50
-Questid 2173 : Itemid 4031846 should have qty -1
-Questid 2169 : Itemid 4031843 should have qty -1
-Questid 2168 : Itemid 4031842 should have qty -1
-Questid 2185 : Itemid 4031852 should have qty -1
-Questid 6380 : Itemid 4031873 should have qty -50
-Questid 6350 : Itemid 4031871 should have qty -50
-Questid 2052 : Itemid 4031025 should have qty -10
-Questid 2053 : Itemid 4031026 should have qty -20
-Questid 2054 : Itemid 4031028 should have qty -30
-Questid 6340 : Itemid 4031872 should have qty -50
-Questid 28120 : Itemid 4032306 should have qty -4
-Questid 2180 : Itemid 4031850 should have qty -1
-Questid 2183 : Itemid 4031851 should have qty -1
diff --git a/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/MapleQuestItemCountFetcher.java b/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/MapleQuestItemCountFetcher.java
deleted file mode 100644
index f06cd1f2f3..0000000000
--- a/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/MapleQuestItemCountFetcher.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 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 maplequestitemcountfetcher;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.LinkedHashMap;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- *
- * @author RonanLana
-
- This application parses the Quest.wz file inputted and generates a report showing
- all cases where a quest requires an item, but doesn't take them, which may happen
- because the node representing the item doesn't have a "count" clause.
-
- Running it should generate a report file under "lib" folder with the search results.
-
- */
-public class MapleQuestItemCountFetcher {
- static String actName = "../../wz/Quest.wz/Act.img.xml";
- static String checkName = "../../wz/Quest.wz/Check.img.xml";
- static String newFile = "lib/QuestReport.txt";
-
- static PrintWriter printWriter = null;
- static InputStreamReader fileReader = null;
- static BufferedReader bufferedReader = null;
-
- static int initialLength = 200;
- static int initialStringLength = 50;
-
- static byte status = 0;
- static int questId = -1;
- static int isCompleteState = 0;
-
- static int curItemId;
- static int curItemCount;
-
- static Map> checkItems = new HashMap<>();
- static Map> actItems = new HashMap<>();
-
- 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
-
- 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 readItemLabel(String token) {
- String name = getName(token);
- String value = getValue(token);
-
- switch(name) {
- case "id":
- curItemId = Integer.parseInt(value);
- break;
-
- case "count":
- curItemCount = Integer.parseInt(value);
- break;
- }
- }
-
- private static void commitQuestItemPair(Map> map) {
- Map list = map.get(questId);
- if(list == null) {
- list = new LinkedHashMap<>();
- map.put(questId, list);
- }
-
- list.put(curItemId, curItemCount);
- }
-
- private static void translateTokenAct(String token) {
- String d;
-
- if(token.contains("/imgdir")) {
- status -= 1;
-
- if(status == 4) {
- if(curItemCount == Integer.MAX_VALUE && isCompleteState == 1) {
- commitQuestItemPair(actItems);
- }
- }
- }
- 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) {
- if(!token.contains("item")) {
- forwardCursor(status);
- }
- }
- else if(status == 4) {
- curItemId = Integer.MAX_VALUE;
- curItemCount = Integer.MAX_VALUE;
- }
-
- status += 1;
- }
- else {
- if(status == 5) {
- readItemLabel(token);
- }
- }
- }
-
- private static void translateTokenCheck(String token) {
- String d;
-
- if(token.contains("/imgdir")) {
- status -= 1;
-
- if(status == 4) {
- Map missedItems = actItems.get(questId);
-
- if(missedItems != null && missedItems.containsKey(curItemId) && isCompleteState == 1) {
- commitQuestItemPair(checkItems);
- }
- }
- }
- 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) {
- if(!token.contains("item")) {
- forwardCursor(status);
- }
- }
- else if(status == 4) {
- curItemId = Integer.MAX_VALUE;
- curItemCount = Integer.MAX_VALUE;
- }
-
- status += 1;
- }
- else {
- if(status == 5) {
- readItemLabel(token);
- }
- }
- }
-
- private static void readQuestItemCountData() throws IOException {
- String line;
-
- fileReader = new InputStreamReader(new FileInputStream(actName), "UTF-8");
- bufferedReader = new BufferedReader(fileReader);
-
- while((line = bufferedReader.readLine()) != null) {
- translateTokenAct(line);
- }
-
- bufferedReader.close();
- fileReader.close();
-
- fileReader = new InputStreamReader(new FileInputStream(checkName), "UTF-8");
- bufferedReader = new BufferedReader(fileReader);
-
- while((line = bufferedReader.readLine()) != null) {
- translateTokenCheck(line);
- }
-
- bufferedReader.close();
- fileReader.close();
- }
-
- private static void printReportFileHeader() {
- printWriter.println(" # Report File autogenerated from the MapleQuestItemCountFetcher feature by Ronan Lana.");
- printWriter.println(" # Generated data takes into account several data info from the server-side WZ.xmls.");
- printWriter.println();
- }
-
- private static void printReportFileResults() {
- List>> reports = new ArrayList<>();
- List> notChecked = new ArrayList<>();
-
- for(Entry> actItem : actItems.entrySet()) {
- int questid = actItem.getKey();
-
- for(Entry actData : actItem.getValue().entrySet()) {
- int itemid = actData.getKey();
-
- Map checkData = checkItems.get(questid);
- if(checkData != null) {
- Integer count = checkData.get(itemid);
- if(count != null) {
- reports.add(new Pair<>(questid, new Pair<>(itemid, -count)));
- }
- } else {
- notChecked.add(new Pair<>(questid, itemid));
- }
- }
- }
-
- for(Pair> r : reports) {
- printWriter.println("Questid " + r.left + " : Itemid " + r.right.left + " should have qty " + r.right.right);
- }
-
- for(Pair r : notChecked) {
- printWriter.println("Questid " + r.left + " : Itemid " + r.right + " is unchecked");
- }
- }
-
- private static void ReportQuestItemCountData() {
- // This will reference one line at a time
-
- try {
- System.out.println("Reading WZs...");
- readQuestItemCountData();
-
- System.out.println("Reporting results...");
- printWriter = new PrintWriter(newFile, "UTF-8");
-
- printReportFileHeader();
- printReportFileResults();
-
- printWriter.close();
- System.out.println("Done!");
- }
-
- catch(FileNotFoundException ex) {
- System.out.println("Unable to open quest file.");
- }
- catch(IOException ex) {
- System.out.println("Error reading quest file.");
- }
-
- catch(Exception e) {
- e.printStackTrace();
- }
- }
-
- public static void main(String[] args) {
- ReportQuestItemCountData();
- }
-
-}
diff --git a/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/Pair.java b/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/Pair.java
deleted file mode 100644
index 97ce258574..0000000000
--- a/tools/MapleQuestItemCountFetcher/src/maplequestitemcountfetcher/Pair.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-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 maplequestitemcountfetcher;
-
-/**
- * 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 with 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