Quest & Command tweak + MapleCashDropFetcher + Cash drop tidyup

Solved a possible exploit on starting/completing non-scripted quests.
Added missing drop data for Aran's puppeteer questline.
Moved GM tier level of some commands.
Applied proper synchronization for BuddyList modules.
Issued commands now requires "@" heading for normal players and donators (GM level < 2) and "!" for Jr. GM and above (GM level >= 2).
Added custom feature: a message will be sent to acquaintances of a player (friends, family, guild, spouse) when they change/upgrade jobs.
Removed cash drop entries from the DB.
New tool: MapleCashDropFetcher. Reports on a text file all cash-type drop data on DB.
This commit is contained in:
ronancpl
2018-04-14 13:38:14 -03:00
parent 6d91c79f28
commit 6a63f9d95e
38 changed files with 3472 additions and 1057 deletions
+4
View File
@@ -15,6 +15,10 @@
/tools/MapleBossHpBarFetcher/build/ /tools/MapleBossHpBarFetcher/build/
/tools/MapleBossHpBarFetcher/dist/ /tools/MapleBossHpBarFetcher/dist/
/tools/MapleCashDropFetcher/nbproject/private/
/tools/MapleCashDropFetcher/build/
/tools/MapleCashDropFetcher/dist/
/tools/MapleCouponInstaller/build/ /tools/MapleCouponInstaller/build/
/tools/MapleCouponInstaller/dist/ /tools/MapleCouponInstaller/dist/
/tools/MapleCouponInstaller/nbproject/private/ /tools/MapleCouponInstaller/nbproject/private/
+8 -2
View File
@@ -20,9 +20,15 @@ Server files: https://github.com/ronancpl/HeavenMS
Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V4MYVJ0TWIxd05hYUk 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 ### Support us
+6
View File
@@ -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. * 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. * 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. * 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. * 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. * 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. * 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). * 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.
--------------------------- ---------------------------
+7
View File
@@ -860,3 +860,10 @@ Corrigido NPC de guild tirando mesos do jogador sem efetuar a ação alguma caso
Localhost melhorado: retirado caps de Matk, Mdef, Wdef, Acc e Avoid. Localhost melhorado: retirado caps de Matk, Mdef, Wdef, Acc e Avoid.
Balanceado Ninja Ambush, agora dando uma quantidade de dano justificável. Balanceado Ninja Ambush, agora dando uma quantidade de dano justificável.
Implementado questline do Dyle. 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.
+7
View File
@@ -18,6 +18,13 @@ function action(mode, type, selection){
if(status == 0){ 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!"); cm.sendGetText("A suspicious voice pierces through the silence. #bPassword#k!");
} }
else if(status == 1){ else if(status == 1){
+10 -6
View File
@@ -152,6 +152,7 @@ function writeSolaxiaCommandsLv2() { //JrGM
comm_cursor = comm_lv2; comm_cursor = comm_lv2;
desc_cursor = desc_lv2; desc_cursor = desc_lv2;
addCommand("whereami", "");
addCommand("hide", ""); addCommand("hide", "");
addCommand("unhide", ""); addCommand("unhide", "");
addCommand("sp", ""); addCommand("sp", "");
@@ -188,10 +189,13 @@ function writeSolaxiaCommandsLv1() { //Donator
comm_cursor = comm_lv1; comm_cursor = comm_lv1;
desc_cursor = desc_lv1; desc_cursor = desc_lv1;
addCommand("bosshp", "");
addCommand("mobhp", "");
addCommand("whatdropsfrom", "");
addCommand("whodrops", "");
addCommand("buffme", ""); addCommand("buffme", "");
addCommand("goto", ""); addCommand("goto", "");
addCommand("recharge", ""); addCommand("recharge", "");
addCommand("whereami", "");
} }
function writeSolaxiaCommandsLv0() { //Common function writeSolaxiaCommandsLv0() { //Common
@@ -204,21 +208,21 @@ function writeSolaxiaCommandsLv0() { //Common
addCommand("credits", ""); addCommand("credits", "");
addCommand("uptime", ""); addCommand("uptime", "");
addCommand("gacha", ""); addCommand("gacha", "");
addCommand("whatdropsfrom", "");
addCommand("whodrops", "");
addCommand("dispose", ""); addCommand("dispose", "");
addCommand("equiplv", ""); addCommand("equiplv", "");
addCommand("showrates", ""); addCommand("showrates", "");
addCommand("rates", ""); addCommand("rates", "");
addCommand("online", ""); addCommand("online", "");
addCommand("gm", ""); addCommand("gm", "");
addCommand("bug", ""); addCommand("reportbug", "");
//addCommand("points", ""); //addCommand("points", "");
addCommand("joinevent", ""); addCommand("joinevent", "");
addCommand("leaveevent", ""); addCommand("leaveevent", "");
addCommand("bosshp", "");
addCommand("mobhp", "");
addCommand("ranks", ""); addCommand("ranks", "");
addCommand("str", "");
addCommand("int", "");
addCommand("luk", "");
addCommand("dex", "");
} }
function writeSolaxiaCommands() { function writeSolaxiaCommands() {
+49
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}
}
+44
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}
}
+9
View File
@@ -25,6 +25,8 @@
Quest ID: 2214 Quest ID: 2214
*/ */
importPackage(java.util);
var status = -1; var status = -1;
function end(mode, type, selection) { function end(mode, type, selection) {
@@ -42,6 +44,13 @@ function end(mode, type, selection) {
status--; status--;
if (status == 0) { 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)) { if(!qm.canHold(4031894, 1)) {
qm.sendNext("(Eh, I can't hold the #t4031894# right now, I need an ETC slot available.)"); qm.sendNext("(Eh, I can't hold the #t4031894# right now, I need an ETC slot available.)");
qm.dispose(); qm.dispose();
+9
View File
@@ -25,6 +25,8 @@
Quest ID: 2215 Quest ID: 2215
*/ */
importPackage(java.util);
var status = -1; var status = -1;
function end(mode, type, selection) { function end(mode, type, selection) {
@@ -42,6 +44,13 @@ function end(mode, type, selection) {
status--; status--;
if (status == 0) { 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) { if(qm.getMeso() < 2000) {
qm.sendNext("(Oh, I don't have the combined fee amount yet.)"); qm.sendNext("(Oh, I don't have the combined fee amount yet.)");
qm.dispose(); qm.dispose();
-3
View File
@@ -10830,9 +10830,6 @@ INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`,
(10608, 9302010, 2022524, 1, 1, 0, 100000), (10608, 9302010, 2022524, 1, 1, 0, 100000),
(10609, 9400256, 4032192, 1, 1, 0, 50000), (10609, 9400256, 4032192, 1, 1, 0, 50000),
(10610, 9400257, 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), (10614, 9410066, 4000306, 1, 1, 0, 700000),
(10615, 9410066, 4000306, 1, 1, 0, 700000), (10615, 9410066, 4000306, 1, 1, 0, 700000),
(10616, 9410066, 4000306, 1, 1, 0, 700000), (10616, 9410066, 4000306, 1, 1, 0, 700000),
+5 -3
View File
@@ -1107,7 +1107,6 @@ USE `heavenms`;
(9300063, 1052101, 1, 1, 0, 700), (9300063, 1052101, 1, 1, 0, 700),
(9300082, 1052101, 1, 1, 0, 700), (9300082, 1052101, 1, 1, 0, 700),
(9400503, 1052101, 1, 1, 0, 40000), (9400503, 1052101, 1, 1, 0, 40000),
(2100100, 5240005, 1, 1, 0, 7000),
(2100100, 4003004, 1, 1, 0, 7000), (2100100, 4003004, 1, 1, 0, 7000),
(2100100, 2000001, 1, 1, 0, 40000), (2100100, 2000001, 1, 1, 0, 40000),
(2100100, 2000003, 1, 1, 0, 40000), (2100100, 2000003, 1, 1, 0, 40000),
@@ -10022,7 +10021,6 @@ USE `heavenms`;
(9500326, 1372000, 1, 1, 0, 40000), (9500326, 1372000, 1, 1, 0, 40000),
(9500345, 1372000, 1, 1, 0, 40000), (9500345, 1372000, 1, 1, 0, 40000),
(9303004, 1372000, 1, 1, 0, 700), (9303004, 1372000, 1, 1, 0, 700),
(6130103, 1702131, 1, 1, 0, 700),
(6130103, 2000006, 1, 1, 0, 40000), (6130103, 2000006, 1, 1, 0, 40000),
(6130103, 2000004, 1, 1, 0, 40000), (6130103, 2000004, 1, 1, 0, 40000),
(6130103, 2040401, 1, 1, 0, 750), (6130103, 2040401, 1, 1, 0, 750),
@@ -20183,7 +20181,11 @@ USE `heavenms`;
(9400114, 2022063, 10, 30, 0, 200000), (9400114, 2022063, 10, 30, 0, 200000),
(9400114, 2022064, 10, 30, 0, 200000), (9400114, 2022064, 10, 30, 0, 200000),
(9400120, 4000094, 1, 1, 0, 400000), (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) # (dropperid, itemid, minqty, maxqty, questid, chance)
+35 -3
View File
@@ -26,10 +26,12 @@ import java.sql.ResultSet;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Deque; import java.util.Deque;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import net.server.PlayerStorage;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
@@ -50,15 +52,22 @@ public class BuddyList {
} }
public boolean contains(int characterId) { public boolean contains(int characterId) {
synchronized(buddies) {
return buddies.containsKey(Integer.valueOf(characterId)); return buddies.containsKey(Integer.valueOf(characterId));
} }
}
public boolean containsVisible(int characterId) { public boolean containsVisible(int characterId) {
BuddylistEntry ble = buddies.get(characterId); BuddylistEntry ble;
synchronized(buddies) {
ble = buddies.get(characterId);
}
if (ble == null) { if (ble == null) {
return false; return false;
} }
return ble.isVisible(); return ble.isVisible();
} }
public int getCapacity() { public int getCapacity() {
@@ -70,36 +79,48 @@ public class BuddyList {
} }
public BuddylistEntry get(int characterId) { public BuddylistEntry get(int characterId) {
synchronized(buddies) {
return buddies.get(Integer.valueOf(characterId)); return buddies.get(Integer.valueOf(characterId));
} }
}
public BuddylistEntry get(String characterName) { public BuddylistEntry get(String characterName) {
String lowerCaseName = characterName.toLowerCase(); String lowerCaseName = characterName.toLowerCase();
for (BuddylistEntry ble : buddies.values()) { for (BuddylistEntry ble : getBuddies()) {
if (ble.getName().toLowerCase().equals(lowerCaseName)) { if (ble.getName().toLowerCase().equals(lowerCaseName)) {
return ble; return ble;
} }
} }
return null; return null;
} }
public void put(BuddylistEntry entry) { public void put(BuddylistEntry entry) {
synchronized(buddies) {
buddies.put(Integer.valueOf(entry.getCharacterId()), entry); buddies.put(Integer.valueOf(entry.getCharacterId()), entry);
} }
}
public void remove(int characterId) { public void remove(int characterId) {
synchronized(buddies) {
buddies.remove(Integer.valueOf(characterId)); buddies.remove(Integer.valueOf(characterId));
} }
}
public Collection<BuddylistEntry> getBuddies() { public Collection<BuddylistEntry> getBuddies() {
return buddies.values(); synchronized(buddies) {
return Collections.unmodifiableCollection(buddies.values());
}
} }
public boolean isFull() { public boolean isFull() {
synchronized(buddies) {
return buddies.size() >= capacity; return buddies.size() >= capacity;
} }
}
public int[] getBuddyIds() { public int[] getBuddyIds() {
synchronized(buddies) {
int buddyIds[] = new int[buddies.size()]; int buddyIds[] = new int[buddies.size()];
int i = 0; int i = 0;
for (BuddylistEntry ble : buddies.values()) { for (BuddylistEntry ble : buddies.values()) {
@@ -107,6 +128,17 @@ public class BuddyList {
} }
return buddyIds; 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);
}
}
}
public void loadFromDb(int characterId) { public void loadFromDb(int characterId) {
try { try {
+30 -5
View File
@@ -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 expRate = 1, mesoRate = 1, dropRate = 1, expCoupon = 1, mesoCoupon = 1, dropCoupon = 1;
private int omokwins, omokties, omoklosses, matchcardwins, matchcardties, matchcardlosses; private int omokwins, omokties, omoklosses, matchcardwins, matchcardties, matchcardlosses;
private int owlSearch; private int owlSearch;
private int married;
private long lastfametime, lastUsedCashItem, lastHealed, lastMesoDrop = -1, jailExpiration = -1; private long lastfametime, lastUsedCashItem, lastHealed, lastMesoDrop = -1, jailExpiration = -1;
private transient int localmaxhp, localmaxmp, localstr, localdex, localluk, localint_, magic, watk; private transient int localmaxhp, localmaxmp, localstr, localdex, localluk, localint_, magic, watk;
private boolean hidden, canDoor = true, berserk, hasMerchant, whiteChat = false; private boolean hidden, canDoor = true, berserk, hasMerchant, whiteChat = false;
@@ -1093,6 +1092,36 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
createDragon(); 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) { public void changeKeybinding(int key, MapleKeyBinding keybinding) {
@@ -3955,10 +3984,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return marriageRing; return marriageRing;
} }
public int getMarried() {
return married;
}
public int getMasterLevel(Skill skill) { public int getMasterLevel(Skill skill) {
if (skills.get(skill) == null) { if (skills.get(skill) == null) {
return 0; return 0;
+164 -118
View File
@@ -402,90 +402,14 @@ public class Commands {
} }
break; 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 i = 0; i < 2; i++){
for (int id : gacha.getItems(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."; 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, output, "00 00", (byte) 0)); c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, talkStr, "00 00", (byte) 0));
break;
case "whatdropsfrom":
if (sub.length < 2) {
player.dropMessage(5, "Please do @whatdropsfrom <monster name>");
break;
}
String monsterName = joinStringFrom(sub, 1);
output = "";
int limit = 3;
Iterator<Pair<Integer, String>> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
for (int i = 0; i < limit; i++) {
if(listIterator.hasNext()) {
Pair<Integer, String> 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 <item name>");
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<Integer, String> 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; break;
case "dispose": case "dispose":
@@ -560,7 +484,7 @@ public class Commands {
player.dropMessage(5, tips[Randomizer.nextInt(tips.length)]); player.dropMessage(5, tips[Randomizer.nextInt(tips.length)]);
break; break;
case "bug": case "reportbug":
if (sub.length < 2) { if (sub.length < 2) {
player.dropMessage(5, "Message too short and not sent. Please do @bug <bug>"); player.dropMessage(5, "Message too short and not sent. Please do @bug <bug>");
@@ -636,30 +560,6 @@ public class Commands {
} }
break; 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": case "ranks":
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@@ -692,6 +592,47 @@ public class Commands {
} }
break; 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: default:
return false; return false;
} }
@@ -703,7 +644,112 @@ public class Commands {
MapleCharacter player = c.getPlayer(); 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 <monster name>");
break;
}
String monsterName = joinStringFrom(sub, 1);
String output = "";
int limit = 3;
Iterator<Pair<Integer, String>> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
for (int i = 0; i < limit; i++) {
if(listIterator.hasNext()) {
Pair<Integer, String> 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 <item name>");
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<Integer, String> 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": 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 //GM Skills : Haste(Super) - Holy Symbol - Bless - Hyper Body - Echo of Hero
SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player); SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player); SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player);
@@ -754,6 +800,19 @@ public class Commands {
player.dropMessage(5, "USE Recharged."); player.dropMessage(5, "USE Recharged.");
break; 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": case "whereami":
player.yellowMessage("Map ID: " + player.getMap().getId()); player.yellowMessage("Map ID: " + player.getMap().getId());
player.yellowMessage("Players on this map:"); player.yellowMessage("Players on this map:");
@@ -779,19 +838,6 @@ public class Commands {
} }
break; 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 "hide": case "hide":
SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player); SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player);
break; break;
+32 -9
View File
@@ -62,28 +62,38 @@ public class GameConstants {
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000, 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}; 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) { public static int getJobBranch(MapleJob job) {
if(job.getId() % 1000 == 0) { // beginner int jobid = job.getId();
return 10;
} else if(job.getId() % 100 == 0) { // 1st job
return 30;
if(jobid % 1000 == 0) {
return 0;
} else if(jobid % 100 == 0) {
return 1;
} else { } else {
int jobBranch = job.getId() % 10; return 2 + (jobid % 10);
}
}
public static int getJobMaxLevel(MapleJob job) {
int jobBranch = getJobBranch(job);
switch(jobBranch) { switch(jobBranch) {
case 0: case 0:
return 70; // 2nd job return 10; // beginner
case 1: case 1:
return 30; // 1st job
case 2:
return 70; // 2nd job
case 3:
return 120; // 3rd job return 120; // 3rd job
default: default:
return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200 return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
} }
} }
}
public static int getHiddenSkill(final int skill) { public static int getHiddenSkill(final int skill) {
switch (skill) { switch (skill) {
@@ -225,4 +235,17 @@ public class GameConstants {
} }
return mobHpVal[level]; 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];
}
}
} }
+4
View File
@@ -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_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. 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 //Server Rates And Experience
public static final int EXP_RATE = 10; public static final int EXP_RATE = 10;
public static final int MESO_RATE = 10; public static final int MESO_RATE = 10;
@@ -32,6 +32,14 @@ import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
public final class GeneralChatHandler extends net.AbstractMaplePacketHandler { 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 @Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
String s = slea.readMapleAsciiString(); String s = slea.readMapleAsciiString();
@@ -47,7 +55,7 @@ public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
return; return;
} }
char heading = s.charAt(0); char heading = s.charAt(0);
if (heading == '!' || heading == '@') { if (isCommandIssue(heading, chr)) {
String[] sp = s.split(" "); String[] sp = s.split(" ");
sp[0] = sp[0].toLowerCase().substring(1); sp[0] = sp[0].toLowerCase().substring(1);
@@ -44,16 +44,22 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
if (slea.available() >= 4) { if (slea.available() >= 4) {
slea.readInt(); slea.readInt();
} }
if(quest.canStart(player, npc)) {
quest.start(player, npc); quest.start(player, npc);
}
} else if (action == 2) { // Complete Quest } else if (action == 2) { // Complete Quest
int npc = slea.readInt(); int npc = slea.readInt();
slea.readInt(); slea.readInt();
if(quest.canComplete(player, npc)) {
if (slea.available() >= 2) { if (slea.available() >= 2) {
int selection = slea.readShort(); int selection = slea.readShort();
quest.complete(player, npc, selection); quest.complete(player, npc, selection);
} else { } else {
quest.complete(player, npc); quest.complete(player, npc);
} }
}
} else if (action == 3) {// forfeit quest } else if (action == 3) {// forfeit quest
quest.forfeit(player); quest.forfeit(player);
} else if (action == 4) { // scripted start quest } else if (action == 4) { // scripted start quest
+2 -14
View File
@@ -34,6 +34,7 @@ import javax.script.Invocable;
import javax.script.ScriptException; import javax.script.ScriptException;
import constants.ServerConstants; import constants.ServerConstants;
import constants.GameConstants;
import client.MapleCharacter; import client.MapleCharacter;
import net.server.Server; import net.server.Server;
import net.server.world.World; import net.server.world.World;
@@ -499,19 +500,6 @@ public class EventManager {
return(MapleLifeFactory.getMonster(mid)); 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) { private void exportReadyGuild(Integer guildId) {
MapleGuild mg = server.getGuild(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() 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) { private void exportMovedQueueToGuild(Integer guildId, int place) {
MapleGuild mg = server.getGuild(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() 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); mg.dropMessage(6, callout);
} }
+2 -1
View File
@@ -61,7 +61,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm); qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c); Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) { 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) { if (iv == null || QuestScriptManager.getInstance() == null) {
qm.dispose(); qm.dispose();
@@ -112,6 +112,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm); qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c); Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) { if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.\r\n");
qm.dispose(); qm.dispose();
return; return;
} }
+1 -2
View File
@@ -535,8 +535,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
} }
}, getAnimationTime("die1")); }, getAnimationTime("die1"));
} }
} } else { // is this even necessary?
else { // is this even necessary?
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName()); System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
} }
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="MapleCashDropFetcher" default="default" basedir=".">
<description>Builds, tests, and runs the project MapleCashDropFetcher.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="MapleCashDropFetcher-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>
@@ -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
+3
View File
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
build.xml.data.CRC32=928d5bb0
build.xml.script.CRC32=27a7b03c
build.xml.stylesheet.CRC32=[email protected]
# 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=[email protected]
@@ -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
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>MapleCashDropFetcher</name>
<explicit-platform explicit-source-supported="true"/>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>
@@ -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 <http://www.gnu.org/licenses/>.
*/
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<Integer> nxItems = new HashSet<>();
static Set<Integer> 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<File> 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<Pair<Integer, Integer>> getNxDropsEntries(boolean dropdata) throws SQLException {
List<Pair<Integer, Integer>> entries = new ArrayList<>();
List<Integer> 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<Pair<Integer, Integer>> nxEntries = getNxDropsEntries(dropdata);
printWriter.println("NX DROPS ON " + getDropTableName(dropdata));
for(Pair<Integer, Integer> 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<File> 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();
}
}
@@ -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<Connection> 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<Connection> {
@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;
}
}
}
}
@@ -0,0 +1,121 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
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 <http://www.gnu.org/licenses/>.
*/
package tools;
/**
* Represents a pair of values.
*
* @author Frz
* @since Revision 333
* @version 1.0
*
* @param <E> The type of the left value.
* @param <F> The type of the right value.
*/
public class Pair<E, F> {
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;
}
}
@@ -2,8 +2,6 @@
<project-private xmlns="http://www.netbeans.org/ns/project-private/1"> <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group> <group/>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java</file>
</group>
</open-files> </open-files>
</project-private> </project-private>
Binary file not shown.
+150 -303
View File
@@ -2,33 +2,28 @@
# Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls. # Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls.
INCORRECT QUESTIDS ON DB INCORRECT QUESTIDS ON DB
4001342 : 7777 -> 28175 2022055 : -1 -> 9330 EXPIRED
2022056 : -1 -> 9330 EXPIRED
4001352 : 28205 -> 28206
4001366 : 28194 -> 28195
4001367 : 28257 -> 28262 4001367 : 28257 -> 28262
4001368 : 28258 -> 28262 4001368 : 28258 -> 28262
4001369 : 28259 -> 28262 4001369 : 28259 -> 28262
4001370 : 28260 -> 28262 4001370 : 28260 -> 28262
4001371 : 28261 -> 28262 4001371 : 28261 -> 28262
4001372 : 28344 -> 28282
4031107 : -1 -> 3409
4031116 : -1 -> 3419
4031130 : 0 -> 3238 4031130 : 0 -> 3238
4031164 : 0 -> 2084 4031164 : 0 -> 2084
4031171 : 0 -> 7101
4031172 : 7103 -> 7106
4031189 : 0 -> 3448 4031189 : 0 -> 3448
4031218 : 0 -> 3071 4031218 : 0 -> 3071
4031223 : 3607 -> 3608 4031223 : 3607 -> 3608
4031343 : 6904 -> 6905 4031405 : 0 -> 4207 EXPIRED
4031344 : 6904 -> 6905
4031405 : 0 -> 4207
4031511 : 6904 -> 6914 4031511 : 6904 -> 6914
4031512 : 6914 -> 6915
4031514 : 6924 -> 6925
4031515 : 6924 -> 6925
4031517 : 6934 -> 6935
4031518 : 6934 -> 6935
4031856 : 0 -> 2191 4031856 : 0 -> 2191
4031857 : 0 -> 2192 4031857 : 0 -> 2192
4031860 : 6944 -> 6945 4032319 : -1 -> 21723
4031861 : 6944 -> 6945
4031871 : 6350 -> 28344
4032324 : 21736 -> 21737 4032324 : 21736 -> 21737
4032339 : 0 -> 21303 4032339 : 0 -> 21303
@@ -38,283 +33,195 @@ INCORRECT QUESTIDS ON DB
ITEMS WITH NO QUEST DROP DATA ON DB ITEMS WITH NO QUEST DROP DATA ON DB
1002436 - 2075
1102057 - 7103
1102061 - 3066
1302014 - 2048 1302014 - 2048
2022053 - 9330 2022053 - 9330 EXPIRED
2022054 - 9330 2022054 - 9330 EXPIRED
2022055 - 9330 2022057 - 9332 EXPIRED
2022056 - 9330 3994139 - 10360 EXPIRED
2022057 - 9332 4000142 - 1018
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
4001353 - 28227 4001353 - 28227
4001366 - 28195
4031014 - 2020 4031014 - 2020
4031015 - 2022 4031015 - 2020
4031019 - 9411
4031020 - 2050 4031020 - 2050
4031025 - 2052
4031026 - 2053
4031028 - 2054
4031032 - 2051 4031032 - 2051
4031039 - 2055 4031039 - 2055
4031040 - 2056 4031040 - 2056
4031041 - 2057 4031041 - 2057
4031042 - 2035 4031042 - 2035
4031063 - 9260 4031063 - 9260 EXPIRED
4031064 - 8012 4031064 - 8012
4031107 - 3409
4031116 - 3419
4031117 - 3421 4031117 - 3421
4031122 - 9340 4031122 - 9340 EXPIRED
4031124 - 9340 4031124 - 9340 EXPIRED
4031134 - 3443
4031136 - 3439
4031141 - 3407
4031142 - 3407
4031143 - 3407
4031144 - 2047 4031144 - 2047
4031150 - 2067 4031167 - 9052 EXPIRED
4031157 - 2074 4031168 - 9055 EXPIRED
4031158 - 2074 4031169 - 9058 EXPIRED
4031165 - 2086
4031167 - 9052
4031168 - 9055
4031169 - 9058
4031180 - 8020 4031180 - 8020
4031181 - 9140 4031181 - 9140 EXPIRED
4031182 - 9140 4031182 - 9140 EXPIRED
4031183 - 9140 4031183 - 9140 EXPIRED
4031184 - 9150 4031184 - 9150 EXPIRED
4031185 - 9150 4031185 - 9150 EXPIRED
4031186 - 9150 4031186 - 9150 EXPIRED
4031190 - 3054 4031190 - 3055
4031191 - 3063 4031191 - 3063
4031192 - 8700 4031192 - 8700 EXPIRED
4031198 - 3043 4031199 - 3045
4031199 - 3046
4031200 - 3069
4031201 - 3048 4031201 - 3048
4031202 - 3050 4031202 - 3050
4031207 - 3443 4031207 - 3443
4031220 - 9210 4031220 - 9210 EXPIRED
4031225 - 3606 4031226 - 9321 EXPIRED
4031226 - 9321
4031227 - 4103 EXPIRED 4031227 - 4103 EXPIRED
4031230 - 3619 4031230 - 3619
4031231 - 3620 4031235 - 3615
4031235 - 3607
4031236 - 3616 4031236 - 3616
4031237 - 3605 4031237 - 3617
4031238 - 3611 4031238 - 3618
4031243 - 3443 4031243 - 3443
4031257 - 9350 4031257 - 9350 EXPIRED
4031258 - 9351 4031270 - 3630
4031270 - 3629 4031271 - 9351 EXPIRED
4031271 - 9351 4031272 - 9352 EXPIRED
4031272 - 9352 4031280 - 3633
4031274 - 3083 4031290 - 4104 EXPIRED
4031275 - 3083 4031291 - 4006 EXPIRED
4031276 - 3083 4031292 - 4006 EXPIRED
4031277 - 3083 4031293 - 4006 EXPIRED
4031278 - 3083 4031296 - 4010 EXPIRED
4031280 - 3632 4031297 - 9386 EXPIRED
4031290 - 4106 4031298 - 3639
4031291 - 4006 4031301 - 9391 EXPIRED
4031292 - 4009 4031302 - 9503 EXPIRED
4031293 - 4010 4031303 - 4007 EXPIRED
4031296 - 4010 4031304 - 9392 EXPIRED
4031297 - 9386 4031321 - 9504 EXPIRED
4031298 - 3636 4031352 - 4005 EXPIRED
4031301 - 9391 4031354 - 4013 EXPIRED
4031302 - 9503 4031388 - 4218 EXPIRED
4031303 - 4008 4031418 - 8823 EXPIRED
4031304 - 9392 4031419 - 8823 EXPIRED
4031321 - 9504 4031420 - 8823 EXPIRED
4031352 - 4005 4031421 - 8823 EXPIRED
4031354 - 4013
4031388 - 4218
4031418 - 8823
4031419 - 8823
4031420 - 8823
4031421 - 8823
4031425 - 8822
4031448 - 6134 4031448 - 6134
4031450 - 6263
4031452 - 6201
4031454 - 6281
4031455 - 6280 4031455 - 6280
4031456 - 6230 4031456 - 6230
4031462 - 6210 4031462 - 6210
4031468 - 6222 4031468 - 6222
4031471 - 6153
4031478 - 6210 4031478 - 6210
4031488 - 6312 4031488 - 6312
4031495 - 6192 4031504 - 9640 EXPIRED
4031504 - 9640 4031505 - 9641 EXPIRED
4031505 - 9641 4031506 - 9642 EXPIRED
4031506 - 9642
4031507 - 6002
4031508 - 6002
4031554 - 3821 4031554 - 3821
4031557 - 9710 4031557 - 9710 EXPIRED
4031558 - 9711 4031558 - 9711 EXPIRED
4031559 - 9712 4031559 - 9712 EXPIRED
4031560 - 9713 4031560 - 9713 EXPIRED
4031561 - 9714 4031561 - 9714 EXPIRED
4031563 - 8850 4031563 - 8855
4031564 - 8851 4031564 - 8856
4031565 - 8852 4031565 - 8857
4031566 - 8853 4031566 - 8858
4031567 - 8854 4031567 - 8859
4031568 - 3911 4031570 - 3938
4031570 - 3939 4031571 - 3940
4031571 - 3941
4031574 - 3935
4031578 - 3923 4031578 - 3923
4031581 - 3937 4031582 - 3949
4031582 - 3901 4031584 - 9731 EXPIRED
4031584 - 9731 4031585 - 9732 EXPIRED
4031585 - 9732 4031586 - 9740 EXPIRED
4031586 - 9740 4031587 - 9741 EXPIRED
4031587 - 9741 4031588 - 9742 EXPIRED
4031588 - 9742 4031590 - 8881 EXPIRED
4031590 - 8881 4031608 - 9803 EXPIRED
4031608 - 9803 4031611 - 9804 EXPIRED
4031611 - 9804 4031612 - 9805 EXPIRED
4031612 - 9805
4031625 - 9820 4031625 - 9820
4031661 - 9861 4031661 - 9861 EXPIRED
4031662 - 9866 4031662 - 9866 EXPIRED
4031667 - 9863 4031667 - 9863 EXPIRED
4031683 - 1115
4031684 - 1116
4031685 - 1117
4031686 - 1118
4031687 - 1119
4031688 - 1120
4031689 - 1121
4031690 - 1122
4031691 - 1123
4031692 - 1124
4031695 - 3335
4031696 - 3334 4031696 - 3334
4031697 - 3322 4031697 - 3322
4031703 - 3302
4031708 - 3309 4031708 - 3309
4031709 - 3310 4031764 - 4949 EXPIRED
4031737 - 3343 4031766 - 4959 EXPIRED
4031764 - 4949 4031767 - 4947 EXPIRED
4031766 - 4959 4031769 - 4946 EXPIRED
4031767 - 4947 4031770 - 4946 EXPIRED
4031768 - 4953
4031769 - 4946
4031770 - 4946
4031771 - 4944
4031772 - 4942 4031772 - 4942
4031774 - 3361 4031774 - 3361
4031785 - 3376 4031785 - 3376
4031789 - 3844
4031796 - 3362 4031796 - 3362
4031797 - 3367 4031797 - 3367
4031798 - 3366 4031806 - 3379
4031801 - 1040 4031812 - 4950 EXPIRED
4031806 - 3380 4031837 - 9942 EXPIRED
4031812 - 4950
4031833 - 9946
4031837 - 9945
4031839 - 2162 4031839 - 2162
4031881 - 4484 4031850 - 2180
4031894 - 2214 4031881 - 4484 EXPIRED
4031921 - 4646 4031921 - 4646
4031927 - 3454 4032037 - 9154 EXPIRED
4031928 - 3454 4032038 - 9154 EXPIRED
4031945 - 9987 4032039 - 9154 EXPIRED
4032037 - 9154 4032087 - 10081 EXPIRED
4032038 - 9154 4032119 - 28109 EXPIRED
4032039 - 9154
4032055 - 4675
4032087 - 10081
4032092 - 28003
4032119 - 28109
4032136 - 20710 4032136 - 20710
4032138 - 20713 4032138 - 20712
4032142 - 20716 4032142 - 20716
4032143 - 20717
4032196 - 20528 4032196 - 20528
4032197 - 20528 4032197 - 20528
4032198 - 20528 4032198 - 20528
4032233 - 8298 4032233 - 8298 EXPIRED
4032234 - 8299 4032234 - 8299 EXPIRED
4032235 - 8299 4032235 - 8299 EXPIRED
4032236 - 8299 4032236 - 8299 EXPIRED
4032237 - 8299 4032237 - 8299 EXPIRED
4032238 - 8299 4032238 - 8299 EXPIRED
4032239 - 8299 4032239 - 8298 EXPIRED
4032247 - 28103 4032248 - 28108 EXPIRED
4032248 - 28108 4032264 - 10240 EXPIRED
4032264 - 10240 4032265 - 10241 EXPIRED
4032265 - 10241 4032266 - 10240 EXPIRED
4032266 - 10240 4032270 - 10241 EXPIRED
4032270 - 10241 4032271 - 10260 EXPIRED
4032271 - 10260 4032272 - 10268 EXPIRED
4032272 - 10268 4032273 - 10268 EXPIRED
4032273 - 10268 4032275 - 10261 EXPIRED
4032275 - 10261 4032276 - 10262 EXPIRED
4032276 - 10262 4032277 - 10263 EXPIRED
4032277 - 10263 4032278 - 10270 EXPIRED
4032278 - 10270 4032279 - 10271 EXPIRED
4032279 - 10271 4032280 - 10272 EXPIRED
4032280 - 10272 4032281 - 10270 EXPIRED
4032281 - 10270 4032282 - 10271 EXPIRED
4032282 - 10271 4032283 - 10272 EXPIRED
4032283 - 10272 4032284 - 10264 EXPIRED
4032284 - 10264 4032285 - 10265 EXPIRED
4032285 - 10265 4032286 - 10266 EXPIRED
4032286 - 10266 4032287 - 10267 EXPIRED
4032287 - 10267 4032306 - 28120 EXPIRED
4032307 - 28121 4032307 - 28121 EXPIRED
4032308 - 28122 4032308 - 28122 EXPIRED
4032317 - 21717 4032325 - 21751
4032318 - 21718
4032319 - 21723
4032321 - 21727
4032325 - 21752
4032326 - 21752 4032326 - 21752
4032331 - 21601 4032331 - 21601
4032333 - 21608 4032333 - 21608
4032335 - 21617 4032348 - 10300 EXPIRED
4032342 - 21743 4032349 - 10301 EXPIRED
4032348 - 10300 4032350 - 10302 EXPIRED
4032349 - 10301
4032350 - 10302
4032374 - 2405
4032376 - 2406
4032377 - 2407
4032378 - 2408
4032379 - 2409
4032401 - 2261 4032401 - 2261
4032402 - 2263 4032402 - 2263
4032404 - 28128 4032404 - 28128 EXPIRED
4032423 - 21767 4032423 - 21767
4032435 - 28307 4032435 - 28307 EXPIRED
4032436 - 28314 4032436 - 28314 EXPIRED
4032437 - 28321 4032437 - 28321 EXPIRED
4032443 - 28317 4161000 - 9322 EXPIRED
4032496 - 28238
4032512 - 3720
4161000 - 9322
@@ -322,87 +229,27 @@ ITEMS WITH NO QUEST DROP DATA ON DB
COMPLETE QUEST ITEMS WITH ZERO QUANTITY 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: 8142:
4000300 4000300
4000301 4000301
8218: 8218 EXPIRED:
4031664 4031664
4031665 4031665
4031666 4031666
8886: 8886 EXPIRED:
4031659 4031659
8887: 8887 EXPIRED:
4031658 4031658
8888: 8888 EXPIRED:
4031660 4031660
10430:
4220152
28104: 28104:
4032247 4032247
28120:
4032306
@@ -72,7 +72,6 @@ public class MapleQuestItemFetcher {
static String password = ""; static String password = "";
static String wzPath = "../../wz"; static String wzPath = "../../wz";
static String fileName = "../../wz/Quest.wz/Act.img.xml";
static String directoryName = "../.."; static String directoryName = "../..";
static String newFile = "lib/QuestReport.txt"; static String newFile = "lib/QuestReport.txt";
@@ -134,6 +133,28 @@ public class MapleQuestItemFetcher {
return(d.trim()); 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) { private static void inspectQuestItemList(int st) {
String line = null; String line = null;
@@ -152,6 +173,7 @@ public class MapleQuestItemFetcher {
if(ii.isQuestItem(currentItemid)) { if(ii.isQuestItem(currentItemid)) {
if(currentCount != 0) { if(currentCount != 0) {
if(isCompleteState == 1) { if(isCompleteState == 1) {
if(currentCount < 0) {
Set<Integer> qi = completeQuestItems.get(questId); Set<Integer> qi = completeQuestItems.get(questId);
if(qi == null) { if(qi == null) {
Set<Integer> newSet = new HashSet<>(); Set<Integer> newSet = new HashSet<>();
@@ -161,7 +183,9 @@ public class MapleQuestItemFetcher {
} else { } else {
qi.add(currentItemid); qi.add(currentItemid);
} }
}
} else { } else {
if(currentCount > 0) {
Set<Integer> qi = startQuestItems.get(questId); Set<Integer> qi = startQuestItems.get(questId);
if(qi == null) { if(qi == null) {
Set<Integer> newSet = new HashSet<>(); Set<Integer> newSet = new HashSet<>();
@@ -172,6 +196,7 @@ public class MapleQuestItemFetcher {
qi.add(currentItemid); qi.add(currentItemid);
} }
} }
}
} else { } else {
if(isCompleteState == 1) { if(isCompleteState == 1) {
Set<Integer> qi = zeroedCompleteQuestItems.get(questId); Set<Integer> qi = zeroedCompleteQuestItems.get(questId);
@@ -222,7 +247,7 @@ public class MapleQuestItemFetcher {
} }
} }
private static void translateToken(String token) { private static void translateActToken(String token) {
String d; String d;
int temp; int temp;
@@ -244,6 +269,8 @@ public class MapleQuestItemFetcher {
if(d.contains("item")) { if(d.contains("item")) {
temp = status; temp = status;
inspectQuestItemList(temp); inspectQuestItemList(temp);
} else {
forwardCursor(status);
} }
} }
@@ -259,6 +286,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() { private static void calculateQuestItemDiff() {
// This will remove started quest items from the "to complete" item set. // This will remove started quest items from the "to complete" item set.
@@ -289,11 +347,12 @@ public class MapleQuestItemFetcher {
return list; return list;
} }
private static void filterQuestDropsOnDB(List<Pair<Integer, Integer>> itemsWithQuest) throws SQLException { private static String getTableName(boolean dropdata) {
List<Pair<Integer, Integer>> copyItemsWithQuest = new ArrayList<>(itemsWithQuest); return dropdata ? "drop_data" : "reactordrops";
try { }
for(Pair<Integer, Integer> iq : copyItemsWithQuest) {
PreparedStatement ps = con.prepareStatement("SELECT questid FROM drop_data WHERE itemid = ?;"); private static void filterQuestDropsOnTable(Pair<Integer, Integer> iq, List<Pair<Integer, Integer>> itemsWithQuest, boolean dropdata) throws SQLException {
PreparedStatement ps = con.prepareStatement("SELECT questid FROM " + getTableName(dropdata) + " WHERE itemid = ?;");
ps.setInt(1, iq.getLeft()); ps.setInt(1, iq.getLeft());
ResultSet rs = ps.executeQuery(); ResultSet rs = ps.executeQuery();
@@ -301,6 +360,11 @@ public class MapleQuestItemFetcher {
while(rs.next()) { while(rs.next()) {
int curQuest = rs.getInt(1); int curQuest = rs.getInt(1);
if(curQuest != iq.getRight()) { if(curQuest != iq.getRight()) {
Set<Integer> sqSet = startQuestItems.get(curQuest);
if(sqSet != null && sqSet.contains(iq.getLeft())) {
continue;
}
int[] mixed = new int[3]; int[] mixed = new int[3];
mixed[0] = iq.getLeft(); mixed[0] = iq.getLeft();
mixed[1] = curQuest; mixed[1] = curQuest;
@@ -316,6 +380,14 @@ public class MapleQuestItemFetcher {
rs.close(); rs.close();
ps.close(); ps.close();
} }
private static void filterQuestDropsOnDB(List<Pair<Integer, Integer>> itemsWithQuest) throws SQLException {
List<Pair<Integer, Integer>> copyItemsWithQuest = new ArrayList<>(itemsWithQuest);
try {
for(Pair<Integer, Integer> iq : copyItemsWithQuest) {
filterQuestDropsOnTable(iq, itemsWithQuest, true);
filterQuestDropsOnTable(iq, itemsWithQuest, false);
}
} }
catch(SQLException e) { catch(SQLException e) {
e.printStackTrace(); e.printStackTrace();
@@ -431,17 +503,30 @@ public class MapleQuestItemFetcher {
private static void ReportQuestItemData() { private static void ReportQuestItemData() {
// This will reference one line at a time // This will reference one line at a time
String line = null; String line = null;
String fileName = null;
try { try {
Class.forName(driver).newInstance(); Class.forName(driver).newInstance();
System.out.println("Reading WZs..."); System.out.println("Reading WZs...");
fileName = wzPath + "/Quest.wz/Check.img.xml";
fileReader = new InputStreamReader(new FileInputStream(fileName), "UTF-8"); fileReader = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
bufferedReader = new BufferedReader(fileReader); bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) { 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(); bufferedReader.close();
+1 -6
View File
@@ -22139,12 +22139,7 @@
</imgdir> </imgdir>
<imgdir name="1"> <imgdir name="1">
<int name="npc" value="1061019"/> <int name="npc" value="1061019"/>
<int name="infoNumber" value="21761"/> <string name="endscript" value="q21728e"/>
<imgdir name="infoex">
<imgdir name="0">
<string name="value" value="0"/>
</imgdir>
</imgdir>
</imgdir> </imgdir>
</imgdir> </imgdir>
<imgdir name="21729"> <imgdir name="21729">
File diff suppressed because it is too large Load Diff