diff --git a/build/built-jar.properties b/build/built-jar.properties
index e17a2decfc..0fd3e3f6f0 100644
--- a/build/built-jar.properties
+++ b/build/built-jar.properties
@@ -1,4 +1,4 @@
-#Fri, 03 Nov 2017 14:56:01 -0200
+#Mon, 06 Nov 2017 23:43:28 -0200
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
diff --git a/build/classes/client/MapleBuffStat.class b/build/classes/client/MapleBuffStat.class
index e45da74220..9972dc6f57 100644
Binary files a/build/classes/client/MapleBuffStat.class and b/build/classes/client/MapleBuffStat.class differ
diff --git a/build/classes/client/MapleCharacter$12.class b/build/classes/client/MapleCharacter$12.class
index 50664fb8c9..ca5484a936 100644
Binary files a/build/classes/client/MapleCharacter$12.class and b/build/classes/client/MapleCharacter$12.class differ
diff --git a/build/classes/client/MapleCharacter$13.class b/build/classes/client/MapleCharacter$13.class
index f77c87cfc3..0ae47bcb48 100644
Binary files a/build/classes/client/MapleCharacter$13.class and b/build/classes/client/MapleCharacter$13.class differ
diff --git a/build/classes/client/MapleCharacter$14.class b/build/classes/client/MapleCharacter$14.class
index 30e9380844..1759f96a13 100644
Binary files a/build/classes/client/MapleCharacter$14.class and b/build/classes/client/MapleCharacter$14.class differ
diff --git a/build/classes/client/MapleCharacter$15.class b/build/classes/client/MapleCharacter$15.class
index aa84d348ef..e7b3795628 100644
Binary files a/build/classes/client/MapleCharacter$15.class and b/build/classes/client/MapleCharacter$15.class differ
diff --git a/build/classes/client/MapleCharacter$16.class b/build/classes/client/MapleCharacter$16.class
index f663b38dd9..e1e49f98e7 100644
Binary files a/build/classes/client/MapleCharacter$16.class and b/build/classes/client/MapleCharacter$16.class differ
diff --git a/build/classes/client/MapleCharacter$17.class b/build/classes/client/MapleCharacter$17.class
index 1cc80b6723..535321a81f 100644
Binary files a/build/classes/client/MapleCharacter$17.class and b/build/classes/client/MapleCharacter$17.class differ
diff --git a/build/classes/client/MapleCharacter$18.class b/build/classes/client/MapleCharacter$18.class
index a7eaf47da6..ce1d0d8ac6 100644
Binary files a/build/classes/client/MapleCharacter$18.class and b/build/classes/client/MapleCharacter$18.class differ
diff --git a/build/classes/client/MapleCharacter$19.class b/build/classes/client/MapleCharacter$19.class
index cb87eb1649..77750ec6f6 100644
Binary files a/build/classes/client/MapleCharacter$19.class and b/build/classes/client/MapleCharacter$19.class differ
diff --git a/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class b/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class
index b9fca1d6f8..cc4888866c 100644
Binary files a/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class and b/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class differ
diff --git a/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class b/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class
index 4ff5af6d31..09c42f3cc7 100644
Binary files a/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class and b/build/classes/client/MapleCharacter$MapleCoolDownValueHolder.class differ
diff --git a/build/classes/client/MapleCharacter$SkillEntry.class b/build/classes/client/MapleCharacter$SkillEntry.class
index 0f17d33bfd..a0ba23d3fe 100644
Binary files a/build/classes/client/MapleCharacter$SkillEntry.class and b/build/classes/client/MapleCharacter$SkillEntry.class differ
diff --git a/build/classes/client/MapleCharacter.class b/build/classes/client/MapleCharacter.class
index 3b488be5f9..fa2240e3ab 100644
Binary files a/build/classes/client/MapleCharacter.class and b/build/classes/client/MapleCharacter.class differ
diff --git a/build/classes/client/command/Commands.class b/build/classes/client/command/Commands.class
index 26c329a4f6..dba6164182 100644
Binary files a/build/classes/client/command/Commands.class and b/build/classes/client/command/Commands.class differ
diff --git a/build/classes/constants/GameConstants$1.class b/build/classes/constants/GameConstants$1.class
index e366eef883..73fc52ad75 100644
Binary files a/build/classes/constants/GameConstants$1.class and b/build/classes/constants/GameConstants$1.class differ
diff --git a/build/classes/constants/GameConstants.class b/build/classes/constants/GameConstants.class
index b89ad9a319..775f2d3cb8 100644
Binary files a/build/classes/constants/GameConstants.class and b/build/classes/constants/GameConstants.class differ
diff --git a/build/classes/constants/ServerConstants.class b/build/classes/constants/ServerConstants.class
index 39b529d9b4..89511e2b55 100644
Binary files a/build/classes/constants/ServerConstants.class and b/build/classes/constants/ServerConstants.class differ
diff --git a/build/classes/net/server/channel/handlers/CancelBuffHandler.class b/build/classes/net/server/channel/handlers/CancelBuffHandler.class
index 1c8401081b..00336cf120 100644
Binary files a/build/classes/net/server/channel/handlers/CancelBuffHandler.class and b/build/classes/net/server/channel/handlers/CancelBuffHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class b/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class
index 27898bdb4f..5927ee3806 100644
Binary files a/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class and b/build/classes/net/server/channel/handlers/CloseRangeDamageHandler.class differ
diff --git a/build/classes/net/server/channel/handlers/RangedAttackHandler.class b/build/classes/net/server/channel/handlers/RangedAttackHandler.class
index 2a33769d85..05de455d04 100644
Binary files a/build/classes/net/server/channel/handlers/RangedAttackHandler.class and b/build/classes/net/server/channel/handlers/RangedAttackHandler.class differ
diff --git a/build/classes/scripting/event/EventInstanceManager$1.class b/build/classes/scripting/event/EventInstanceManager$1.class
index 13a5b0a21e..385e3b614f 100644
Binary files a/build/classes/scripting/event/EventInstanceManager$1.class and b/build/classes/scripting/event/EventInstanceManager$1.class differ
diff --git a/build/classes/scripting/event/EventInstanceManager$2.class b/build/classes/scripting/event/EventInstanceManager$2.class
index 83c24e623e..ebdc110a7a 100644
Binary files a/build/classes/scripting/event/EventInstanceManager$2.class and b/build/classes/scripting/event/EventInstanceManager$2.class differ
diff --git a/build/classes/scripting/event/EventInstanceManager$3.class b/build/classes/scripting/event/EventInstanceManager$3.class
index 8fbd0a5d0e..49f0d86333 100644
Binary files a/build/classes/scripting/event/EventInstanceManager$3.class and b/build/classes/scripting/event/EventInstanceManager$3.class differ
diff --git a/build/classes/scripting/event/EventInstanceManager.class b/build/classes/scripting/event/EventInstanceManager.class
index 5890396b50..a69d3ba181 100644
Binary files a/build/classes/scripting/event/EventInstanceManager.class and b/build/classes/scripting/event/EventInstanceManager.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$1.class b/build/classes/server/MapleItemInformationProvider$1.class
index 78b1e2e6e9..033d7b2e2b 100644
Binary files a/build/classes/server/MapleItemInformationProvider$1.class and b/build/classes/server/MapleItemInformationProvider$1.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$RewardItem.class b/build/classes/server/MapleItemInformationProvider$RewardItem.class
index 14fd492722..80c0edaea0 100644
Binary files a/build/classes/server/MapleItemInformationProvider$RewardItem.class and b/build/classes/server/MapleItemInformationProvider$RewardItem.class differ
diff --git a/build/classes/server/MapleItemInformationProvider$scriptedItem.class b/build/classes/server/MapleItemInformationProvider$scriptedItem.class
index b5ec07c22b..bdd482163c 100644
Binary files a/build/classes/server/MapleItemInformationProvider$scriptedItem.class and b/build/classes/server/MapleItemInformationProvider$scriptedItem.class differ
diff --git a/build/classes/server/MapleItemInformationProvider.class b/build/classes/server/MapleItemInformationProvider.class
index 086e9835df..b85ecfe736 100644
Binary files a/build/classes/server/MapleItemInformationProvider.class and b/build/classes/server/MapleItemInformationProvider.class differ
diff --git a/build/classes/server/MapleStatEffect.class b/build/classes/server/MapleStatEffect.class
index 7fe5b72591..34f620a77e 100644
Binary files a/build/classes/server/MapleStatEffect.class and b/build/classes/server/MapleStatEffect.class differ
diff --git a/build/classes/server/life/MapleMonster$4.class b/build/classes/server/life/MapleMonster$4.class
index ebf19e2fd5..be603fc572 100644
Binary files a/build/classes/server/life/MapleMonster$4.class and b/build/classes/server/life/MapleMonster$4.class differ
diff --git a/build/classes/server/life/MapleMonster$5.class b/build/classes/server/life/MapleMonster$5.class
index e5780de744..61611257fe 100644
Binary files a/build/classes/server/life/MapleMonster$5.class and b/build/classes/server/life/MapleMonster$5.class differ
diff --git a/build/classes/server/life/MapleMonster$DamageTask.class b/build/classes/server/life/MapleMonster$DamageTask.class
index ce3aea590d..3dbab9aa8e 100644
Binary files a/build/classes/server/life/MapleMonster$DamageTask.class and b/build/classes/server/life/MapleMonster$DamageTask.class differ
diff --git a/build/classes/server/life/MapleMonster.class b/build/classes/server/life/MapleMonster.class
index d792d511ca..17928b67d8 100644
Binary files a/build/classes/server/life/MapleMonster.class and b/build/classes/server/life/MapleMonster.class differ
diff --git a/build/classes/server/maps/MapleMap$1.class b/build/classes/server/maps/MapleMap$1.class
index 80658c3088..a3dcefb8ad 100644
Binary files a/build/classes/server/maps/MapleMap$1.class and b/build/classes/server/maps/MapleMap$1.class differ
diff --git a/build/classes/server/maps/MapleMap$10.class b/build/classes/server/maps/MapleMap$10.class
index 0e662c0eeb..549549e076 100644
Binary files a/build/classes/server/maps/MapleMap$10.class and b/build/classes/server/maps/MapleMap$10.class differ
diff --git a/build/classes/server/maps/MapleMap$11.class b/build/classes/server/maps/MapleMap$11.class
index a2a6934e72..2973fc2651 100644
Binary files a/build/classes/server/maps/MapleMap$11.class and b/build/classes/server/maps/MapleMap$11.class differ
diff --git a/build/classes/server/maps/MapleMap$12.class b/build/classes/server/maps/MapleMap$12.class
index 26a2a2ec84..f05aafd2a3 100644
Binary files a/build/classes/server/maps/MapleMap$12.class and b/build/classes/server/maps/MapleMap$12.class differ
diff --git a/build/classes/server/maps/MapleMap$13.class b/build/classes/server/maps/MapleMap$13.class
index 25d851bb08..1aef397c1b 100644
Binary files a/build/classes/server/maps/MapleMap$13.class and b/build/classes/server/maps/MapleMap$13.class differ
diff --git a/build/classes/server/maps/MapleMap$14.class b/build/classes/server/maps/MapleMap$14.class
index 197c016052..3d3f2b190e 100644
Binary files a/build/classes/server/maps/MapleMap$14.class and b/build/classes/server/maps/MapleMap$14.class differ
diff --git a/build/classes/server/maps/MapleMap$15.class b/build/classes/server/maps/MapleMap$15.class
index 65ea3874aa..4f50b571ba 100644
Binary files a/build/classes/server/maps/MapleMap$15.class and b/build/classes/server/maps/MapleMap$15.class differ
diff --git a/build/classes/server/maps/MapleMap$16.class b/build/classes/server/maps/MapleMap$16.class
index 1a1805f00d..0e98d39e15 100644
Binary files a/build/classes/server/maps/MapleMap$16.class and b/build/classes/server/maps/MapleMap$16.class differ
diff --git a/build/classes/server/maps/MapleMap$17.class b/build/classes/server/maps/MapleMap$17.class
index d247221831..5c40cdc9d1 100644
Binary files a/build/classes/server/maps/MapleMap$17.class and b/build/classes/server/maps/MapleMap$17.class differ
diff --git a/build/classes/server/maps/MapleMap$18.class b/build/classes/server/maps/MapleMap$18.class
index cccf2c92e0..099f6b64e7 100644
Binary files a/build/classes/server/maps/MapleMap$18.class and b/build/classes/server/maps/MapleMap$18.class differ
diff --git a/build/classes/server/maps/MapleMap$19.class b/build/classes/server/maps/MapleMap$19.class
index eea1e2bd25..87845fcc58 100644
Binary files a/build/classes/server/maps/MapleMap$19.class and b/build/classes/server/maps/MapleMap$19.class differ
diff --git a/build/classes/server/maps/MapleMap$2.class b/build/classes/server/maps/MapleMap$2.class
index f384bcd8a8..d5ca13bf8d 100644
Binary files a/build/classes/server/maps/MapleMap$2.class and b/build/classes/server/maps/MapleMap$2.class differ
diff --git a/build/classes/server/maps/MapleMap$20.class b/build/classes/server/maps/MapleMap$20.class
index 2b0802c5d8..88cdd18385 100644
Binary files a/build/classes/server/maps/MapleMap$20.class and b/build/classes/server/maps/MapleMap$20.class differ
diff --git a/build/classes/server/maps/MapleMap$21.class b/build/classes/server/maps/MapleMap$21.class
index a925185178..7c329c44de 100644
Binary files a/build/classes/server/maps/MapleMap$21.class and b/build/classes/server/maps/MapleMap$21.class differ
diff --git a/build/classes/server/maps/MapleMap$22.class b/build/classes/server/maps/MapleMap$22.class
index 1695900e18..51c756bb1f 100644
Binary files a/build/classes/server/maps/MapleMap$22.class and b/build/classes/server/maps/MapleMap$22.class differ
diff --git a/build/classes/server/maps/MapleMap$23.class b/build/classes/server/maps/MapleMap$23.class
index 97e7f18578..e4eb0d2f04 100644
Binary files a/build/classes/server/maps/MapleMap$23.class and b/build/classes/server/maps/MapleMap$23.class differ
diff --git a/build/classes/server/maps/MapleMap$24.class b/build/classes/server/maps/MapleMap$24.class
index 2b2172e50a..a5bed8a178 100644
Binary files a/build/classes/server/maps/MapleMap$24.class and b/build/classes/server/maps/MapleMap$24.class differ
diff --git a/build/classes/server/maps/MapleMap$25.class b/build/classes/server/maps/MapleMap$25.class
index ca83a1be82..b28a3fb55e 100644
Binary files a/build/classes/server/maps/MapleMap$25.class and b/build/classes/server/maps/MapleMap$25.class differ
diff --git a/build/classes/server/maps/MapleMap$26.class b/build/classes/server/maps/MapleMap$26.class
index 24c7a991b9..61559d9aec 100644
Binary files a/build/classes/server/maps/MapleMap$26.class and b/build/classes/server/maps/MapleMap$26.class differ
diff --git a/build/classes/server/maps/MapleMap$27.class b/build/classes/server/maps/MapleMap$27.class
index 35d7d3603e..8cfb0e8845 100644
Binary files a/build/classes/server/maps/MapleMap$27.class and b/build/classes/server/maps/MapleMap$27.class differ
diff --git a/build/classes/server/maps/MapleMap$28.class b/build/classes/server/maps/MapleMap$28.class
index 9c729a5dc8..2ab344f6d6 100644
Binary files a/build/classes/server/maps/MapleMap$28.class and b/build/classes/server/maps/MapleMap$28.class differ
diff --git a/build/classes/server/maps/MapleMap$29.class b/build/classes/server/maps/MapleMap$29.class
index eb571c2fff..8335b8fd65 100644
Binary files a/build/classes/server/maps/MapleMap$29.class and b/build/classes/server/maps/MapleMap$29.class differ
diff --git a/build/classes/server/maps/MapleMap$3.class b/build/classes/server/maps/MapleMap$3.class
index ceb2145abd..03c6bf7efc 100644
Binary files a/build/classes/server/maps/MapleMap$3.class and b/build/classes/server/maps/MapleMap$3.class differ
diff --git a/build/classes/server/maps/MapleMap$4.class b/build/classes/server/maps/MapleMap$4.class
index 85f0bb93b6..ac2a92370d 100644
Binary files a/build/classes/server/maps/MapleMap$4.class and b/build/classes/server/maps/MapleMap$4.class differ
diff --git a/build/classes/server/maps/MapleMap$5.class b/build/classes/server/maps/MapleMap$5.class
index 4e49355353..c91963dfc2 100644
Binary files a/build/classes/server/maps/MapleMap$5.class and b/build/classes/server/maps/MapleMap$5.class differ
diff --git a/build/classes/server/maps/MapleMap$6.class b/build/classes/server/maps/MapleMap$6.class
index 6b3f20caf5..ce7ba3bfb9 100644
Binary files a/build/classes/server/maps/MapleMap$6.class and b/build/classes/server/maps/MapleMap$6.class differ
diff --git a/build/classes/server/maps/MapleMap$7.class b/build/classes/server/maps/MapleMap$7.class
index 7a2d56619c..6b793db673 100644
Binary files a/build/classes/server/maps/MapleMap$7.class and b/build/classes/server/maps/MapleMap$7.class differ
diff --git a/build/classes/server/maps/MapleMap$8.class b/build/classes/server/maps/MapleMap$8.class
index ebd2414b39..85fc7058e1 100644
Binary files a/build/classes/server/maps/MapleMap$8.class and b/build/classes/server/maps/MapleMap$8.class differ
diff --git a/build/classes/server/maps/MapleMap$9.class b/build/classes/server/maps/MapleMap$9.class
index 081f44afea..04287732ad 100644
Binary files a/build/classes/server/maps/MapleMap$9.class and b/build/classes/server/maps/MapleMap$9.class differ
diff --git a/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class b/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class
index 63cfc2a0e1..9abcd749c1 100644
Binary files a/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class and b/build/classes/server/maps/MapleMap$ActivateItemReactor$1.class differ
diff --git a/build/classes/server/maps/MapleMap$ActivateItemReactor.class b/build/classes/server/maps/MapleMap$ActivateItemReactor.class
index db9a70d0af..c81a1b44b2 100644
Binary files a/build/classes/server/maps/MapleMap$ActivateItemReactor.class and b/build/classes/server/maps/MapleMap$ActivateItemReactor.class differ
diff --git a/build/classes/server/maps/MapleMap$ExpireMapItemJob.class b/build/classes/server/maps/MapleMap$ExpireMapItemJob.class
index 726f3deda4..6d1483e6b2 100644
Binary files a/build/classes/server/maps/MapleMap$ExpireMapItemJob.class and b/build/classes/server/maps/MapleMap$ExpireMapItemJob.class differ
diff --git a/build/classes/server/maps/MapleMap.class b/build/classes/server/maps/MapleMap.class
index cb98bf2e39..64f702157e 100644
Binary files a/build/classes/server/maps/MapleMap.class and b/build/classes/server/maps/MapleMap.class differ
diff --git a/dist/MapleSolaxia.jar b/dist/MapleSolaxia.jar
index 2c11ea8d4e..211b183d48 100644
Binary files a/dist/MapleSolaxia.jar and b/dist/MapleSolaxia.jar differ
diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt
index 7c6ddc4b04..1ffcddf0c2 100644
--- a/docs/mychanges_ptbr.txt
+++ b/docs/mychanges_ptbr.txt
@@ -641,4 +641,13 @@ Corrigido buff Wind Walk n
03 Novembro 2017,
Modificado custom questline: recompensa deixa de ser PAC com chaos scrolls p/ map chair skill com itens de Maple.
-Adicionado quest de Horus' Eye.
\ No newline at end of file
+Adicionado quest de Horus' Eye.
+Consertado Wind Walk agora atuando corretamente, não uma outra versão de Dark Sight.
+
+04 Novembro 2017,
+Corrigido WK Charge skills não sobrescrevendo uma à outra ao ativar as skills.
+Implementado nova ferramenta: MapleQuestItemFetcher. Ela vasculha a DB e os XMLs em busca de informações perdidas quanto aos itens de quest.
+
+05 Novembro 2017,
+Adicionado sistema de level cap para jobs correntes.
+Revisto acesso concorrente sobre o componente EM da classe EIM.
\ No newline at end of file
diff --git a/docs/todo.txt b/docs/todo.txt
index ae81dec973..4765e76daf 100644
--- a/docs/todo.txt
+++ b/docs/todo.txt
@@ -35,7 +35,6 @@ ToDo / Missing features list:
---------------------------
** Skills **
-- Some pirate skills incomplete or not implemented yet.
---------------------------
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
index 3287222d26..b320fa7483 100644
--- a/nbproject/private/private.xml
+++ b/nbproject/private/private.xml
@@ -2,6 +2,8 @@
-
+
+ file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/maps/MapleMap.java
+
diff --git a/scripts/event/DollHouse.js b/scripts/event/DollHouse.js
index b5fb34344f..9e8ac8f927 100644
--- a/scripts/event/DollHouse.js
+++ b/scripts/event/DollHouse.js
@@ -27,7 +27,6 @@ importPackage(Packages.tools);
var entryMap = 922000010;
var exitMap = 221024400;
var eventTime = 10; //10 minutes
-var eim;
function init() {
em.setProperty("noEntry","false");
diff --git a/scripts/event/Puppeteer.js b/scripts/event/Puppeteer.js
index a2159a9d3f..b0410e9f24 100644
--- a/scripts/event/Puppeteer.js
+++ b/scripts/event/Puppeteer.js
@@ -1,7 +1,6 @@
var minPlayers = 1;
-var timeLimit = 10; //10 minutes
+var timeLimit = 1; //10 minutes
var eventTimer = 1000 * 60 * timeLimit;
-var entryMap = 910510001;
var exitMap = 105070300;
var eventMap = 910510000;
@@ -18,12 +17,7 @@ function setup(difficulty, lobbyId){
function afterSetup(eim){}
-function respawn(eim){
- var map = eim.getMapInstance(entryMap);
- map.allowSummonState(true);
- map.instanceMapRespawn();
- eim.schedule("respawn", 10000);
-}
+function respawn(eim){}
function playerEntry(eim, player){
var cave = eim.getMapInstance(eventMap);
@@ -43,7 +37,7 @@ function playerRevive(eim, player){
player.setHp(50);
player.setStance(0);
eim.unregisterPlayer(player);
- player.changeMap(entryMap);
+ player.changeMap(exitMap);
return false;
}
@@ -65,19 +59,7 @@ function monsterValue(eim, mobId){
return -1;
}
-function leftParty(eim, player){
- var party = eim.getPlayers();
-
- if(party.size() < minPlayers){
- for(var i = 0; i < party.size(); i++){
- playerExit(eim, party.get(i));
- }
- eim.dispose();
- }
- else{
- playerExit(eim, player);
- }
-}
+function leftParty(eim, player){}
function disbandParty(eim){}
@@ -85,11 +67,11 @@ function playerUnregistered(eim, player){}
function playerExit(eim, player){
eim.unregisterPlayer(player);
- player.changeMap(entryMap, 2);
+ player.changeMap(exitMap);
}
-function moveMap(eim, player){
- if(player.getMap().getId() == exitMap || player.getMap().getId() == entryMap){
+function changedMap(eim, player){
+ if(player.getMap().getId() < eventMap || player.getMap().getId() > next){
removePlayer(eim, player);
eim.stopEventTimer();
eim.setEventCleared();
@@ -100,7 +82,7 @@ function moveMap(eim, player){
function removePlayer(eim, player){
eim.unregisterPlayer(player);
player.getMap().removePlayer(player);
- player.setMap(entryMap);
+ player.setMap(exitMap);
}
function cancelSchedule(){}
diff --git a/scripts/map/onUserEnter/910510202.js b/scripts/map/onUserEnter/910510202.js
new file mode 100644
index 0000000000..40ce41eea3
--- /dev/null
+++ b/scripts/map/onUserEnter/910510202.js
@@ -0,0 +1,11 @@
+importPackage(Packages.server.life);
+
+function start(ms){
+ var mobId = 9300344;
+ var player = ms.getPlayer();
+ var map = player.getMap();
+
+ if(map.countMonster(mobId) == 0) {
+ map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), new java.awt.Point(680, 258));
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/1063016.js b/scripts/npc/1063016.js
new file mode 100644
index 0000000000..778cb8eca6
--- /dev/null
+++ b/scripts/npc/1063016.js
@@ -0,0 +1,33 @@
+/* Strange Looking Statue
+ Puppeteer's Secret Passage (910510100)
+ Puppeteer JQ.
+ */
+
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.sendYesNo("Will you exit this trial?");
+ } else {
+ cm.warp(105040201, 2);
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/1063017.js b/scripts/npc/1063017.js
new file mode 100644
index 0000000000..f1bde509de
--- /dev/null
+++ b/scripts/npc/1063017.js
@@ -0,0 +1,38 @@
+/* Monstrous Looking Statue
+ Puppeteer's Secret Passage (910510100)
+ Puppeteer JQ.
+ */
+
+var status;
+
+function start() {
+ status = -1;
+ action(1, 0, 0);
+}
+
+function action(mode, type, selection) {
+ if (mode == -1) {
+ cm.dispose();
+ } else {
+ if (mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+ if (mode == 1)
+ status++;
+ else
+ status--;
+
+ if(status == 0) {
+ cm.sendYesNo("Ahead awaits the Master himself. Are you ready to face him?");
+ } else {
+ if(cm.getClient().getChannelServer().getMapFactory().getMap(925020010).getCharacters().size() > 0) {
+ cm.sendOk("Someone is already challenging the Master. Try again later.");
+ } else {
+ cm.warp(910510202, 0);
+ }
+
+ cm.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/npc/1104000.js b/scripts/npc/1104000.js
index 6741c377ae..35e8580d21 100644
--- a/scripts/npc/1104000.js
+++ b/scripts/npc/1104000.js
@@ -15,8 +15,6 @@ function action(mode, type, selection){
else
status++;
-
-
if(status == 0){
cm.sendNext("What the... you don't belong here!");
}
diff --git a/scripts/npc/1204001.js b/scripts/npc/1204001.js
index 461de680e3..d4b555070e 100644
--- a/scripts/npc/1204001.js
+++ b/scripts/npc/1204001.js
@@ -5,7 +5,16 @@
var status = -1;
+function start() {
+ action(1, 0, 0);
+}
+
function action(mode, type, selection) {
+ if(mode == -1 || mode == 0 && type > 0) {
+ cm.dispose();
+ return;
+ }
+
if (mode == 1) {
status++;
} else {
@@ -16,8 +25,8 @@ function action(mode, type, selection) {
} else if (status == 1) {
cm.sendNextPrev("#b(The Black Wings? Huh? Who are they? And how is all this related to the Black Mage? Hm, maybe you should report this info to Tru.)#k", 3);
} else if (status == 2) {
- cm.startQuest(21760);
- cm.warp(105040200, 3);//104000004
- cm.dispose();
+ cm.startQuest(21760);
+ cm.warp(105040200, 3);//104000004
+ cm.dispose();
}
}
\ No newline at end of file
diff --git a/scripts/npc/2091005_old.js b/scripts/npc/2091005_old.js
index 4a4af5d907..e79cd01adb 100644
--- a/scripts/npc/2091005_old.js
+++ b/scripts/npc/2091005_old.js
@@ -79,9 +79,9 @@ function action(mode, type, selection) {
cm.sendNext("Haha! Who are you trying to impress with a heart like that?\r\nGo back home where you belong!");
} else {
if(cm.getClient().getChannelServer().getMapFactory().getMap(925020010).getCharacters().size() > 0) {
- cm.sendOk("Someone is already in Dojo");
- cm.dispose();
- return;
+ cm.sendOk("Someone is already in Dojo.");
+ cm.dispose();
+ return;
}
cm.warp(925020010, 0);
cm.getPlayer().setFinishedDojoTutorial();
diff --git a/scripts/npc/PupeteerPassword.js b/scripts/npc/PupeteerPassword.js
index 6c00cc35d3..6be94aaeaf 100644
--- a/scripts/npc/PupeteerPassword.js
+++ b/scripts/npc/PupeteerPassword.js
@@ -22,11 +22,10 @@ function action(mode, type, selection){
}
else if(status == 1){
if(cm.getText() == "Francis is a genius Puppeteer!"){
-
- if(cm.isQuestCompleted(20730) || !cm.isQuestStarted(20730) || (cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) > 0))
- cm.warp(910510000, 1);
- else if(cm.isQuestStarted(20730))
+ if(cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) == 0)
cm.warp(910510001, 1);
+ else
+ cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
cm.dispose();
}
diff --git a/scripts/portal/enterDollWay.js b/scripts/portal/enterDollWay.js
new file mode 100644
index 0000000000..127ab5646b
--- /dev/null
+++ b/scripts/portal/enterDollWay.js
@@ -0,0 +1,12 @@
+function enter(pi) {
+ if(pi.isQuestCompleted(20730) || pi.isQuestCompleted(21731)) { // puppeteer defeated, newfound secret path
+ pi.warp(105070300,3);
+ return true;
+ } else if(pi.isQuestStarted(21731)) {
+ pi.warp(910510100,0);
+ return true;
+ } else {
+ pi.message("An ominous power prevents you from passing here.");
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/scripts/portal/enterDollcave.js b/scripts/portal/enterDollcave.js
index a88ac1b06c..320f270737 100644
--- a/scripts/portal/enterDollcave.js
+++ b/scripts/portal/enterDollcave.js
@@ -1,4 +1,9 @@
function enter(pi) {
+ if(pi.isQuestCompleted(20730) || pi.isQuestCompleted(21731)) { // puppeteer defeated, newfound secret path
+ pi.warp(105040201,2);
+ return true;
+ }
+
pi.openNpc(1063011, "PupeteerPassword");
return false;
}
\ No newline at end of file
diff --git a/src/client/MapleBuffStat.java b/src/client/MapleBuffStat.java
index 62b9a444c0..57373d1fa8 100644
--- a/src/client/MapleBuffStat.java
+++ b/src/client/MapleBuffStat.java
@@ -110,7 +110,7 @@ public enum MapleBuffStat {
// needs Soul Stone
//end incorrect buffstats
- //WIND_WALK(0x400000000L, true),
+ WIND_WALK(0x400000000L, true),
ARAN_COMBO(0x1000000000L, true),
COMBO_DRAIN(0x2000000000L, true),
COMBO_BARRIER(0x4000000000L, true),
diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java
index cac2ae3d25..886cce135c 100644
--- a/src/client/MapleCharacter.java
+++ b/src/client/MapleCharacter.java
@@ -2984,10 +2984,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
private List> cancelEffectInternal(MapleStatEffect effect, boolean overwrite, long startTime, Set removedStats) {
- Map buffstats;
+ Map buffstats = null;
+ MapleBuffStat ombs;
if (!overwrite) { // is removing the source effect, meaning every effect from this srcid is being purged
buffstats = extractCurrentBuffStats(effect);
- } else { // is dropping ALL current statups that uses same stats as the given effect
+ } else if ((ombs = getSingletonStatupFromEffect(effect)) != null) { // removing all effects of a buff having non-shareable buff stat.
+ MapleBuffStatValueHolder mbsvh = effects.get(ombs);
+ if(mbsvh != null) {
+ buffstats = extractCurrentBuffStats(mbsvh.effect);
+ }
+ }
+
+ if (buffstats == null) { // all else, is dropping ALL current statups that uses same stats as the given effect
buffstats = extractLeastRelevantStatEffectsIfFull(effect);
}
@@ -3178,7 +3186,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return extractedStatBuffs;
}
- private boolean isSingletonStatup(MapleBuffStat mbs) {
+ private static MapleBuffStat getSingletonStatupFromEffect(MapleStatEffect mse) {
+ for(Pair mbs : mse.getStatups()) {
+ if(isSingletonStatup(mbs.getLeft())) {
+ return mbs.getLeft();
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isSingletonStatup(MapleBuffStat mbs) {
switch(mbs) { //HPREC and MPREC are supposed to be singleton
case COUPON_EXP1:
case COUPON_EXP2:
@@ -3890,9 +3908,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return maxhp;
}
- public int getMaxLevel() {
+ public int getMaxClassLevel() {
return isCygnus() ? 120 : 200;
}
+
+ public int getMaxLevel() {
+ if(!ServerConstants.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) {
+ return getMaxClassLevel();
+ }
+
+ return GameConstants.getJobMaxLevel(job);
+ }
public int getMaxMp() {
return maxmp;
@@ -4691,12 +4717,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void increaseGuildCapacity() { //hopefully nothing is null
- if (getMeso() < getGuild().getIncreaseGuildCost(getGuild().getCapacity())) {
+ if (getMeso() < MapleGuild.getIncreaseGuildCost(getGuild().getCapacity())) {
dropMessage(1, "You don't have enough mesos.");
return;
}
Server.getInstance().increaseGuildCapacity(guildid);
- gainMeso(-getGuild().getIncreaseGuildCost(getGuild().getCapacity()), true, false, false);
+ gainMeso(-MapleGuild.getIncreaseGuildCost(getGuild().getCapacity()), true, false, false);
}
public boolean isActiveBuffedValue(int skillid) {
@@ -4741,13 +4767,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public boolean isCygnus() {
return getJobType() == 1;
}
+
+ public boolean isGmJob() {
+ int jn = job.getJobNiche();
+ return jn >= 8 && jn <= 9;
+ }
public boolean isAran() {
- return getJob().getId() >= 2000 && getJob().getId() <= 2112;
+ return job.getId() >= 2000 && job.getId() <= 2112;
}
public boolean isBeginnerJob() {
- return (getJob().getId() == 0 || getJob().getId() == 1000 || getJob().getId() == 2000);
+ return (job.getId() == 0 || job.getId() == 1000 || job.getId() == 2000);
}
public boolean isGM() {
@@ -4852,9 +4883,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
level++;
- if (level >= getMaxLevel()) {
+ if (level >= getMaxClassLevel()) {
exp.set(0);
- level = getMaxLevel(); //To prevent levels past 200
+ level = getMaxClassLevel(); //To prevent levels past the maximum
}
maxhp = Math.min(30000, maxhp);
diff --git a/src/client/MapleJob.java b/src/client/MapleJob.java
index 4a7eb9c64b..c301e20d75 100644
--- a/src/client/MapleJob.java
+++ b/src/client/MapleJob.java
@@ -57,7 +57,7 @@ public enum MapleJob {
THUNDERBREAKER1(1500), THUNDERBREAKER2(1510), THUNDERBREAKER3(1511), THUNDERBREAKER4(1512),
LEGEND(2000), EVAN(2001),
- ARAN1(2100),ARAN2(2110), ARAN3(2111), ARAN4(2112),
+ ARAN1(2100), ARAN2(2110), ARAN3(2111), ARAN4(2112),
EVAN1(2200), EVAN2(2210), EVAN3(2211), EVAN4(2212), EVAN5(2213), EVAN6(2214),
EVAN7(2215), EVAN8(2216), EVAN9(2217), EVAN10(2218);
diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java
index 2b0fcb4f11..55ba527837 100644
--- a/src/client/command/Commands.java
+++ b/src/client/command/Commands.java
@@ -1174,7 +1174,7 @@ public class Commands {
}
player.loseExp(player.getExp(), false, false);
- player.setLevel(Math.min(Integer.parseInt(sub[1]), player.getMaxLevel()) - 1);
+ player.setLevel(Math.min(Integer.parseInt(sub[1]), player.getMaxClassLevel()) - 1);
player.resetPlayerRates();
if(ServerConstants.USE_ADD_RATES_BY_LEVEL == true) player.setPlayerRates();
@@ -1189,7 +1189,7 @@ public class Commands {
break;
}
- while (player.getLevel() < Math.min(255, Integer.parseInt(sub[1]))) {
+ while (player.getLevel() < Math.min(player.getMaxClassLevel(), Integer.parseInt(sub[1]))) {
player.levelUp(false);
}
break;
diff --git a/src/client/status/MonsterStatusEffect.java b/src/client/status/MonsterStatusEffect.java
index 473eb04d98..8cc2bc3bb1 100644
--- a/src/client/status/MonsterStatusEffect.java
+++ b/src/client/status/MonsterStatusEffect.java
@@ -63,7 +63,7 @@ public class MonsterStatusEffect {
if (cancelTask != null) {
cancelTask.cancel(false);
}
- cancelTask = null;
+ cancelTask = null;
}
public ScheduledFuture> getCancelTask() {
diff --git a/src/constants/GameConstants.java b/src/constants/GameConstants.java
index cd3c097f06..a7ae908c22 100644
--- a/src/constants/GameConstants.java
+++ b/src/constants/GameConstants.java
@@ -62,7 +62,29 @@ public class GameConstants {
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000,
530000, 550000, 570000, 590000, 610000, 630000, 650000, 670000, 690000, 710000, 730000, 750000, 770000, 790000, 810000, 830000, 850000, 870000, 890000, 910000};
-
+ public static int getJobMaxLevel(MapleJob job) {
+ if(job.getId() % 1000 == 0) { // beginner
+ return 10;
+
+ } else if(job.getId() % 100 == 0) { // 1st job
+ return 30;
+
+ } else {
+ int jobBranch = job.getId() % 10;
+
+ switch(jobBranch) {
+ case 0:
+ return 70; // 2nd job
+
+ case 1:
+ return 120; // 3rd job
+
+ default:
+ return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
+ }
+ }
+ }
+
public static int getHiddenSkill(final int skill) {
switch (skill) {
case Aran.HIDDEN_FULL_DOUBLE:
@@ -82,7 +104,6 @@ public class GameConstants {
return 0;
}
-
public static boolean isAranSkills(final int skill) {
return Aran.FULL_SWING == skill || Aran.OVER_SWING == skill || Aran.COMBO_TEMPEST == skill || Aran.COMBO_FENRIR == skill || Aran.COMBO_DRAIN == skill
|| Aran.HIDDEN_FULL_DOUBLE == skill || Aran.HIDDEN_FULL_TRIPLE == skill || Aran.HIDDEN_OVER_DOUBLE == skill || Aran.HIDDEN_OVER_TRIPLE == skill
diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java
index 808ff02641..1542fbad63 100644
--- a/src/constants/ServerConstants.java
+++ b/src/constants/ServerConstants.java
@@ -17,9 +17,11 @@ public class ServerConstants {
//Login Configuration
public static final int CHANNEL_LOAD = 100; //Max players per channel.
+ public static final long RESPAWN_INTERVAL = 10 * 1000; //10 seconds, 10000.
public static final long PURGING_INTERVAL = 5 * 60 * 1000;
public static final long RANKING_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
+
public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character needs this feature ENABLED.
public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin.
@@ -50,6 +52,8 @@ public class ServerConstants {
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
public static final boolean USE_REFRESH_RANK_MOVE = true;
+ public static final boolean USE_ENFORCE_MOB_LEVEL_RANGE = true; //Players N levels below the killed mob will gain no experience from defeating it.
+ public static final boolean USE_ENFORCE_JOB_LEVEL_RANGE = false;//Caps the player level on the minimum required to advance their current jobs.
public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of those featured by the players.
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
@@ -57,7 +61,6 @@ public class ServerConstants {
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
- public static final boolean USE_UNDERLEVELED_EXP_BLOCK = true; //Players N levels below the killed mob will gain no experience from defeating it.
//Server Rates And Experience
public static final int EXP_RATE = 10;
@@ -72,7 +75,7 @@ public class ServerConstants {
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
//Miscellaneous Configuration
- public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_UNDERLEVELED_EXP_BLOCK" is enabled.
+ public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled.
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
@@ -81,7 +84,7 @@ public class ServerConstants {
//Dangling Items Configuration
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
- public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling item objects on the map item history.
+ public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
//Some Gameplay Enhancing Configurations
diff --git a/src/net/server/channel/Channel.java b/src/net/server/channel/Channel.java
index 9b30d86820..859a32c107 100644
--- a/src/net/server/channel/Channel.java
+++ b/src/net/server/channel/Channel.java
@@ -108,7 +108,7 @@ public final class Channel {
IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
- TimerManager.getInstance().register(new respawnMaps(), 10000);
+ TimerManager.getInstance().register(new respawnMaps(), ServerConstants.RESPAWN_INTERVAL);
acceptor.setHandler(new MapleServerHandler(world, channel));
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
diff --git a/src/net/server/channel/handlers/CancelBuffHandler.java b/src/net/server/channel/handlers/CancelBuffHandler.java
index d55e4f0508..a77203666b 100644
--- a/src/net/server/channel/handlers/CancelBuffHandler.java
+++ b/src/net/server/channel/handlers/CancelBuffHandler.java
@@ -45,11 +45,6 @@ public final class CancelBuffHandler extends AbstractMaplePacketHandler implemen
int sourceid = slea.readInt();
switch (sourceid) {
- case NightWalker.DARK_SIGHT: // wind walk as a dark sight...
- c.getPlayer().cancelEffect(SkillFactory.getSkill(NightWalker.DARK_SIGHT).getEffect(1), false, -1);
- c.getPlayer().cancelEffect(SkillFactory.getSkill(WindArcher.WIND_WALK).getEffect(1), false, -1);
- break;
-
case FPArchMage.BIG_BANG:
case ILArchMage.BIG_BANG:
case Bishop.BIG_BANG:
diff --git a/src/net/server/channel/handlers/CloseRangeDamageHandler.java b/src/net/server/channel/handlers/CloseRangeDamageHandler.java
index ff9ff0830e..da974ce9a3 100644
--- a/src/net/server/channel/handlers/CloseRangeDamageHandler.java
+++ b/src/net/server/channel/handlers/CloseRangeDamageHandler.java
@@ -178,10 +178,14 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
}
}
}
- if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 || player.getSkillLevel(SkillFactory.getSkill(Rogue.DARK_SIGHT)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null) {// && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004
+ if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(Rogue.DARK_SIGHT)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null) {// && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004
player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT);
player.cancelBuffStats(MapleBuffStat.DARKSIGHT);
+ } else if(player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 && player.getBuffedValue(MapleBuffStat.WIND_WALK) != null) {
+ player.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK);
+ player.cancelBuffStats(MapleBuffStat.WIND_WALK);
}
+
applyAttack(attack, player, attackCount);
}
}
\ No newline at end of file
diff --git a/src/net/server/channel/handlers/RangedAttackHandler.java b/src/net/server/channel/handlers/RangedAttackHandler.java
index cf255c8327..5bdcfa5777 100644
--- a/src/net/server/channel/handlers/RangedAttackHandler.java
+++ b/src/net/server/channel/handlers/RangedAttackHandler.java
@@ -211,10 +211,15 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
}
}
}
- if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && attack.numAttacked > 0 && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004) {
+
+ if (player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && attack.numAttacked > 0 && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004) {
player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT);
player.cancelBuffStats(MapleBuffStat.DARKSIGHT);
+ } else if(player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 && player.getBuffedValue(MapleBuffStat.WIND_WALK) != null && attack.numAttacked > 0) {
+ player.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK);
+ player.cancelBuffStats(MapleBuffStat.WIND_WALK);
}
+
applyAttack(attack, player, bulletCount);
}
}
diff --git a/src/scripting/event/EventInstanceManager.java b/src/scripting/event/EventInstanceManager.java
index e3cfefee0d..32b7992f6a 100644
--- a/src/scripting/event/EventInstanceManager.java
+++ b/src/scripting/event/EventInstanceManager.java
@@ -131,7 +131,12 @@ public class EventInstanceManager {
}
public EventManager getEm() {
- return em;
+ sL.lock();
+ try {
+ return em;
+ } finally {
+ sL.unlock();
+ }
}
public int getEventPlayersJobs() {
@@ -623,7 +628,10 @@ public class EventInstanceManager {
}
}
- public void dispose() {
+ public synchronized void dispose() {
+ if(disposed) return;
+
+ disposed = true;
try {
sL.lock();
try {
@@ -652,8 +660,14 @@ public class EventInstanceManager {
killCount.clear();
disposeExpedition();
- if(!eventCleared) em.disposeInstance(name);
- em = null;
+
+ sL.lock();
+ try {
+ if(!eventCleared) em.disposeInstance(name);
+ em = null;
+ } finally {
+ sL.unlock();
+ }
}
public MapleMapFactory getMapFactory() {
@@ -664,12 +678,11 @@ public class EventInstanceManager {
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
- if(em == null) return;
-
try {
sL.lock();
try {
- em.getIv().invokeFunction(methodName, EventInstanceManager.this);
+ if(em == null) return;
+ em.getIv().invokeFunction(methodName, EventInstanceManager.this);
} finally {
sL.unlock();
}
@@ -685,10 +698,18 @@ public class EventInstanceManager {
}
public void saveWinner(MapleCharacter chr) {
+ String emName;
+ sL.lock();
+ try {
+ emName = em.getName();
+ } finally {
+ sL.unlock();
+ }
+
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("INSERT INTO eventstats (event, instance, characterid, channel) VALUES (?, ?, ?, ?)")) {
- ps.setString(1, em.getName());
+ ps.setString(1, emName);
ps.setString(2, getName());
ps.setInt(3, chr.getId());
ps.setInt(4, chr.getClient().getChannel());
@@ -706,9 +727,14 @@ public class EventInstanceManager {
map.setEventInstance(this);
if (!mapFactory.isMapLoaded(mapId)) {
- if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) {
- map.shuffleReactors();
- }
+ sL.lock();
+ try {
+ if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) {
+ map.shuffleReactors();
+ }
+ } finally {
+ sL.unlock();
+ }
}
return map;
}
@@ -1035,8 +1061,14 @@ public class EventInstanceManager {
private void disposeExpedition() {
if (expedition != null) {
- expedition.dispose(eventCleared);
- em.getChannelServer().getExpeditions().remove(expedition);
+ expedition.dispose(eventCleared);
+
+ sL.lock();
+ try {
+ em.getChannelServer().getExpeditions().remove(expedition);
+ } finally {
+ sL.unlock();
+ }
expedition = null;
}
@@ -1044,7 +1076,14 @@ public class EventInstanceManager {
public final void setEventCleared() {
eventCleared = true;
- em.disposeInstance(name);
+
+ sL.lock();
+ try {
+ em.disposeInstance(name);
+ } finally {
+ sL.unlock();
+ }
+
disposeExpedition();
}
diff --git a/src/server/MapleItemInformationProvider.java b/src/server/MapleItemInformationProvider.java
index 5170502659..f8e6659dfc 100644
--- a/src/server/MapleItemInformationProvider.java
+++ b/src/server/MapleItemInformationProvider.java
@@ -1129,7 +1129,6 @@ public class MapleItemInformationProvider {
return isQuestItemCache.get(itemId);
}
MapleData data = getItemData(itemId);
- System.out.println(data);
boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
isQuestItemCache.put(itemId, questItem);
return questItem;
diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java
index 0b32d8eab1..af77171840 100644
--- a/src/server/MapleStatEffect.java
+++ b/src/server/MapleStatEffect.java
@@ -455,9 +455,10 @@ public class MapleStatEffect {
case Marksman.SHARP_EYES:
statups.add(new Pair<>(MapleBuffStat.SHARP_EYES, Integer.valueOf(ret.x << 8 | ret.y)));
break;
- // THIEF
- case Rogue.DARK_SIGHT:
case WindArcher.WIND_WALK:
+ statups.add(new Pair<>(MapleBuffStat.WIND_WALK, Integer.valueOf(x)));
+ break;
+ case Rogue.DARK_SIGHT:
case NightWalker.DARK_SIGHT:
statups.add(new Pair<>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x)));
break;
@@ -1099,6 +1100,9 @@ public class MapleStatEffect {
} else if (isDs()) {
List> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.DARKSIGHT, 0));
mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat);
+ } else if (isWw()) {
+ List> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.WIND_WALK, 0));
+ mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat);
} else if (isCombo()) {
mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), statups);
} else if (isMonsterRiding()) {
@@ -1353,7 +1357,11 @@ public class MapleStatEffect {
}
private boolean isDs() {
- return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == WindArcher.WIND_WALK || sourceid == NightWalker.DARK_SIGHT);
+ return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == NightWalker.DARK_SIGHT);
+ }
+
+ private boolean isWw() {
+ return skill && (sourceid == WindArcher.WIND_WALK);
}
private boolean isCombo() {
diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java
index ea00a7881a..bc86e8e430 100644
--- a/src/server/life/MapleMonster.java
+++ b/src/server/life/MapleMonster.java
@@ -287,7 +287,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
int partyLevel = 0;
- int leechMinLevel = (ServerConstants.USE_UNDERLEVELED_EXP_BLOCK) ? getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 0; //NO EXP WILL BE GIVEN for those who are underleveled!
+ int leechMinLevel = (ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE) ? getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 0; //NO EXP WILL BE GIVEN for those who are underleveled!
int leechCount = 0;
for (MapleCharacter mc : members) {
@@ -347,7 +347,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
} else {
- if(!ServerConstants.USE_UNDERLEVELED_EXP_BLOCK || mc.getLevel() >= getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN) {
+ if(!ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE || mc.getLevel() >= getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN) {
//NO EXP WILL BE GIVEN for those who are underleveled!
giveExpToCharacter(mc, xp, isKiller, 1);
} else {
@@ -1021,8 +1021,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
final MapleMonster mons = this;
- TimerManager tMan = TimerManager.getInstance();
- tMan.schedule(
+ TimerManager.getInstance().schedule(
new Runnable() {
@Override
diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java
index 0d2df3608d..000871ccd1 100644
--- a/src/server/maps/MapleMap.java
+++ b/src/server/maps/MapleMap.java
@@ -602,6 +602,8 @@ public class MapleMap {
private void startItemMonitor() {
chrWLock.lock();
try {
+ if(itemMonitor != null) return;
+
itemMonitor = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
@@ -1093,14 +1095,13 @@ public class MapleMap {
public void destroyReactor(int oid) {
final MapleReactor reactor = getReactorByOid(oid);
- TimerManager tMan = TimerManager.getInstance();
broadcastMessage(MaplePacketCreator.destroyReactor(reactor));
reactor.cancelReactorTimeout();
reactor.setAlive(false);
removeMapObject(reactor);
if (reactor.getDelay() > 0) {
- tMan.schedule(new Runnable() {
+ TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
respawnReactor(reactor);
@@ -1879,9 +1880,12 @@ public class MapleMap {
}
public void addPlayer(final MapleCharacter chr) {
+ int chrSize;
chrWLock.lock();
try {
characters.add(chr);
+ chrSize = characters.size();
+
addPartyMemberInternal(chr);
} finally {
chrWLock.unlock();
@@ -1889,7 +1893,7 @@ public class MapleMap {
chr.setMapId(mapid);
itemMonitorTimeout = 1;
- if (getCharacters().size() <= 1) {
+ if (chrSize == 1) {
if(!hasItemMonitor()) startItemMonitor();
if (onFirstUserEnter.length() != 0 && !chr.hasEntered(onFirstUserEnter, mapid) && MapScriptManager.getInstance().scriptExists(onFirstUserEnter, true)) {
diff --git a/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java b/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java
index 89d293a7f6..b06b17a617 100644
--- a/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java
+++ b/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java
@@ -40,9 +40,10 @@ import tools.Pair;
/**
*
* @author RonanLana
+ *
* This application traces arrow drop data on the underlying DB (that must be
- * defined on the DatabaseConnection file of this project) and generates a SQL
- * file that proposes updated arrow quantitty on drop entries for the drop_data table.
+ * defined on the DatabaseConnection file of this project) and generates a SQL file
+ * that proposes updated arrow quantitty on drop entries for the drop_data table.
*
* The arrow quantity range is calculated accordingly with the target mob stats, such
* as level and if it's a boss or not.
diff --git a/tools/MapleCouponInstaller/nbproject/private/private.properties b/tools/MapleCouponInstaller/nbproject/private/private.properties
index 67c9c27960..adc8a8f46a 100644
--- a/tools/MapleCouponInstaller/nbproject/private/private.properties
+++ b/tools/MapleCouponInstaller/nbproject/private/private.properties
@@ -3,4 +3,4 @@ do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
-user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
+user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
diff --git a/tools/MapleCouponInstaller/nbproject/private/private.xml b/tools/MapleCouponInstaller/nbproject/private/private.xml
index 27b105dcc9..6807a2ba19 100644
--- a/tools/MapleCouponInstaller/nbproject/private/private.xml
+++ b/tools/MapleCouponInstaller/nbproject/private/private.xml
@@ -2,8 +2,6 @@
-
- file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/MapleCouponInstaller/src/maplecouponinstaller/MapleCouponInstaller.java
-
+
diff --git a/tools/MapleCouponInstaller/src/maplecouponinstaller/MapleCouponInstaller.java b/tools/MapleCouponInstaller/src/maplecouponinstaller/MapleCouponInstaller.java
index 583e34b6a8..49cfd31adb 100644
--- a/tools/MapleCouponInstaller/src/maplecouponinstaller/MapleCouponInstaller.java
+++ b/tools/MapleCouponInstaller/src/maplecouponinstaller/MapleCouponInstaller.java
@@ -28,9 +28,9 @@ import java.sql.SQLException;
*
* @author RonanLana
*
- * This application gathers information about the Cash Shop EXP & DROP coupons, such
- * as applied rates, active times of day and days of week and dumps them in a SQL
- * table, in which will be used by the server.
+ * This application gathers information about the Cash Shop's EXP & DROP coupons,
+ * such as applied rates, active times of day and days of week and dumps them in
+ * a SQL table, in which will be used by the server.
*
*/
public class MapleCouponInstaller {
diff --git a/tools/MapleIdRetriever/nbproject/private/private.properties b/tools/MapleIdRetriever/nbproject/private/private.properties
index 646b670577..1c5af62efc 100644
--- a/tools/MapleIdRetriever/nbproject/private/private.properties
+++ b/tools/MapleIdRetriever/nbproject/private/private.properties
@@ -1,2 +1,2 @@
compile.on.save=true
-user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
+user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
diff --git a/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java b/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java
index 4acee45014..17d961b05c 100644
--- a/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java
+++ b/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java
@@ -38,6 +38,7 @@ import tools.Pair;
/**
*
* @author RonanLana
+ *
* This application traces missing meso drop data on the underlying DB (that must be
* defined on the DatabaseConnection file of this project) and generates a
* SQL file that proposes missing drop entries for the drop_data table.
diff --git a/tools/MapleQuestItemFetcher/build.xml b/tools/MapleQuestItemFetcher/build.xml
new file mode 100644
index 0000000000..5191e498af
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project MapleQuestItemFetcher.
+
+
+
diff --git a/tools/MapleQuestItemFetcher/lib/QuestReport.txt b/tools/MapleQuestItemFetcher/lib/QuestReport.txt
new file mode 100644
index 0000000000..b25e0da53c
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/lib/QuestReport.txt
@@ -0,0 +1,423 @@
+ # Report File autogenerated from the MapleQuestItemFetcher feature by Ronan Lana.
+ # Generated data takes into account several data info from the underlying DB and the server-side WZ.xmls.
+
+INCORRECT QUESTIDS ON DB
+4001342 : 7777 -> 28175
+4001367 : 28257 -> 28262
+4001368 : 28258 -> 28262
+4001369 : 28259 -> 28262
+4001370 : 28260 -> 28262
+4001371 : 28261 -> 28262
+4031130 : 0 -> 3238
+4031164 : 0 -> 2084
+4031171 : 0 -> 7101
+4031172 : 7103 -> 7106
+4031189 : 0 -> 3448
+4031218 : 0 -> 3071
+4031223 : 3607 -> 3608
+4031343 : 6904 -> 6905
+4031344 : 6904 -> 6905
+4031405 : 0 -> 4207
+4031511 : 6904 -> 6914
+4031512 : 6914 -> 6915
+4031514 : 6924 -> 6925
+4031515 : 6924 -> 6925
+4031517 : 6934 -> 6935
+4031518 : 6934 -> 6935
+4031856 : 0 -> 2191
+4031857 : 0 -> 2192
+4031860 : 6944 -> 6945
+4031861 : 6944 -> 6945
+4031871 : 6350 -> 28344
+4032339 : 0 -> 21303
+
+
+
+
+
+
+ITEMS WITH NO QUEST DROP DATA ON DB
+1002436 - 2075
+1102057 - 7103
+1102061 - 3066
+1302014 - 2048
+2022053 - 9330
+2022054 - 9330
+2022055 - 9330
+2022056 - 9330
+2022057 - 9332
+2022281 - 8569
+2100016 - 3223
+2100017 - 3419
+2100018 - 3236
+2100019 - 3238
+3994139 - 10360
+4001118 - 3814
+4001340 - 28167
+4001347 - 28229
+4001348 - 28231
+4001349 - 28235
+4001350 - 28235
+4001351 - 28237
+4001352 - 28206
+4001353 - 28227
+4001366 - 28195
+4031014 - 2020
+4031015 - 2022
+4031019 - 9411
+4031020 - 2050
+4031032 - 2051
+4031039 - 2055
+4031040 - 2056
+4031041 - 2057
+4031042 - 2035
+4031063 - 9260
+4031064 - 8012
+4031107 - 3409
+4031116 - 3419
+4031117 - 3421
+4031122 - 9340
+4031124 - 9340
+4031134 - 3443
+4031136 - 3439
+4031141 - 3407
+4031142 - 3407
+4031143 - 3407
+4031144 - 2047
+4031150 - 2067
+4031157 - 2074
+4031158 - 2074
+4031165 - 2086
+4031167 - 9052
+4031168 - 9055
+4031169 - 9058
+4031180 - 8020
+4031181 - 9140
+4031182 - 9140
+4031183 - 9140
+4031184 - 9150
+4031185 - 9150
+4031186 - 9150
+4031190 - 3054
+4031191 - 3063
+4031192 - 8700
+4031198 - 3043
+4031199 - 3046
+4031200 - 3069
+4031201 - 3048
+4031202 - 3050
+4031207 - 3443
+4031220 - 9210
+4031225 - 3606
+4031226 - 9321
+4031227 - 4103
+4031230 - 3619
+4031231 - 3620
+4031235 - 3607
+4031236 - 3616
+4031237 - 3605
+4031238 - 3611
+4031243 - 3443
+4031257 - 9350
+4031258 - 9351
+4031270 - 3629
+4031271 - 9351
+4031272 - 9352
+4031274 - 3083
+4031275 - 3083
+4031276 - 3083
+4031277 - 3083
+4031278 - 3083
+4031280 - 3632
+4031290 - 4106
+4031291 - 4006
+4031292 - 4009
+4031293 - 4010
+4031296 - 4010
+4031297 - 9386
+4031298 - 3636
+4031301 - 9391
+4031302 - 9503
+4031303 - 4008
+4031304 - 9392
+4031321 - 9504
+4031352 - 4005
+4031354 - 4013
+4031388 - 4218
+4031418 - 8823
+4031419 - 8823
+4031420 - 8823
+4031421 - 8823
+4031425 - 8822
+4031448 - 6134
+4031450 - 6263
+4031452 - 6201
+4031454 - 6281
+4031455 - 6280
+4031456 - 6230
+4031462 - 6210
+4031468 - 6222
+4031471 - 6153
+4031478 - 6210
+4031488 - 6312
+4031495 - 6192
+4031504 - 9640
+4031505 - 9641
+4031506 - 9642
+4031507 - 6002
+4031508 - 6002
+4031554 - 3821
+4031557 - 9710
+4031558 - 9711
+4031559 - 9712
+4031560 - 9713
+4031561 - 9714
+4031563 - 8850
+4031564 - 8851
+4031565 - 8852
+4031566 - 8853
+4031567 - 8854
+4031568 - 3911
+4031570 - 3939
+4031571 - 3941
+4031574 - 3935
+4031578 - 3923
+4031581 - 3937
+4031582 - 3901
+4031584 - 9731
+4031585 - 9732
+4031586 - 9740
+4031587 - 9741
+4031588 - 9742
+4031590 - 8881
+4031608 - 9803
+4031611 - 9804
+4031612 - 9805
+4031625 - 9820
+4031661 - 9861
+4031662 - 9866
+4031667 - 9863
+4031683 - 1115
+4031684 - 1116
+4031685 - 1117
+4031686 - 1118
+4031687 - 1119
+4031688 - 1120
+4031689 - 1121
+4031690 - 1122
+4031691 - 1123
+4031692 - 1124
+4031695 - 3335
+4031696 - 3334
+4031697 - 3322
+4031703 - 3302
+4031708 - 3309
+4031709 - 3310
+4031737 - 3343
+4031764 - 4949
+4031766 - 4959
+4031767 - 4947
+4031768 - 4953
+4031769 - 4946
+4031770 - 4946
+4031771 - 4944
+4031772 - 4942
+4031774 - 3361
+4031785 - 3376
+4031789 - 3844
+4031796 - 3362
+4031797 - 3367
+4031798 - 3366
+4031801 - 1040
+4031806 - 3380
+4031812 - 4950
+4031833 - 9946
+4031837 - 9945
+4031881 - 4484
+4031894 - 2214
+4031921 - 4646
+4031927 - 3454
+4031928 - 3454
+4031945 - 9987
+4032037 - 9154
+4032038 - 9154
+4032039 - 9154
+4032055 - 4675
+4032087 - 10081
+4032092 - 28003
+4032119 - 28109
+4032136 - 20710
+4032138 - 20713
+4032142 - 20716
+4032143 - 20717
+4032196 - 20528
+4032197 - 20528
+4032198 - 20528
+4032233 - 8298
+4032234 - 8299
+4032235 - 8299
+4032236 - 8299
+4032237 - 8299
+4032238 - 8299
+4032239 - 8299
+4032247 - 28103
+4032248 - 28108
+4032264 - 10240
+4032265 - 10241
+4032266 - 10240
+4032270 - 10241
+4032271 - 10260
+4032272 - 10268
+4032273 - 10268
+4032275 - 10261
+4032276 - 10262
+4032277 - 10263
+4032278 - 10270
+4032279 - 10271
+4032280 - 10272
+4032281 - 10270
+4032282 - 10271
+4032283 - 10272
+4032284 - 10264
+4032285 - 10265
+4032286 - 10266
+4032287 - 10267
+4032307 - 28121
+4032308 - 28122
+4032317 - 21717
+4032318 - 21718
+4032319 - 21723
+4032321 - 21727
+4032322 - 21731
+4032324 - 21737
+4032325 - 21752
+4032326 - 21752
+4032331 - 21601
+4032333 - 21608
+4032335 - 21617
+4032342 - 21743
+4032348 - 10300
+4032349 - 10301
+4032350 - 10302
+4032374 - 2405
+4032376 - 2406
+4032377 - 2407
+4032378 - 2408
+4032379 - 2409
+4032401 - 2261
+4032402 - 2263
+4032404 - 28128
+4032423 - 21767
+4032435 - 28307
+4032436 - 28314
+4032437 - 28321
+4032443 - 28317
+4032496 - 28238
+4032511 - 3718
+4032512 - 3720
+4032513 - 3722
+4032514 - 3727
+4032516 - 3735
+4032517 - 3740
+4032518 - 3743
+4161000 - 9322
+
+
+
+
+
+
+COMPLETE QUEST ITEMS WITH ZERO QUANTITY
+1018:
+ 4000142
+
+2052:
+ 4031025
+
+2053:
+ 4031026
+
+2054:
+ 4031028
+
+2162:
+ 4031839
+
+2164:
+ 4031840
+
+2167:
+ 4031841
+
+2168:
+ 4031842
+
+2169:
+ 4031843
+
+2173:
+ 4031846
+
+2180:
+ 4031850
+
+2183:
+ 4031851
+
+2185:
+ 4031852
+
+3010:
+ 4031050
+
+6340:
+ 4031872
+
+6350:
+ 4031871
+
+6360:
+ 4031869
+
+6361:
+ 4031870
+
+6380:
+ 4031873
+
+6390:
+ 4031874
+
+8142:
+ 4000300
+ 4000301
+
+8218:
+ 4031664
+ 4031665
+ 4031666
+
+8886:
+ 4031659
+
+8887:
+ 4031658
+
+8888:
+ 4031660
+
+10430:
+ 4220152
+
+28104:
+ 4032247
+
+28120:
+ 4032306
+
+
+
+
+
+
+
diff --git a/tools/MapleQuestItemFetcher/lib/commons-io-2.6.jar b/tools/MapleQuestItemFetcher/lib/commons-io-2.6.jar
new file mode 100644
index 0000000000..00556b119d
Binary files /dev/null and b/tools/MapleQuestItemFetcher/lib/commons-io-2.6.jar differ
diff --git a/tools/MapleQuestItemFetcher/manifest.mf b/tools/MapleQuestItemFetcher/manifest.mf
new file mode 100644
index 0000000000..328e8e5bc3
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java b/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java
new file mode 100644
index 0000000000..37eef74077
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java
@@ -0,0 +1,544 @@
+/*
+ This file is part of the MapleSolaxiaV2 Maple Story Server
+
+ 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 maplequestitemfetcher;
+
+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.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.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Scanner;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import java.io.File;
+import tools.MapleItemInformationProvider;
+
+import tools.Pair;
+
+/**
+ *
+ * @author RonanLana
+ *
+ * This application haves 2 objectives: fetch missing drop data relevant to quests,
+ * and update the questid from items that are labeled as "Quest Item" on the DB.
+ *
+ * To test a server instance with this feature, MapleQuestItemFetcher must be set
+ * just like it is displayed on the MapleSolaxiaV2 source: 2 folders ahead of the
+ * root of the main source.
+ *
+ * Running it should generate a report file under "lib" folder with the search results.
+ *
+ * Estimated parse time: 1.5 minute
+ */
+public class MapleQuestItemFetcher {
+ static MapleItemInformationProvider ii;
+
+ static String host = "jdbc:mysql://localhost:3306/maplesolaxia";
+ static String driver = "com.mysql.jdbc.Driver";
+ static String username = "root";
+ static String password = "";
+
+ static String wzPath = "../../wz";
+ static String fileName = "../../wz/Quest.wz/Act.img.xml";
+ static String directoryName = "../..";
+ static String newFile = "lib/QuestReport.txt";
+
+ 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 boolean displayExtraInfo = true; // display items with zero quantity over the quest act WZ
+
+ static Map> startQuestItems = new HashMap<>(initialLength);
+ static Map> completeQuestItems = new HashMap<>(initialLength);
+
+ static Map> zeroedStartQuestItems = new HashMap<>();
+ static Map> zeroedCompleteQuestItems = new HashMap<>();
+ static Map mixedQuestidItems = new HashMap<>();
+
+ static byte status = 0;
+ static int questId = -1;
+ static int isCompleteState = 0;
+
+ static int currentItemid = 0;
+ static int currentCount = 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
+
+ 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 inspectQuestItemList(int st) {
+ String line = null;
+
+ try {
+ while(status >= st && (line = bufferedReader.readLine()) != null) {
+ readItemToken(line);
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void processCurrentItem() {
+ try {
+ if(ii.isQuestItem(currentItemid)) {
+ if(currentCount != 0) {
+ if(isCompleteState == 1) {
+ Set qi = completeQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
+
+ completeQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
+ } else {
+ Set qi = startQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
+
+ startQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
+ }
+ } else {
+ if(isCompleteState == 1) {
+ Set qi = zeroedCompleteQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
+
+ zeroedCompleteQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
+ } else {
+ Set qi = zeroedStartQuestItems.get(questId);
+ if(qi == null) {
+ Set newSet = new HashSet<>();
+ newSet.add(currentItemid);
+
+ zeroedStartQuestItems.put(questId, newSet);
+ } else {
+ qi.add(currentItemid);
+ }
+ }
+ }
+ }
+ } catch(Exception e) {}
+ }
+
+ private static void readItemToken(String token) {
+ if(token.contains("/imgdir")) {
+ status -= 1;
+
+ processCurrentItem();
+
+ currentItemid = 0;
+ currentCount = 0;
+ }
+ else if(token.contains("imgdir")) {
+ status += 1;
+ }
+ else {
+ String d = getName(token);
+
+ if(d.equals("id")) {
+ currentItemid = Integer.parseInt(getValue(token));
+ } else if(d.equals("count")) {
+ currentCount = Integer.parseInt(getValue(token));
+ }
+ }
+ }
+
+ private static void translateToken(String token) {
+ String d;
+ int temp;
+
+ 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) {
+ d = getName(token);
+
+ if(d.contains("item")) {
+ temp = status;
+ inspectQuestItemList(temp);
+ }
+ }
+
+ status += 1;
+ }
+
+ }
+
+ private static void calculateQuestItemDiff() {
+ // This will remove started quest items from the "to complete" item set.
+
+ for(Entry> qd : startQuestItems.entrySet()) {
+ for(Integer qi : qd.getValue()) {
+ Set questSet = completeQuestItems.get(qd.getKey());
+
+ if(questSet != null) {
+ if(questSet.remove(qi)) {
+ if(completeQuestItems.isEmpty()) {
+ completeQuestItems.remove(qd.getKey());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static List> getPairsQuestItem() { // quest items not gained at WZ's quest start
+ List> list = new ArrayList<>(initialLength);
+
+ for(Entry> qd : completeQuestItems.entrySet()) {
+ for(Integer qi : qd.getValue()) {
+ list.add(new Pair<>(qi, qd.getKey()));
+ }
+ }
+
+ return list;
+ }
+
+ private static void filterQuestDropsOnDB(List> itemsWithQuest) throws SQLException {
+ List> copyItemsWithQuest = new ArrayList<>(itemsWithQuest);
+ try {
+ for(Pair iq : copyItemsWithQuest) {
+ PreparedStatement ps = con.prepareStatement("SELECT questid FROM drop_data WHERE itemid = ?;");
+ ps.setInt(1, iq.getLeft());
+ ResultSet rs = ps.executeQuery();
+
+ if (rs.isBeforeFirst()) {
+ while(rs.next()) {
+ int curQuest = rs.getInt(1);
+ if(curQuest != iq.getRight()) {
+ int[] mixed = new int[3];
+ mixed[0] = iq.getLeft();
+ mixed[1] = curQuest;
+ mixed[2] = iq.getRight();
+
+ mixedQuestidItems.put(iq.getLeft(), mixed);
+ }
+ }
+
+ itemsWithQuest.remove(iq);
+ }
+
+ rs.close();
+ ps.close();
+ }
+ }
+ catch(SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void filterDirectorySearchMatchingData(String path, List> itemsWithQuest) {
+ Iterator iter = FileUtils.iterateFiles(new File(directoryName + "/" + path), new String[]{"sql", "js", "txt","java"}, true);
+
+ while(iter.hasNext()) {
+ File file = (File) iter.next();
+ fileSearchMatchingData(file, itemsWithQuest);
+ }
+ }
+
+ private static boolean foundMatchingDataOnFile(Scanner scan, String searchStr) {
+ while(scan.hasNext()){
+ String line = scan.nextLine().toLowerCase();
+ if(line.contains(searchStr)){
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ private static void fileSearchMatchingData(File file, List> itemsWithQuest) {
+ try {
+ Scanner scanner = new Scanner(file);
+
+ List> copyItemsWithQuest = new ArrayList<>(itemsWithQuest);
+ for(Pair iq : copyItemsWithQuest) {
+ scanner.reset();
+
+ if(foundMatchingDataOnFile(scanner, String.valueOf(iq.getLeft()))) {
+ itemsWithQuest.remove(iq);
+ }
+ }
+ } catch(FileNotFoundException e) {}
+ }
+
+ private static void printReportFileHeader() {
+ printWriter.println(" # Report File autogenerated from the MapleQuestItemFetcher 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();
+ }
+
+ static private List> getSortedMapEntries0(Map map) {
+ List> list = new ArrayList<>(map.size());
+ for(Entry e : map.entrySet()) {
+ list.add(e);
+ }
+
+ Collections.sort(list, new Comparator>() {
+ @Override
+ public int compare(Entry o1, Entry o2) {
+ return o1.getKey() - o2.getKey();
+ }
+ });
+
+ return list;
+ }
+
+ static private List> getSortedMapEntries1(Map map) {
+ List> list = new ArrayList<>(map.size());
+ for(Entry e : map.entrySet()) {
+ list.add(e);
+ }
+
+ Collections.sort(list, new Comparator>() {
+ @Override
+ public int compare(Entry o1, Entry o2) {
+ return o1.getKey() - o2.getKey();
+ }
+ });
+
+ return list;
+ }
+
+ static private List>> getSortedMapEntries2(Map> map) {
+ List>> list = new ArrayList<>(map.size());
+ for(Entry> e : map.entrySet()) {
+ List il = new ArrayList<>(2);
+ for(Integer i : e.getValue()) {
+ il.add(i);
+ }
+
+ Collections.sort(il, new Comparator() {
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o1 - o2;
+ }
+ });
+
+ list.add(new Pair<>(e.getKey(), il));
+ }
+
+ Collections.sort(list, new Comparator>>() {
+ @Override
+ public int compare(Pair> o1, Pair> o2) {
+ return o1.getLeft() - o2.getLeft();
+ }
+ });
+
+ return list;
+ }
+
+ private static void ReportQuestItemData() {
+ // This will reference one line at a time
+ String line = null;
+
+ try {
+ Class.forName(driver).newInstance();
+
+ System.out.println("Reading WZs...");
+
+ fileReader = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
+ bufferedReader = new BufferedReader(fileReader);
+
+ while((line = bufferedReader.readLine()) != null) {
+ translateToken(line);
+ }
+
+ bufferedReader.close();
+ fileReader.close();
+
+ System.out.println("Calculating table diffs...");
+ calculateQuestItemDiff();
+
+ System.out.println("Filtering drops on DB...");
+ List> itemsWithQuest = getPairsQuestItem();
+
+ // filter drop data on DB
+ con = DriverManager.getConnection(host, username, password);
+ filterQuestDropsOnDB(itemsWithQuest);
+ con.close();
+
+ System.out.println("Filtering drops on project files...");
+ // finally, filter whether this item is mentioned on the source code or not.
+ filterDirectorySearchMatchingData("scripts", itemsWithQuest);
+ filterDirectorySearchMatchingData("sql", itemsWithQuest);
+ filterDirectorySearchMatchingData("src", itemsWithQuest);
+
+ System.out.println("Reporting results...");
+ // 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();
+
+ if(!mixedQuestidItems.isEmpty()) {
+ printWriter.println("INCORRECT QUESTIDS ON DB");
+ for(Entry emqi : getSortedMapEntries1(mixedQuestidItems)) {
+ int[] mqi = emqi.getValue();
+ printWriter.println(mqi[0] + " : " + mqi[1] + " -> " + mqi[2]);
+ }
+ printWriter.println("\n\n\n\n\n");
+ }
+
+ if(!itemsWithQuest.isEmpty()) {
+ Map mapIwq = new HashMap<>(itemsWithQuest.size());
+ for(Pair iwq : itemsWithQuest) {
+ mapIwq.put(iwq.getLeft(), iwq.getRight());
+ }
+
+ printWriter.println("ITEMS WITH NO QUEST DROP DATA ON DB");
+ for(Entry iwq : getSortedMapEntries0(mapIwq)) {
+ printWriter.println(iwq.getKey() + " - " + iwq.getValue());
+ }
+ printWriter.println("\n\n\n\n\n");
+ }
+
+ if(displayExtraInfo) {
+ if(!zeroedStartQuestItems.isEmpty()) {
+ printWriter.println("START QUEST ITEMS WITH ZERO QUANTITY");
+ for(Pair> iwq : getSortedMapEntries2(zeroedStartQuestItems)) {
+ printWriter.println(iwq.getLeft() + ":");
+ for(Integer i : iwq.getRight()) {
+ printWriter.println(" " + i);
+ }
+ printWriter.println();
+ }
+ printWriter.println("\n\n\n\n\n");
+ }
+
+ if(!zeroedCompleteQuestItems.isEmpty()) {
+ printWriter.println("COMPLETE QUEST ITEMS WITH ZERO QUANTITY");
+ for(Pair> iwq : getSortedMapEntries2(zeroedCompleteQuestItems)) {
+ printWriter.println(iwq.getLeft() + ":");
+ for(Integer i : iwq.getRight()) {
+ printWriter.println(" " + i);
+ }
+ printWriter.println();
+ }
+ printWriter.println("\n\n\n\n\n");
+ }
+ }
+
+ printWriter.close();
+ System.out.println("Done!");
+ }
+
+ catch(FileNotFoundException ex) {
+ System.out.println("Unable to open file '" + fileName + "'");
+ }
+ catch(IOException ex) {
+ System.out.println("Error reading file '" + fileName + "'");
+ }
+
+ 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) {
+ System.setProperty("wzpath", wzPath);
+ ii = MapleItemInformationProvider.getInstance();
+
+ ReportQuestItemData();
+ }
+
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleCanvas.java b/tools/MapleQuestItemFetcher/src/provider/MapleCanvas.java
new file mode 100644
index 0000000000..10ab682196
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleCanvas.java
@@ -0,0 +1,30 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+import java.awt.image.BufferedImage;
+
+public interface MapleCanvas {
+ int getHeight();
+ int getWidth();
+ BufferedImage getImage();
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleData.java b/tools/MapleQuestItemFetcher/src/provider/MapleData.java
new file mode 100644
index 0000000000..4d90a93804
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleData.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+import java.util.List;
+import provider.wz.MapleDataType;
+
+public interface MapleData extends MapleDataEntity, Iterable {
+ @Override
+ public String getName();
+ public MapleDataType getType();
+ public List getChildren();
+ public MapleData getChildByPath(String path);
+ public Object getData();
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataDirectoryEntry.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataDirectoryEntry.java
new file mode 100644
index 0000000000..cb043e0c94
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataDirectoryEntry.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+import java.util.List;
+
+/**
+ *
+ * @author Matze
+ */
+public interface MapleDataDirectoryEntry extends MapleDataEntry {
+ public List getSubdirectories();
+ public List getFiles();
+ public MapleDataEntry getEntry(String name);
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataEntity.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataEntity.java
new file mode 100644
index 0000000000..03ff77649c
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataEntity.java
@@ -0,0 +1,31 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+/**
+ *
+ * @author Matze
+ */
+public interface MapleDataEntity {
+ public String getName();
+ public MapleDataEntity getParent();
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataEntry.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataEntry.java
new file mode 100644
index 0000000000..62db6d0abe
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataEntry.java
@@ -0,0 +1,33 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+/**
+ *
+ * @author Matze
+ */
+public interface MapleDataEntry extends MapleDataEntity {
+ public String getName();
+ public int getSize();
+ public int getChecksum();
+ public int getOffset();
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataFileEntry.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataFileEntry.java
new file mode 100644
index 0000000000..902130a612
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataFileEntry.java
@@ -0,0 +1,30 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+/**
+ *
+ * @author Matze
+ */
+public interface MapleDataFileEntry extends MapleDataEntry {
+ public void setOffset(int offset);
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataProvider.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataProvider.java
new file mode 100644
index 0000000000..5237b7ac37
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataProvider.java
@@ -0,0 +1,27 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+public interface MapleDataProvider {
+ MapleData getData(String path);
+ MapleDataDirectoryEntry getRoot();
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataProviderFactory.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataProviderFactory.java
new file mode 100644
index 0000000000..14753d4406
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataProviderFactory.java
@@ -0,0 +1,55 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+import java.io.File;
+import java.io.IOException;
+import provider.wz.WZFile;
+import provider.wz.XMLWZFile;
+
+public class MapleDataProviderFactory {
+ private final static String wzPath = System.getProperty("wzpath");
+
+ private static MapleDataProvider getWZ(File in, boolean provideImages) {
+ if (in.getName().toLowerCase().endsWith("wz") && !in.isDirectory()) {
+ try {
+ return new WZFile(in, provideImages);
+ } catch (IOException e) {
+ throw new RuntimeException("Loading WZ File failed", e);
+ }
+ } else {
+ return new XMLWZFile(in);
+ }
+ }
+
+ public static MapleDataProvider getDataProvider(File in) {
+ return getWZ(in, false);
+ }
+
+ public static MapleDataProvider getImageProvidingDataProvider(File in) {
+ return getWZ(in, true);
+ }
+
+ public static File fileInWZPath(String filename) {
+ return new File(wzPath, filename);
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/provider/MapleDataTool.java b/tools/MapleQuestItemFetcher/src/provider/MapleDataTool.java
new file mode 100644
index 0000000000..25f4c7f817
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/MapleDataTool.java
@@ -0,0 +1,145 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider;
+
+import java.awt.Point;
+import java.awt.image.BufferedImage;
+import provider.wz.MapleDataType;
+
+public class MapleDataTool {
+ public static String getString(MapleData data) {
+ return ((String) data.getData());
+ }
+
+ public static String getString(MapleData data, String def) {
+ if (data == null || data.getData() == null) {
+ return def;
+ } else {
+ return ((String) data.getData());
+ }
+ }
+
+ public static String getString(String path, MapleData data) {
+ return getString(data.getChildByPath(path));
+ }
+
+ public static String getString(String path, MapleData data, String def) {
+ return getString(data.getChildByPath(path), def);
+ }
+
+ public static double getDouble(MapleData data) {
+ return ((Double) data.getData()).doubleValue();
+ }
+
+ public static float getFloat(MapleData data) {
+ return ((Float) data.getData()).floatValue();
+ }
+
+ public static int getInt(MapleData data) {
+ if (data == null || data.getData() == null) {
+ return 0;// DEF?
+ }
+ return ((Integer) data.getData()).intValue();
+ }
+
+ public static int getInt(String path, MapleData data) {
+ return getInt(data.getChildByPath(path));
+ }
+
+ public static int getIntConvert(MapleData data) {
+ if (data.getType() == MapleDataType.STRING) {
+ return Integer.parseInt(getString(data));
+ } else {
+ return getInt(data);
+ }
+ }
+
+ public static int getIntConvert(String path, MapleData data) {
+ MapleData d = data.getChildByPath(path);
+ if (d.getType() == MapleDataType.STRING) {
+ return Integer.parseInt(getString(d));
+ } else {
+ return getInt(d);
+ }
+ }
+
+ public static int getInt(MapleData data, int def) {
+ if (data == null || data.getData() == null) {
+ return def;
+ } else if (data.getType() == MapleDataType.STRING) {
+ return Integer.parseInt(getString(data));
+ } else {
+ return ((Integer) data.getData()).intValue();
+ }
+ }
+
+ public static int getInt(String path, MapleData data, int def) {
+ return getInt(data.getChildByPath(path), def);
+ }
+
+ public static int getIntConvert(String path, MapleData data, int def) {
+ MapleData d = data.getChildByPath(path);
+ if (d == null) {
+ return def;
+ }
+ if (d.getType() == MapleDataType.STRING) {
+ try {
+ return Integer.parseInt(getString(d));
+ } catch (NumberFormatException nfe) {
+ nfe.printStackTrace();
+ return def;
+ }
+ } else {
+ return getInt(d, def);
+ }
+ }
+
+ public static BufferedImage getImage(MapleData data) {
+ return ((MapleCanvas) data.getData()).getImage();
+ }
+
+ public static Point getPoint(MapleData data) {
+ return ((Point) data.getData());
+ }
+
+ public static Point getPoint(String path, MapleData data) {
+ return getPoint(data.getChildByPath(path));
+ }
+
+ public static Point getPoint(String path, MapleData data, Point def) {
+ final MapleData pointData = data.getChildByPath(path);
+ if (pointData == null) {
+ return def;
+ }
+ return getPoint(pointData);
+ }
+
+ public static String getFullDataPath(MapleData data) {
+ String path = "";
+ MapleDataEntity myData = data;
+ while (myData != null) {
+ path = myData.getName() + "/" + path;
+ myData = myData.getParent();
+ }
+ return path.substring(0, path.length() - 1);
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/FileStoredPngMapleCanvas.java b/tools/MapleQuestItemFetcher/src/provider/wz/FileStoredPngMapleCanvas.java
new file mode 100644
index 0000000000..21736c2c16
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/FileStoredPngMapleCanvas.java
@@ -0,0 +1,70 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+import provider.MapleCanvas;
+
+public class FileStoredPngMapleCanvas implements MapleCanvas {
+ private File file;
+ private int width;
+ private int height;
+ private BufferedImage image;
+
+ public FileStoredPngMapleCanvas(int width, int height, File fileIn) {
+ this.width = width;
+ this.height = height;
+ this.file = fileIn;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ loadImageIfNecessary();
+ return image;
+ }
+
+ private void loadImageIfNecessary() {
+ if (image == null) {
+ try {
+ image = ImageIO.read(file);
+ // replace the dimensions loaded from the wz by the REAL dimensions from the image - should be equal tho
+ width = image.getWidth();
+ height = image.getHeight();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/ImgMapleSound.java b/tools/MapleQuestItemFetcher/src/provider/wz/ImgMapleSound.java
new file mode 100644
index 0000000000..8add2ccb36
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/ImgMapleSound.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+public class ImgMapleSound {
+ private int dataLength, offset;
+
+ public ImgMapleSound(int dataLength, int offset) {
+ this.dataLength = dataLength;
+ this.offset = offset;
+ }
+
+ public int getDataLength() {
+ return dataLength;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/ListWZFile.java b/tools/MapleQuestItemFetcher/src/provider/wz/ListWZFile.java
new file mode 100644
index 0000000000..1672a08c59
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/ListWZFile.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import provider.MapleDataProviderFactory;
+import tools.data.input.GenericLittleEndianAccessor;
+import tools.data.input.InputStreamByteStream;
+import tools.data.input.LittleEndianAccessor;
+
+public class ListWZFile {
+ private LittleEndianAccessor lea;
+ private List entries = new ArrayList();
+ private static Collection modernImgs = new HashSet();
+
+ public static byte[] xorBytes(byte[] a, byte[] b) {
+ byte[] wusched = new byte[a.length];
+ for (int i = 0; i < a.length; i++) {
+ wusched[i] = (byte) (a[i] ^ b[i]);
+ }
+ return wusched;
+ }
+
+ public ListWZFile(File listwz) throws FileNotFoundException {
+ lea = new GenericLittleEndianAccessor(new InputStreamByteStream(new BufferedInputStream(new FileInputStream(listwz))));
+ while (lea.available() > 0) {
+ int l = lea.readInt() * 2;
+ byte[] chunk = new byte[l];
+ for (int i = 0; i < chunk.length; i++) {
+ chunk[i] = lea.readByte();
+ }
+ lea.readChar();
+ final String value = String.valueOf(WZTool.readListString(chunk));
+ entries.add(value);
+ }
+ entries = Collections.unmodifiableList(entries);
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public static void init() {
+ final String listWz = System.getProperty("listwz");
+ if (listWz != null) {
+ ListWZFile listwz;
+ try {
+ listwz = new ListWZFile(MapleDataProviderFactory.fileInWZPath("List.wz"));
+ modernImgs = new HashSet(listwz.getEntries());
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static boolean isModernImgFile(String path) {
+ return modernImgs.contains(path);
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/MapleDataType.java b/tools/MapleQuestItemFetcher/src/provider/wz/MapleDataType.java
new file mode 100644
index 0000000000..e074d57d14
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/MapleDataType.java
@@ -0,0 +1,26 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+public enum MapleDataType {
+ NONE, IMG_0x00, SHORT, INT, FLOAT, DOUBLE, STRING, EXTENDED, PROPERTY, CANVAS, VECTOR, CONVEX, SOUND, UOL, UNKNOWN_TYPE, UNKNOWN_EXTENDED_TYPE;
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/PNGMapleCanvas.java b/tools/MapleQuestItemFetcher/src/provider/wz/PNGMapleCanvas.java
new file mode 100644
index 0000000000..97c2303804
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/PNGMapleCanvas.java
@@ -0,0 +1,151 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.awt.Point;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+import provider.MapleCanvas;
+
+public class PNGMapleCanvas implements MapleCanvas {
+ private static final int[] ZAHLEN = new int[]{2, 1, 0, 3};
+ private int height;
+ private int width;
+ private int dataLength;
+ private int format;
+ private byte[] data;
+
+ public PNGMapleCanvas(int width, int height, int dataLength, int format, byte[] data) {
+ super();
+ this.height = height;
+ this.width = width;
+ this.dataLength = dataLength;
+ this.format = format;
+ this.data = data;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getFormat() {
+ return format;
+ }
+
+ private byte[] getData() {
+ return data;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ int sizeUncompressed = 0;
+ int size8888 = 0;
+ int maxWriteBuf = 2;
+ int maxHeight = 3;
+ byte[] writeBuf = new byte[maxWriteBuf];
+ @SuppressWarnings ("unused")
+ byte[] rowPointers = new byte[maxHeight];
+ switch (getFormat()) {
+ case 1:
+ case 513:
+ sizeUncompressed = getHeight() * getWidth() * 4;
+ break;
+ case 2:
+ sizeUncompressed = getHeight() * getWidth() * 8;
+ break;
+ case 517:
+ sizeUncompressed = getHeight() * getWidth() / 128;
+ break;
+ }
+ size8888 = getHeight() * getWidth() * 8;
+ if (size8888 > maxWriteBuf) {
+ maxWriteBuf = size8888;
+ writeBuf = new byte[maxWriteBuf];
+ }
+ if (getHeight() > maxHeight) {
+ maxHeight = getHeight();
+ rowPointers = new byte[maxHeight];
+ }
+ Inflater dec = new Inflater();
+ dec.setInput(getData(), 0, dataLength);
+ int declen = 0;
+ byte[] uc = new byte[sizeUncompressed];
+ try {
+ declen = dec.inflate(uc);
+ } catch (DataFormatException ex) {
+ throw new RuntimeException("zlib fucks", ex);
+ }
+ dec.end();
+ if (getFormat() == 1) {
+ for (int i = 0; i < sizeUncompressed; i++) {
+ byte low = (byte) (uc[i] & 0x0F);
+ byte high = (byte) (uc[i] & 0xF0);
+ writeBuf[(i << 1)] = (byte) (((low << 4) | low) & 0xFF);
+ writeBuf[(i << 1) + 1] = (byte) (high | ((high >>> 4) & 0xF));
+ }
+ } else if (getFormat() == 2) {
+ writeBuf = uc;
+ } else if (getFormat() == 513) {
+ for (int i = 0; i < declen; i += 2) {
+ byte bBits = (byte) ((uc[i] & 0x1F) << 3);
+ byte gBits = (byte) (((uc[i + 1] & 0x07) << 5) | ((uc[i] & 0xE0) >> 3));
+ byte rBits = (byte) (uc[i + 1] & 0xF8);
+ writeBuf[(i << 1)] = (byte) (bBits | (bBits >> 5));
+ writeBuf[(i << 1) + 1] = (byte) (gBits | (gBits >> 6));
+ writeBuf[(i << 1) + 2] = (byte) (rBits | (rBits >> 5));
+ writeBuf[(i << 1) + 3] = (byte) 0xFF;
+ }
+ } else if (getFormat() == 517) {
+ byte b = 0x00;
+ int pixelIndex = 0;
+ for (int i = 0; i < declen; i++) {
+ for (int j = 0; j < 8; j++) {
+ b = (byte) (((uc[i] & (0x01 << (7 - j))) >> (7 - j)) * 255);
+ for (int k = 0; k < 16; k++) {
+ pixelIndex = (i << 9) + (j << 6) + k * 2;
+ writeBuf[pixelIndex] = b;
+ writeBuf[pixelIndex + 1] = b;
+ writeBuf[pixelIndex + 2] = b;
+ writeBuf[pixelIndex + 3] = (byte) 0xFF;
+ }
+ }
+ }
+ }
+ DataBufferByte imgData = new DataBufferByte(writeBuf, sizeUncompressed);
+ SampleModel sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, getWidth(), getHeight(), 4, getWidth() * 4, ZAHLEN);
+ WritableRaster imgRaster = Raster.createWritableRaster(sm, imgData, new Point(0, 0));
+ BufferedImage aa = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
+ aa.setData(imgRaster);
+ return aa;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZDirectoryEntry.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZDirectoryEntry.java
new file mode 100644
index 0000000000..d24b8cb2b9
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZDirectoryEntry.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import provider.MapleDataDirectoryEntry;
+import provider.MapleDataEntity;
+import provider.MapleDataEntry;
+import provider.MapleDataFileEntry;
+
+public class WZDirectoryEntry extends WZEntry implements MapleDataDirectoryEntry {
+ private List subdirs = new ArrayList();
+ private List files = new ArrayList();
+ private Map entries = new HashMap();
+
+ public WZDirectoryEntry(String name, int size, int checksum, MapleDataEntity parent) {
+ super(name, size, checksum, parent);
+ }
+
+ public WZDirectoryEntry() {
+ super(null, 0, 0, null);
+ }
+
+ public void addDirectory(MapleDataDirectoryEntry dir) {
+ subdirs.add(dir);
+ entries.put(dir.getName(), dir);
+ }
+
+ public void addFile(MapleDataFileEntry fileEntry) {
+ files.add(fileEntry);
+ entries.put(fileEntry.getName(), fileEntry);
+ }
+
+ public List getSubdirectories() {
+ return Collections.unmodifiableList(subdirs);
+ }
+
+ public List getFiles() {
+ return Collections.unmodifiableList(files);
+ }
+
+ public MapleDataEntry getEntry(String name) {
+ return entries.get(name);
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZEntry.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZEntry.java
new file mode 100644
index 0000000000..1e921b2082
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZEntry.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import provider.MapleDataEntity;
+import provider.MapleDataEntry;
+
+public class WZEntry implements MapleDataEntry {
+ private String name;
+ private int size;
+ private int checksum;
+ private int offset;
+ private MapleDataEntity parent;
+
+ public WZEntry(String name, int size, int checksum, MapleDataEntity parent) {
+ super();
+ this.name = name;
+ this.size = size;
+ this.checksum = checksum;
+ this.parent = parent;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public int getChecksum() {
+ return checksum;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public MapleDataEntity getParent() {
+ return parent;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZFile.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZFile.java
new file mode 100644
index 0000000000..c6c0abf537
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZFile.java
@@ -0,0 +1,154 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import provider.MapleData;
+import provider.MapleDataDirectoryEntry;
+import provider.MapleDataFileEntry;
+import provider.MapleDataProvider;
+import tools.data.input.GenericLittleEndianAccessor;
+import tools.data.input.GenericSeekableLittleEndianAccessor;
+import tools.data.input.InputStreamByteStream;
+import tools.data.input.LittleEndianAccessor;
+import tools.data.input.RandomAccessByteStream;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class WZFile implements MapleDataProvider {
+ static {
+ ListWZFile.init();
+ }
+ private File wzfile;
+ private LittleEndianAccessor lea;
+ private SeekableLittleEndianAccessor slea;
+ private int headerSize;
+ private WZDirectoryEntry root;
+ private boolean provideImages;
+ private int cOffset;
+
+ public WZFile(File wzfile, boolean provideImages) throws IOException {
+ this.wzfile = wzfile;
+ lea = new GenericLittleEndianAccessor(new InputStreamByteStream(new BufferedInputStream(new FileInputStream(wzfile))));
+ RandomAccessFile raf = new RandomAccessFile(wzfile, "r");
+ slea = new GenericSeekableLittleEndianAccessor(new RandomAccessByteStream(raf));
+ root = new WZDirectoryEntry(wzfile.getName(), 0, 0, null);
+ this.provideImages = provideImages;
+ load();
+ }
+
+ private void load() throws IOException {
+ lea.readAsciiString(4);
+ lea.readInt();
+ lea.readInt();
+ headerSize = lea.readInt();
+ lea.readNullTerminatedAsciiString();
+ lea.readShort();
+ parseDirectory(root);
+ cOffset = (int) lea.getBytesRead();
+ getOffsets(root);
+ }
+
+ private void getOffsets(MapleDataDirectoryEntry dir) {
+ for (MapleDataFileEntry file : dir.getFiles()) {
+ file.setOffset(cOffset);
+ cOffset += file.getSize();
+ }
+ for (MapleDataDirectoryEntry sdir : dir.getSubdirectories()) {
+ getOffsets(sdir);
+ }
+ }
+
+ private void parseDirectory(WZDirectoryEntry dir) {
+ int entries = WZTool.readValue(lea);
+ for (int i = 0; i < entries; i++) {
+ byte marker = lea.readByte();
+ String name = null;
+ int size, checksum;
+ switch (marker) {
+ case 0x02:
+ name = WZTool.readDecodedStringAtOffsetAndReset(slea, lea.readInt() + this.headerSize + 1);
+ size = WZTool.readValue(lea);
+ checksum = WZTool.readValue(lea);
+ lea.readInt(); //dummy int
+ dir.addFile(new WZFileEntry(name, size, checksum, dir));
+ break;
+ case 0x03:
+ case 0x04:
+ name = WZTool.readDecodedString(lea);
+ size = WZTool.readValue(lea);
+ checksum = WZTool.readValue(lea);
+ lea.readInt(); //dummy int
+ if (marker == 3) {
+ dir.addDirectory(new WZDirectoryEntry(name, size, checksum, dir));
+ } else {
+ dir.addFile(new WZFileEntry(name, size, checksum, dir));
+ }
+ break;
+ default:
+ }
+ }
+ for (MapleDataDirectoryEntry idir : dir.getSubdirectories()) {
+ parseDirectory((WZDirectoryEntry) idir);
+ }
+ }
+
+ public WZIMGFile getImgFile(String path) throws IOException {
+ String segments[] = path.split("/");
+ WZDirectoryEntry dir = root;
+ for (int x = 0; x < segments.length - 1; x++) {
+ dir = (WZDirectoryEntry) dir.getEntry(segments[x]);
+ if (dir == null) {
+ return null;
+ }
+ }
+ WZFileEntry entry = (WZFileEntry) dir.getEntry(segments[segments.length - 1]);
+ if (entry == null) {
+ return null;
+ }
+ String fullPath = wzfile.getName().substring(0, wzfile.getName().length() - 3).toLowerCase() + "/" + path;
+ return new WZIMGFile(this.wzfile, entry, provideImages, ListWZFile.isModernImgFile(fullPath));
+ }
+
+ @Override
+ public synchronized MapleData getData(String path) {
+ try {
+ WZIMGFile imgFile = getImgFile(path);
+ if (imgFile == null) {
+ return null;
+ }
+ MapleData ret = imgFile.getRoot();
+ return ret;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public MapleDataDirectoryEntry getRoot() {
+ return root;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZFileEntry.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZFileEntry.java
new file mode 100644
index 0000000000..792371d9cf
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZFileEntry.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import provider.MapleDataEntity;
+import provider.MapleDataFileEntry;
+
+public class WZFileEntry extends WZEntry implements MapleDataFileEntry {
+ private int offset;
+
+ public WZFileEntry(String name, int size, int checksum, MapleDataEntity parent) {
+ super(name, size, checksum, parent);
+ }
+
+ @Override
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGEntry.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGEntry.java
new file mode 100644
index 0000000000..385d785183
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGEntry.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import provider.MapleData;
+import provider.MapleDataEntity;
+
+public class WZIMGEntry implements MapleData {
+ private String name;
+ private MapleDataType type;
+ private List children = new ArrayList(10);
+ private Object data;
+ private MapleDataEntity parent;
+
+ public WZIMGEntry(MapleDataEntity parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public MapleDataType getType() {
+ return type;
+ }
+
+ @Override
+ public List getChildren() {
+ return Collections.unmodifiableList(children);
+ }
+
+ @Override
+ public MapleData getChildByPath(String path) {
+ String segments[] = path.split("/");
+ if (segments[0].equals("..")) {
+ return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
+ }
+ MapleData ret = this;
+ for (int x = 0; x < segments.length; x++) {
+ boolean foundChild = false;
+ for (MapleData child : ret.getChildren()) {
+ if (child.getName().equals(segments[x])) {
+ ret = child;
+ foundChild = true;
+ break;
+ }
+ }
+ if (!foundChild) {
+ return null;
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public Object getData() {
+ return data;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setType(MapleDataType type) {
+ this.type = type;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ public void addChild(WZIMGEntry entry) {
+ children.add(entry);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return getChildren().iterator();
+ }
+
+ @Override
+ public String toString() {
+ return getName() + ":" + getData();
+ }
+
+ public MapleDataEntity getParent() {
+ return parent;
+ }
+
+ public void finish() {
+ ((ArrayList) children).trimToSize();
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGFile.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGFile.java
new file mode 100644
index 0000000000..bec06c78bd
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZIMGFile.java
@@ -0,0 +1,227 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.awt.Point;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import tools.data.input.GenericSeekableLittleEndianAccessor;
+import tools.data.input.RandomAccessByteStream;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+public class WZIMGFile {
+ private WZFileEntry file;
+ private WZIMGEntry root;
+ private boolean provideImages;
+ @SuppressWarnings ("unused")
+ private boolean modernImg;
+
+ public WZIMGFile(File wzfile, WZFileEntry file, boolean provideImages, boolean modernImg) throws IOException {
+ RandomAccessFile raf = new RandomAccessFile(wzfile, "r");
+ SeekableLittleEndianAccessor slea = new GenericSeekableLittleEndianAccessor(new RandomAccessByteStream(raf));
+ slea.seek(file.getOffset());
+ this.file = file;
+ this.provideImages = provideImages;
+ root = new WZIMGEntry(file.getParent());
+ root.setName(file.getName());
+ root.setType(MapleDataType.EXTENDED);
+ this.modernImg = modernImg;
+ parseExtended(root, slea, 0);
+ root.finish();
+ raf.close();
+ }
+
+ protected void dumpImg(OutputStream out, SeekableLittleEndianAccessor slea) throws IOException {
+ DataOutputStream os = new DataOutputStream(out);
+ long oldPos = slea.getPosition();
+ slea.seek(file.getOffset());
+ for (int x = 0; x < file.getSize(); x++) {
+ os.write(slea.readByte());
+ }
+ slea.seek(oldPos);
+ }
+
+ public WZIMGEntry getRoot() {
+ return root;
+ }
+
+ private void parse(WZIMGEntry entry, SeekableLittleEndianAccessor slea) {
+ byte marker = slea.readByte();
+ switch (marker) {
+ case 0: {
+ String name = WZTool.readDecodedString(slea);
+ entry.setName(name);
+ break;
+ }
+ case 1: {
+ String name = WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt());
+ entry.setName(name);
+ break;
+ }
+ default:
+ System.out.println("Unknown Image identifier: " + marker + " at offset " + (slea.getPosition() - file.getOffset()));
+ }
+ marker = slea.readByte();
+ switch (marker) {
+ case 0:
+ entry.setType(MapleDataType.IMG_0x00);
+ break;
+ case 2:
+ case 11: //??? no idea, since 0.49
+ entry.setType(MapleDataType.SHORT);
+ entry.setData(Short.valueOf(slea.readShort()));
+ break;
+ case 3:
+ entry.setType(MapleDataType.INT);
+ entry.setData(Integer.valueOf(WZTool.readValue(slea)));
+ break;
+ case 4:
+ entry.setType(MapleDataType.FLOAT);
+ entry.setData(Float.valueOf(WZTool.readFloatValue(slea)));
+ break;
+ case 5:
+ entry.setType(MapleDataType.DOUBLE);
+ entry.setData(Double.valueOf(slea.readDouble()));
+ break;
+ case 8:
+ entry.setType(MapleDataType.STRING);
+ byte iMarker = slea.readByte();
+ if (iMarker == 0) {
+ entry.setData(WZTool.readDecodedString(slea));
+ } else if (iMarker == 1) {
+ entry.setData(WZTool.readDecodedStringAtOffsetAndReset(slea, slea.readInt() + file.getOffset()));
+ } else {
+ System.out.println("Unknown String type " + iMarker);
+ }
+ break;
+ case 9:
+ entry.setType(MapleDataType.EXTENDED);
+ long endOfExtendedBlock = slea.readInt();
+ endOfExtendedBlock += slea.getPosition();
+ parseExtended(entry, slea, endOfExtendedBlock);
+ break;
+ default:
+ System.out.println("Unknown Image type " + marker);
+ }
+ }
+
+ private void parseExtended(WZIMGEntry entry, SeekableLittleEndianAccessor slea, long endOfExtendedBlock) {
+ byte marker = slea.readByte();
+ String type;
+ switch (marker) {
+ case 0x73:
+ type = WZTool.readDecodedString(slea);
+ break;
+ case 0x1B:
+ type = WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt());
+ break;
+ default:
+ throw new RuntimeException("Unknown extended image identifier: " + marker + " at offset " +
+ (slea.getPosition() - file.getOffset()));
+ }
+ if (type.equals("Property")) {
+ entry.setType(MapleDataType.PROPERTY);
+ slea.readByte();
+ slea.readByte();
+ int children = WZTool.readValue(slea);
+ for (int i = 0; i < children; i++) {
+ WZIMGEntry cEntry = new WZIMGEntry(entry);
+ parse(cEntry, slea);
+ cEntry.finish();
+ entry.addChild(cEntry);
+ }
+ } else if (type.equals("Canvas")) {
+ entry.setType(MapleDataType.CANVAS);
+ slea.readByte();
+ marker = slea.readByte();
+ if (marker == 0) {
+ // do nothing
+ } else if (marker == 1) {
+ slea.readByte();
+ slea.readByte();
+ int children = WZTool.readValue(slea);
+ for (int i = 0; i < children; i++) {
+ WZIMGEntry child = new WZIMGEntry(entry);
+ parse(child, slea);
+ child.finish();
+ entry.addChild(child);
+ }
+ } else {
+ System.out.println("Canvas marker != 1 (" + marker + ")");
+ }
+ int width = WZTool.readValue(slea);
+ int height = WZTool.readValue(slea);
+ int format = WZTool.readValue(slea);
+ int format2 = slea.readByte();
+ slea.readInt();
+ int dataLength = slea.readInt() - 1;
+ slea.readByte();
+ if (provideImages) {
+ byte[] pngdata = slea.read(dataLength);
+ entry.setData(new PNGMapleCanvas(width, height, dataLength, format + format2, pngdata));
+ } else {
+ entry.setData(new PNGMapleCanvas(width, height, dataLength, format + format2, null));
+ slea.skip(dataLength);
+ }
+ } else if (type.equals("Shape2D#Vector2D")) {
+ entry.setType(MapleDataType.VECTOR);
+ int x = WZTool.readValue(slea);
+ int y = WZTool.readValue(slea);
+ entry.setData(new Point(x, y));
+ } else if (type.equals("Shape2D#Convex2D")) {
+ int children = WZTool.readValue(slea);
+ for (int i = 0; i < children; i++) {
+ WZIMGEntry cEntry = new WZIMGEntry(entry);
+ parseExtended(cEntry, slea, 0);
+ cEntry.finish();
+ entry.addChild(cEntry);
+ }
+ } else if (type.equals("Sound_DX8")) {
+ entry.setType(MapleDataType.SOUND);
+ slea.readByte();
+ int dataLength = WZTool.readValue(slea);
+ WZTool.readValue(slea); // no clue what this is
+ int offset = (int) slea.getPosition();
+ entry.setData(new ImgMapleSound(dataLength, offset - file.getOffset()));
+ slea.seek(endOfExtendedBlock);
+ } else if (type.equals("UOL")) {
+ entry.setType(MapleDataType.UOL);
+ slea.readByte();
+ byte uolmarker = slea.readByte();
+ switch (uolmarker) {
+ case 0:
+ entry.setData(WZTool.readDecodedString(slea));
+ break;
+ case 1:
+ entry.setData(WZTool.readDecodedStringAtOffsetAndReset(slea, file.getOffset() + slea.readInt()));
+ break;
+ default:
+ System.out.println("Unknown UOL marker: " + uolmarker + " " + entry.getName());
+ }
+ } else {
+ throw new RuntimeException("Unhandled extended type: " + type);
+ }
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/WZTool.java b/tools/MapleQuestItemFetcher/src/provider/wz/WZTool.java
new file mode 100644
index 0000000000..85e1c8d90b
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/WZTool.java
@@ -0,0 +1,187 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import tools.data.input.LittleEndianAccessor;
+import tools.data.input.SeekableLittleEndianAccessor;
+
+/*
+ * Ported Code, see WZFile.java for more info
+ */
+public class WZTool {
+ private static byte[] encKey;
+
+ static {
+ byte[] iv = new byte[]{(byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
+ (byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
+ (byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,
+ (byte) 0x4d, (byte) 0x23, (byte) 0xc7, (byte) 0x2b,};
+ byte[] key = new byte[]{(byte) 0x13, 0x00, 0x00, 0x00,
+ (byte) 0x08, 0x00, 0x00, 0x00,
+ (byte) 0x06, 0x00, 0x00, 0x00,
+ (byte) 0xB4, 0x00, 0x00, 0x00,
+ (byte) 0x1B, 0x00, 0x00, 0x00,
+ (byte) 0x0F, 0x00, 0x00, 0x00,
+ (byte) 0x33, 0x00, 0x00, 0x00,
+ (byte) 0x52, 0x00, 0x00, 0x00
+ };
+ Cipher cipher = null;
+ SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
+ try {
+ cipher = Cipher.getInstance("AES");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ }
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ encKey = new byte[0xFFFF];
+ for (int i = 0; i < (0xFFFF / 16); i++) {
+ try {
+ iv = cipher.doFinal(iv);
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ }
+ System.arraycopy(iv, 0, encKey, (i * 16), 16);
+ }
+ try {
+ iv = cipher.doFinal(iv);
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ }
+ System.arraycopy(iv, 0, encKey, 65520, 15);
+ }
+
+ public static byte[] readListString(byte[] str) {
+ for (int i = 0; i < str.length; i++) {
+ str[i] = (byte) (str[i] ^ encKey[i]);
+ }
+ return str;
+ }
+
+ public static String readDecodedString(LittleEndianAccessor llea) {
+ int strLength;
+ byte b = llea.readByte();
+ if (b == 0x00) {
+ return "";
+ }
+ if (b >= 0) {
+ if (b == 0x7F) {
+ strLength = llea.readInt();
+ } else {
+ strLength = (int) b;
+ }
+ if (strLength < 0) {
+ return "";
+ }
+ byte str[] = new byte[strLength * 2];
+ for (int i = 0; i < strLength * 2; i++) {
+ str[i] = llea.readByte();
+ }
+ return DecryptUnicodeStr(str);
+ } else {
+ if (b == -128) {
+ strLength = llea.readInt();
+ } else {
+ strLength = -b;
+ }
+ if (strLength < 0) {
+ return "";
+ }
+ byte str[] = new byte[strLength];
+ for (int i = 0; i < strLength; i++) {
+ str[i] = llea.readByte();
+ }
+ return DecryptAsciiStr(str);
+ }
+ }
+
+ public static String DecryptAsciiStr(byte[] str) {
+ byte xorByte = (byte) 0xAA;
+ for (int i = 0; i < str.length; i++) {
+ str[i] = (byte) (str[i] ^ xorByte ^ encKey[i]);
+ xorByte++;
+ }
+ return new String(str);
+ }
+
+ public static String DecryptUnicodeStr(byte[] str) {
+ int xorByte = 0xAAAA;
+ char[] charRet = new char[str.length / 2];
+ for (int i = 0; i < str.length; i++) {
+ str[i] = (byte) (str[i] ^ encKey[i]);
+ }
+ for (int i = 0; i < (str.length / 2); i++) {
+ char toXor = (char) ((str[i] << 8) | str[i + 1]);
+ charRet[i] = (char) (toXor ^ xorByte);
+ xorByte++;
+ }
+ return String.valueOf(charRet);
+ }
+
+ public static String readDecodedStringAtOffset(SeekableLittleEndianAccessor slea, int offset) {
+ slea.seek(offset);
+ return readDecodedString(slea);
+ }
+
+ public static String readDecodedStringAtOffsetAndReset(SeekableLittleEndianAccessor slea, int offset) {
+ long pos = 0;
+ pos = slea.getPosition();
+ slea.seek(offset);
+ String ret = readDecodedString(slea);
+ slea.seek(pos);
+ return ret;
+ }
+
+ public static int readValue(LittleEndianAccessor lea) {
+ byte b = lea.readByte();
+ if (b == -128) {
+ return lea.readInt();
+ } else {
+ return ((int) b);
+ }
+ }
+
+ public static float readFloatValue(LittleEndianAccessor lea) {
+ byte b = lea.readByte();
+ if (b == -128) {
+ return lea.readFloat();
+ } else {
+ return 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/XMLDomMapleData.java b/tools/MapleQuestItemFetcher/src/provider/wz/XMLDomMapleData.java
new file mode 100644
index 0000000000..151a04c2fd
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/XMLDomMapleData.java
@@ -0,0 +1,219 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.awt.Point;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.text.NumberFormat;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import provider.MapleData;
+import provider.MapleDataEntity;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class XMLDomMapleData implements MapleData {
+ private Node node;
+ private File imageDataDir;
+ private NumberFormat nf;
+
+ public XMLDomMapleData(FileInputStream fis, File imageDataDir) {
+ try {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.parse(fis);
+ this.node = document.getFirstChild();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ this.imageDataDir = imageDataDir;
+ this.nf = NumberFormat.getInstance(Locale.FRANCE);
+ }
+
+ private XMLDomMapleData(Node node) {
+ this.node = node;
+ this.nf = NumberFormat.getInstance(Locale.FRANCE);
+ }
+
+ @Override
+ public MapleData getChildByPath(String path) {
+ String segments[] = path.split("/");
+ if (segments[0].equals("..")) {
+ return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
+ }
+
+ Node myNode = node;
+ for (int x = 0; x < segments.length; x++) {
+ NodeList childNodes = myNode.getChildNodes();
+ boolean foundChild = false;
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) {
+ myNode = childNode;
+ foundChild = true;
+ break;
+ }
+ }
+ if (!foundChild) {
+ return null;
+ }
+ }
+ XMLDomMapleData ret = new XMLDomMapleData(myNode);
+ ret.imageDataDir = new File(imageDataDir, getName() + "/" + path).getParentFile();
+ return ret;
+ }
+
+ @Override
+ public List getChildren() {
+ List ret = new ArrayList();
+ NodeList childNodes = node.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ XMLDomMapleData child = new XMLDomMapleData(childNode);
+ child.imageDataDir = new File(imageDataDir, getName());
+ ret.add(child);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public Object getData() {
+ NamedNodeMap attributes = node.getAttributes();
+ MapleDataType type = getType();
+ switch (type) {
+ case DOUBLE:
+ case FLOAT:
+ case INT:
+ case SHORT: {
+ String value = attributes.getNamedItem("value").getNodeValue();
+ Number nval;
+
+ try {
+ nval = nf.parse(value);
+ }
+ catch(java.text.ParseException pe) {
+ pe.printStackTrace();
+ nval = 0.0f;
+ }
+
+ switch (type) {
+ case DOUBLE:
+ return nval.doubleValue();
+ case FLOAT:
+ return nval.floatValue();
+ case INT:
+ return nval.intValue();
+ case SHORT:
+ return nval.shortValue();
+ default:
+ return null;
+ }
+ }
+ case STRING:
+ case UOL: {
+ String value = attributes.getNamedItem("value").getNodeValue();
+ return value;
+ }
+ case VECTOR: {
+ String x = attributes.getNamedItem("x").getNodeValue();
+ String y = attributes.getNamedItem("y").getNodeValue();
+ return new Point(Integer.parseInt(x), Integer.parseInt(y));
+ }
+ case CANVAS: {
+ String width = attributes.getNamedItem("width").getNodeValue();
+ String height = attributes.getNamedItem("height").getNodeValue();
+ return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File(
+ imageDataDir, getName() + ".png"));
+ }
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public MapleDataType getType() {
+ String nodeName = node.getNodeName();
+ if (nodeName.equals("imgdir")) {
+ return MapleDataType.PROPERTY;
+ } else if (nodeName.equals("canvas")) {
+ return MapleDataType.CANVAS;
+ } else if (nodeName.equals("convex")) {
+ return MapleDataType.CONVEX;
+ } else if (nodeName.equals("sound")) {
+ return MapleDataType.SOUND;
+ } else if (nodeName.equals("uol")) {
+ return MapleDataType.UOL;
+ } else if (nodeName.equals("double")) {
+ return MapleDataType.DOUBLE;
+ } else if (nodeName.equals("float")) {
+ return MapleDataType.FLOAT;
+ } else if (nodeName.equals("int")) {
+ return MapleDataType.INT;
+ } else if (nodeName.equals("short")) {
+ return MapleDataType.SHORT;
+ } else if (nodeName.equals("string")) {
+ return MapleDataType.STRING;
+ } else if (nodeName.equals("vector")) {
+ return MapleDataType.VECTOR;
+ } else if (nodeName.equals("null")) {
+ return MapleDataType.IMG_0x00;
+ }
+ return null;
+ }
+
+ @Override
+ public MapleDataEntity getParent() {
+ Node parentNode = node.getParentNode();
+ if (parentNode.getNodeType() == Node.DOCUMENT_NODE) {
+ return null;
+ }
+ XMLDomMapleData parentData = new XMLDomMapleData(parentNode);
+ parentData.imageDataDir = imageDataDir.getParentFile();
+ return parentData;
+ }
+
+ @Override
+ public String getName() {
+ return node.getAttributes().getNamedItem("name").getNodeValue();
+ }
+
+ @Override
+ public Iterator iterator() {
+ return getChildren().iterator();
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/provider/wz/XMLWZFile.java b/tools/MapleQuestItemFetcher/src/provider/wz/XMLWZFile.java
new file mode 100644
index 0000000000..2a7694fdc9
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/provider/wz/XMLWZFile.java
@@ -0,0 +1,85 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 provider.wz;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import provider.MapleData;
+import provider.MapleDataDirectoryEntry;
+import provider.MapleDataProvider;
+
+public class XMLWZFile implements MapleDataProvider {
+ private File root;
+ private WZDirectoryEntry rootForNavigation;
+
+ public XMLWZFile(File fileIn) {
+ root = fileIn;
+ rootForNavigation = new WZDirectoryEntry(fileIn.getName(), 0, 0, null);
+ fillMapleDataEntitys(root, rootForNavigation);
+ }
+
+ private void fillMapleDataEntitys(File lroot, WZDirectoryEntry wzdir) {
+ for (File file : lroot.listFiles()) {
+ String fileName = file.getName();
+ if (file.isDirectory() && !fileName.endsWith(".img")) {
+ WZDirectoryEntry newDir = new WZDirectoryEntry(fileName, 0, 0, wzdir);
+ wzdir.addDirectory(newDir);
+ fillMapleDataEntitys(file, newDir);
+ } else if (fileName.endsWith(".xml")) {
+ wzdir.addFile(new WZFileEntry(fileName.substring(0, fileName.length() - 4), 0, 0, wzdir));
+ }
+ }
+ }
+
+ @Override
+ public MapleData getData(String path) {
+ File dataFile = new File(root, path + ".xml");
+ File imageDataDir = new File(root, path);
+ if (!dataFile.exists()) {
+ return null;//bitches
+ }
+ FileInputStream fis;
+ try {
+ fis = new FileInputStream(dataFile);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("Datafile " + path + " does not exist in " + root.getAbsolutePath());
+ }
+ final XMLDomMapleData domMapleData;
+ try {
+ domMapleData = new XMLDomMapleData(fis, imageDataDir.getParentFile());
+ } finally {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return domMapleData;
+ }
+
+ @Override
+ public MapleDataDirectoryEntry getRoot() {
+ return rootForNavigation;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/ArrayMap.java b/tools/MapleQuestItemFetcher/src/tools/ArrayMap.java
new file mode 100644
index 0000000000..c08508f7e3
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/ArrayMap.java
@@ -0,0 +1,149 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class ArrayMap extends AbstractMap {
+
+ static class Entry implements Map.Entry {
+ protected K key;
+ protected V value;
+
+ public Entry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public V getValue() {
+ return value;
+ }
+
+ @Override
+ public V setValue(V newValue) {
+ V oldValue = value;
+ value = newValue;
+ return oldValue;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map.Entry, ?>)) {
+ return false;
+ }
+ Map.Entry, ?> e = (Map.Entry, ?>) o;
+ return (key == null ? e.getKey() == null : key.equals(e.getKey())) && (value == null ? e.getValue() == null : value.equals(e.getValue()));
+ }
+
+ @Override
+ public int hashCode() {
+ int keyHash = (key == null ? 0 : key.hashCode());
+ int valueHash = (value == null ? 0 : value.hashCode());
+ return keyHash ^ valueHash;
+ }
+
+ @Override
+ public String toString() {
+ return key + "=" + value;
+ }
+ }
+ private Set extends java.util.Map.Entry> entries = null;
+ private ArrayList> list;
+
+ public ArrayMap() {
+ list = new ArrayList<>();
+ }
+
+ public ArrayMap(Map map) {
+ list = new ArrayList<>();
+ putAll(map);
+ }
+
+ public ArrayMap(int initialCapacity) {
+ list = new ArrayList<>(initialCapacity);
+ }
+
+ @Override
+ @SuppressWarnings ("unchecked")
+ public Set> entrySet() {
+ if (entries == null) {
+ entries = new AbstractSet>() {
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Iterator> iterator() {
+ return list.iterator();
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+ };
+ }
+ return (Set>) entries;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ int size = list.size();
+ Entry entry = null;
+ int i;
+ if (key == null) {
+ for (i = 0; i < size; i++) {
+ entry = (list.get(i));
+ if (entry.getKey() == null) {
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++) {
+ entry = (list.get(i));
+ if (key.equals(entry.getKey())) {
+ break;
+ }
+ }
+ }
+ V oldValue = null;
+ if (i < size) {
+ oldValue = entry.getValue();
+ entry.setValue(value);
+ } else {
+ list.add(new Entry<>(key, value));
+ }
+ return oldValue;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/DatabaseConnection.java b/tools/MapleQuestItemFetcher/src/tools/DatabaseConnection.java
new file mode 100644
index 0000000000..27ea52da04
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/DatabaseConnection.java
@@ -0,0 +1,51 @@
+package tools;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * @author Frz (Big Daddy)
+ * @author The Real Spookster (some modifications to this beautiful code)
+ */
+public class DatabaseConnection {
+ private static String DB_URL = "jdbc:mysql://localhost:3306/maplesolaxia";
+ private static String DB_USER = "root";
+ private static String DB_PASS = "";
+
+ public static final int RETURN_GENERATED_KEYS = 1;
+
+ private static ThreadLocal con = new ThreadLocalConnection();
+
+ public static Connection getConnection() {
+ Connection c = con.get();
+ try {
+ c.getMetaData();
+ } catch (SQLException e) { // connection is dead, therefore discard old object 5ever
+ con.remove();
+ c = con.get();
+ }
+ return c;
+ }
+
+ private static class ThreadLocalConnection extends ThreadLocal {
+
+ @Override
+ protected Connection initialValue() {
+ try {
+ Class.forName("com.mysql.jdbc.Driver"); // touch the mysql driver
+ } catch (ClassNotFoundException e) {
+ System.out.println("[SEVERE] SQL Driver Not Found. Consider death by clams.");
+ e.printStackTrace();
+ return null;
+ }
+ try {
+ return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
+ } catch (SQLException e) {
+ System.out.println("[SEVERE] Unable to make database connection.");
+ e.printStackTrace();
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/tools/FilePrinter.java b/tools/MapleQuestItemFetcher/src/tools/FilePrinter.java
new file mode 100644
index 0000000000..340129765c
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/FilePrinter.java
@@ -0,0 +1,188 @@
+package tools;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+public class FilePrinter {
+
+ public static final String
+ ACCOUNT_STUCK = "accountStuck.txt",
+ EXCEPTION_CAUGHT = "exceptionCaught.txt",
+ CLIENT_START = "clientStartError.txt",
+ ADD_PLAYER = "addPlayer.txt",
+ MAPLE_MAP = "mapleMap.txt",
+ ERROR38 = "error38.txt",
+ PACKET_LOG = "log.txt",
+ EXCEPTION = "exceptions.txt",
+ SQL_EXCEPTION = "sqlexceptions.txt",
+ PACKET_HANDLER = "PacketHandler/",
+ PORTAL = "portals/",
+ NPC = "npcs/",
+ INVOCABLE = "invocable/",
+ REACTOR = "reactors/",
+ QUEST = "quests/",
+ ITEM = "items/",
+ MOB_MOVEMENT = "mobmovement.txt",
+ MAP_SCRIPT = "mapscript/",
+ DIRECTION = "directions/",
+ SAVE_CHAR = "saveToDB.txt",
+ INSERT_CHAR = "insertCharacter.txt",
+ LOAD_CHAR = "loadCharFromDB.txt",
+ UNHANDLED_EVENT = "doesNotExist.txt",
+ SESSION = "sessions.txt",
+ EXPLOITS = "exploits/",
+ STORAGE = "storage/",
+ PACKET_LOGS = "packetlogs/",
+ DELETED_CHARACTERS = "deletedchars/",
+ FREDRICK = "fredrick/",
+ NPC_UNCODED = "uncodedNPCs.txt",
+ QUEST_UNCODED = "uncodedQuests.txt",
+ AUTOSAVING_CHARACTER = "saveCharAuto.txt",
+ SAVING_CHARACTER = "saveChar.txt",
+ USED_COMMANDS = "usedCommands.txt";//more to come (maps)
+
+ private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
+ private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
+ private static final String ERROR = "error/";
+
+ public static void printError(final String name, final Throwable t) {
+ System.out.println("Error thrown: " + name);
+ System.out.println(getString(t));
+ FileOutputStream out = null;
+ final String file = FILE_PATH + ERROR + name;
+ try {
+ File outputFile = new File(file);
+ if (outputFile.getParentFile() != null) {
+ outputFile.getParentFile().mkdirs();
+ }
+ out = new FileOutputStream(file, true);
+ out.write(getString(t).getBytes());
+ out.write("\n---------------------------------\r\n".getBytes());
+ } catch (IOException ess) {
+ ess.printStackTrace();
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+ }
+
+ public static void printError(final String name, final Throwable t, final String info) {
+ System.out.println("Error thrown: " + name);
+ System.out.println(getString(t));
+ FileOutputStream out = null;
+ final String file = FILE_PATH + ERROR + name;
+ try {
+ File outputFile = new File(file);
+ if (outputFile.getParentFile() != null) {
+ outputFile.getParentFile().mkdirs();
+ }
+ out = new FileOutputStream(file, true);
+ out.write((info + "\r\n").getBytes());
+ out.write(getString(t).getBytes());
+ out.write("\n---------------------------------\r\n".getBytes());
+ } catch (IOException ess) {
+ ess.printStackTrace();
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+ }
+
+ public static void printError(final String name, final String s) {
+ System.out.println("Error thrown: " + name);
+ System.out.println(s);
+ FileOutputStream out = null;
+ final String file = FILE_PATH + ERROR + name;
+ try {
+ File outputFile = new File(file);
+ if (outputFile.getParentFile() != null) {
+ outputFile.getParentFile().mkdirs();
+ }
+ out = new FileOutputStream(file, true);
+ out.write(s.getBytes());
+ //out.write("\n---------------------------------\n".getBytes());
+ } catch (IOException ess) {
+ ess.printStackTrace();
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+ }
+
+ public static void print(final String name, final String s) {
+ print(name, s, true);
+ }
+
+ public static void print(final String name, final String s, boolean line) {
+ System.out.println("Log: " + name);
+ System.out.println(s);
+ FileOutputStream out = null;
+ String file = FILE_PATH + name;
+ try {
+ File outputFile = new File(file);
+ if (outputFile.getParentFile() != null) {
+ outputFile.getParentFile().mkdirs();
+ }
+ out = new FileOutputStream(file, true);
+ out.write(s.getBytes());
+ out.write("\r\n".getBytes());
+ if (line) {
+ out.write("---------------------------------\r\n".getBytes());
+ }
+ } catch (IOException ess) {
+ ess.printStackTrace();
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+ }
+
+ private static String getString(final Throwable e) {
+ String retValue = null;
+ StringWriter sw = null;
+ PrintWriter pw = null;
+ try {
+ sw = new StringWriter();
+ pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ retValue = sw.toString();
+ } finally {
+ try {
+ if (pw != null) {
+ pw.close();
+ }
+ if (sw != null) {
+ sw.close();
+ }
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+ return retValue;
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/tools/HexTool.java b/tools/MapleQuestItemFetcher/src/tools/HexTool.java
new file mode 100644
index 0000000000..8cc0c8aa84
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/HexTool.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools;
+
+import java.io.ByteArrayOutputStream;
+
+public class HexTool {
+ private static final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ private static String toString(byte byteValue) {
+ int tmp = byteValue << 8;
+ char[] retstr = new char[]{HEX[(tmp >> 12) & 0x0F], HEX[(tmp >> 8) & 0x0F]};
+ return String.valueOf(retstr);
+ }
+
+ public static String toString(byte[] bytes) {
+ StringBuilder hexed = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ hexed.append(toString(bytes[i]));
+ hexed.append(' ');
+ }
+ return hexed.substring(0, hexed.length() - 1);
+ }
+
+ public static byte[] getByteArrayFromHexString(String hex) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int nexti = 0;
+ int nextb = 0;
+ boolean highoc = true;
+ outer:
+ for (;;) {
+ int number = -1;
+ while (number == -1) {
+ if (nexti == hex.length()) {
+ break outer;
+ }
+ char chr = hex.charAt(nexti);
+ if (chr >= '0' && chr <= '9') {
+ number = chr - '0';
+ } else if (chr >= 'a' && chr <= 'f') {
+ number = chr - 'a' + 10;
+ } else if (chr >= 'A' && chr <= 'F') {
+ number = chr - 'A' + 10;
+ } else {
+ number = -1;
+ }
+ nexti++;
+ }
+ if (highoc) {
+ nextb = number << 4;
+ highoc = false;
+ } else {
+ nextb |= number;
+ highoc = true;
+ baos.write(nextb);
+ }
+ }
+ return baos.toByteArray();
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/MapleItemInformationProvider.java b/tools/MapleQuestItemFetcher/src/tools/MapleItemInformationProvider.java
new file mode 100644
index 0000000000..30136be234
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/MapleItemInformationProvider.java
@@ -0,0 +1,703 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools;
+
+import java.io.File;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+//import net.server.Server;
+import provider.MapleData;
+import provider.MapleDataDirectoryEntry;
+import provider.MapleDataFileEntry;
+import provider.MapleDataProvider;
+import provider.MapleDataProviderFactory;
+import provider.MapleDataTool;
+import tools.DatabaseConnection;
+//import tools.MaplePacketCreator;
+import tools.Pair;
+//import client.MapleCharacter;
+//import client.MapleClient;
+//import client.MapleJob;
+//import client.Skill;
+//import client.SkillFactory;
+//import client.autoban.AutobanFactory;
+//import client.inventory.Equip;
+//import client.inventory.Item;
+//import client.inventory.MapleInventory;
+//import client.inventory.MapleInventoryType;
+//import client.inventory.MapleWeaponType;
+//import constants.ServerConstants;
+//import constants.EquipSlot;
+//import constants.ItemConstants;
+//import constants.skills.Assassin;
+//import constants.skills.Gunslinger;
+//import constants.skills.NightWalker;
+import java.sql.Connection;
+//import server.life.MapleMonsterInformationProvider;
+
+/**
+ *
+ * @author Matze
+ *
+ */
+public class MapleItemInformationProvider {
+
+ private static MapleItemInformationProvider instance = null;
+ protected MapleDataProvider itemData;
+ protected MapleDataProvider equipData;
+ protected MapleDataProvider stringData;
+ protected MapleData cashStringData;
+ protected MapleData consumeStringData;
+ protected MapleData eqpStringData;
+ protected MapleData etcStringData;
+ protected MapleData insStringData;
+ protected MapleData petStringData;
+ protected Map slotMaxCache = new HashMap<>();
+ protected Map itemEffects = new HashMap<>();
+ protected Map> equipStatsCache = new HashMap<>();
+ protected Map equipCache = new HashMap<>();
+ protected Map priceCache = new HashMap<>();
+ protected Map wholePriceCache = new HashMap<>();
+ protected Map projectileWatkCache = new HashMap<>();
+ protected Map nameCache = new HashMap<>();
+ protected Map descCache = new HashMap<>();
+ protected Map msgCache = new HashMap<>();
+ protected Map dropRestrictionCache = new HashMap<>();
+ protected Map pickupRestrictionCache = new HashMap<>();
+ protected Map getMesoCache = new HashMap<>();
+ protected Map monsterBookID = new HashMap<>();
+ protected Map onEquipUntradableCache = new HashMap<>();
+ protected Map karmaCache = new HashMap<>();
+ protected Map triggerItemCache = new HashMap<>();
+ protected Map expCache = new HashMap<>();
+ protected Map levelCache = new HashMap<>();
+ protected List> itemNameCache = new ArrayList<>();
+ protected Map consumeOnPickupCache = new HashMap<>();
+ protected Map isQuestItemCache = new HashMap<>();
+ protected Map equipmentSlotCache = new HashMap<>();
+ protected Map noCancelMouseCache = new HashMap<>();
+
+ private MapleItemInformationProvider() {
+ loadCardIdData();
+ itemData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Item.wz"));
+ equipData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Character.wz"));
+ stringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz"));
+ cashStringData = stringData.getData("Cash.img");
+ consumeStringData = stringData.getData("Consume.img");
+ eqpStringData = stringData.getData("Eqp.img");
+ etcStringData = stringData.getData("Etc.img");
+ insStringData = stringData.getData("Ins.img");
+ petStringData = stringData.getData("Pet.img");
+ }
+
+ public static MapleItemInformationProvider getInstance() {
+ if (instance == null) {
+ instance = new MapleItemInformationProvider();
+ }
+ return instance;
+ }
+
+ public List> getAllItems() {
+ if (!itemNameCache.isEmpty()) {
+ return itemNameCache;
+ }
+ List> itemPairs = new ArrayList<>();
+ MapleData itemsData;
+ itemsData = stringData.getData("Cash.img");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ itemsData = stringData.getData("Consume.img");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ itemsData = stringData.getData("Eqp.img").getChildByPath("Eqp");
+ for (MapleData eqpType : itemsData.getChildren()) {
+ for (MapleData itemFolder : eqpType.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ }
+ itemsData = stringData.getData("Etc.img").getChildByPath("Etc");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ itemsData = stringData.getData("Ins.img");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ itemsData = stringData.getData("Pet.img");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ return itemPairs;
+ }
+
+ public List> getAllEtcItems() {
+ if (!itemNameCache.isEmpty()) {
+ return itemNameCache;
+ }
+
+ List> itemPairs = new ArrayList<>();
+ MapleData itemsData;
+
+ itemsData = stringData.getData("Etc.img").getChildByPath("Etc");
+ for (MapleData itemFolder : itemsData.getChildren()) {
+ itemPairs.add(new Pair<>(Integer.parseInt(itemFolder.getName()), MapleDataTool.getString("name", itemFolder, "NO-NAME")));
+ }
+ return itemPairs;
+ }
+
+ private MapleData getStringData(int itemId) {
+ String cat = "null";
+ MapleData theData;
+ if (itemId >= 5010000) {
+ theData = cashStringData;
+ } else if (itemId >= 2000000 && itemId < 3000000) {
+ theData = consumeStringData;
+ } else if ((itemId >= 1010000 && itemId < 1040000) || (itemId >= 1122000 && itemId < 1123000) || (itemId >= 1132000 && itemId < 1133000) || (itemId >= 1142000 && itemId < 1143000)) {
+ theData = eqpStringData;
+ cat = "Eqp/Accessory";
+ } else if (itemId >= 1000000 && itemId < 1010000) {
+ theData = eqpStringData;
+ cat = "Eqp/Cap";
+ } else if (itemId >= 1102000 && itemId < 1103000) {
+ theData = eqpStringData;
+ cat = "Eqp/Cape";
+ } else if (itemId >= 1040000 && itemId < 1050000) {
+ theData = eqpStringData;
+ cat = "Eqp/Coat";
+ } else if (itemId >= 20000 && itemId < 22000) {
+ theData = eqpStringData;
+ cat = "Eqp/Face";
+ } else if (itemId >= 1080000 && itemId < 1090000) {
+ theData = eqpStringData;
+ cat = "Eqp/Glove";
+ } else if (itemId >= 30000 && itemId < 35000) {
+ theData = eqpStringData;
+ cat = "Eqp/Hair";
+ } else if (itemId >= 1050000 && itemId < 1060000) {
+ theData = eqpStringData;
+ cat = "Eqp/Longcoat";
+ } else if (itemId >= 1060000 && itemId < 1070000) {
+ theData = eqpStringData;
+ cat = "Eqp/Pants";
+ } else if (itemId >= 1802000 && itemId < 1842000) {
+ theData = eqpStringData;
+ cat = "Eqp/PetEquip";
+ } else if (itemId >= 1112000 && itemId < 1120000) {
+ theData = eqpStringData;
+ cat = "Eqp/Ring";
+ } else if (itemId >= 1092000 && itemId < 1100000) {
+ theData = eqpStringData;
+ cat = "Eqp/Shield";
+ } else if (itemId >= 1070000 && itemId < 1080000) {
+ theData = eqpStringData;
+ cat = "Eqp/Shoes";
+ } else if (itemId >= 1900000 && itemId < 2000000) {
+ theData = eqpStringData;
+ cat = "Eqp/Taming";
+ } else if (itemId >= 1300000 && itemId < 1800000) {
+ theData = eqpStringData;
+ cat = "Eqp/Weapon";
+ } else if (itemId >= 4000000 && itemId < 5000000) {
+ theData = etcStringData;
+ cat = "Etc";
+ } else if (itemId >= 3000000 && itemId < 4000000) {
+ theData = insStringData;
+ } else if (itemId / 1000 == 5000) {
+ theData = petStringData;
+ } else {
+ return null;
+ }
+ if (cat.equalsIgnoreCase("null")) {
+ return theData.getChildByPath(String.valueOf(itemId));
+ } else {
+ return theData.getChildByPath(cat + "/" + itemId);
+ }
+ }
+
+ public boolean noCancelMouse(int itemId) {
+ if (noCancelMouseCache.containsKey(itemId)) {
+ return noCancelMouseCache.get(itemId);
+ }
+
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ noCancelMouseCache.put(itemId, false);
+ return false;
+ }
+
+ boolean blockMouse = MapleDataTool.getIntConvert("info/noCancelMouse", item, 0) == 1;
+ noCancelMouseCache.put(itemId, blockMouse);
+ return blockMouse;
+ }
+
+ private MapleData getItemData(int itemId) {
+ MapleData ret = null;
+ String idStr = "0" + String.valueOf(itemId);
+ MapleDataDirectoryEntry root = itemData.getRoot();
+ for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
+ for (MapleDataFileEntry iFile : topDir.getFiles()) {
+ if (iFile.getName().equals(idStr.substring(0, 4) + ".img")) {
+ ret = itemData.getData(topDir.getName() + "/" + iFile.getName());
+ if (ret == null) {
+ return null;
+ }
+ ret = ret.getChildByPath(idStr);
+ return ret;
+ } else if (iFile.getName().equals(idStr.substring(1) + ".img")) {
+ return itemData.getData(topDir.getName() + "/" + iFile.getName());
+ }
+ }
+ }
+ root = equipData.getRoot();
+ for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
+ for (MapleDataFileEntry iFile : topDir.getFiles()) {
+ if (iFile.getName().equals(idStr + ".img")) {
+ return equipData.getData(topDir.getName() + "/" + iFile.getName());
+ }
+ }
+ }
+ return ret;
+ }
+
+ public List getItemIdsInRange(int minId, int maxId, boolean ignoreCashItem) {
+ List list = new ArrayList<>();
+
+ if(ignoreCashItem) {
+ for(int i = minId; i <= maxId; i++) {
+ if(getItemData(i) != null && !isCash(i)) {
+ list.add(i);
+ }
+ }
+ }
+ else {
+ for(int i = minId; i <= maxId; i++) {
+ if(getItemData(i) != null) {
+ list.add(i);
+ }
+ }
+ }
+
+
+ return list;
+ }
+
+ public short getSlotMax(int itemId) {
+ Short slotMax = slotMaxCache.get(itemId);
+ if (slotMax != null) {
+ return (short)(slotMax);
+ }
+ short ret = 0;
+ MapleData item = getItemData(itemId);
+ if (item != null) {
+ MapleData smEntry = item.getChildByPath("info/slotMax");
+ if (smEntry == null) {
+ ret = 100;
+ } else {
+ ret = (short) MapleDataTool.getInt(smEntry);
+ }
+ }
+
+ slotMaxCache.put(itemId, ret);
+ return (short)(ret);
+ }
+
+ public int getMeso(int itemId) {
+ if (getMesoCache.containsKey(itemId)) {
+ return getMesoCache.get(itemId);
+ }
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ return -1;
+ }
+ int pEntry;
+ MapleData pData = item.getChildByPath("info/meso");
+ if (pData == null) {
+ return -1;
+ }
+ pEntry = MapleDataTool.getInt(pData);
+ getMesoCache.put(itemId, pEntry);
+ return pEntry;
+ }
+
+ public int getWholePrice(int itemId) {
+ if (wholePriceCache.containsKey(itemId)) {
+ return wholePriceCache.get(itemId);
+ }
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ return -1;
+ }
+ int pEntry;
+ MapleData pData = item.getChildByPath("info/price");
+ if (pData == null) {
+ return -1;
+ }
+ pEntry = MapleDataTool.getInt(pData);
+ wholePriceCache.put(itemId, pEntry);
+ return pEntry;
+ }
+
+ public double getPrice(int itemId) {
+ if (priceCache.containsKey(itemId)) {
+ return priceCache.get(itemId);
+ }
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ return -1;
+ }
+ double pEntry;
+ MapleData pData = item.getChildByPath("info/unitPrice");
+ if (pData != null) {
+ try {
+ pEntry = MapleDataTool.getDouble(pData);
+ } catch (Exception e) {
+ pEntry = (double) MapleDataTool.getInt(pData);
+ }
+ } else {
+ pData = item.getChildByPath("info/price");
+ if (pData == null) {
+ return -1;
+ }
+ try {
+ pEntry = (double) MapleDataTool.getInt(pData);
+ } catch(Exception e) {
+ priceCache.put(itemId, 0.0);
+ return 0;
+ }
+ }
+ priceCache.put(itemId, pEntry);
+ return pEntry;
+ }
+
+ protected String getEquipmentSlot(int itemId) {
+ if (equipmentSlotCache.containsKey(itemId)) {
+ return equipmentSlotCache.get(itemId);
+ }
+
+ String ret = "";
+
+ MapleData item = getItemData(itemId);
+
+ if (item == null) {
+ return null;
+ }
+
+ MapleData info = item.getChildByPath("info");
+
+ if (info == null) {
+ return null;
+ }
+
+ ret = MapleDataTool.getString("islot", info, "");
+
+ equipmentSlotCache.put(itemId, ret);
+
+ return ret;
+ }
+
+ public Map getEquipStats(int itemId) {
+ if (equipStatsCache.containsKey(itemId)) {
+ return equipStatsCache.get(itemId);
+ }
+ Map ret = new LinkedHashMap<>();
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ return null;
+ }
+ MapleData info = item.getChildByPath("info");
+ if (info == null) {
+ return null;
+ }
+ for (MapleData data : info.getChildren()) {
+ if (data.getName().startsWith("inc")) {
+ ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
+ }
+ /*else if (data.getName().startsWith("req"))
+ ret.put(data.getName(), MapleDataTool.getInt(data.getName(), info, 0));*/
+ }
+ ret.put("reqJob", MapleDataTool.getInt("reqJob", info, 0));
+ ret.put("reqLevel", MapleDataTool.getInt("reqLevel", info, 0));
+ ret.put("reqDEX", MapleDataTool.getInt("reqDEX", info, 0));
+ ret.put("reqSTR", MapleDataTool.getInt("reqSTR", info, 0));
+ ret.put("reqINT", MapleDataTool.getInt("reqINT", info, 0));
+ ret.put("reqLUK", MapleDataTool.getInt("reqLUK", info, 0));
+ ret.put("reqPOP", MapleDataTool.getInt("reqPOP", info, 0));
+ ret.put("cash", MapleDataTool.getInt("cash", info, 0));
+ ret.put("tuc", MapleDataTool.getInt("tuc", info, 0));
+ ret.put("cursed", MapleDataTool.getInt("cursed", info, 0));
+ ret.put("success", MapleDataTool.getInt("success", info, 0));
+ ret.put("fs", MapleDataTool.getInt("fs", info, 0));
+ equipStatsCache.put(itemId, ret);
+ return ret;
+ }
+
+ public List getScrollReqs(int itemId) {
+ List ret = new ArrayList<>();
+ MapleData data = getItemData(itemId);
+ data = data.getChildByPath("req");
+ if (data == null) {
+ return ret;
+ }
+ for (MapleData req : data.getChildren()) {
+ ret.add(MapleDataTool.getInt(req));
+ }
+ return ret;
+ }
+
+ public String getName(int itemId) {
+ if (nameCache.containsKey(itemId)) {
+ return nameCache.get(itemId);
+ }
+ MapleData strings = getStringData(itemId);
+ if (strings == null) {
+ return null;
+ }
+ String ret = MapleDataTool.getString("name", strings, null);
+ nameCache.put(itemId, ret);
+ return ret;
+ }
+
+ public String getMsg(int itemId) {
+ if (msgCache.containsKey(itemId)) {
+ return msgCache.get(itemId);
+ }
+ MapleData strings = getStringData(itemId);
+ if (strings == null) {
+ return null;
+ }
+ String ret = MapleDataTool.getString("msg", strings, null);
+ msgCache.put(itemId, ret);
+ return ret;
+ }
+
+ public boolean isDropRestricted(int itemId) {
+ if (dropRestrictionCache.containsKey(itemId)) {
+ return dropRestrictionCache.get(itemId);
+ }
+ MapleData data = getItemData(itemId);
+ boolean bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
+ if (!bRestricted) {
+ bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
+ }
+ if (!bRestricted) {
+ bRestricted = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
+ }
+ dropRestrictionCache.put(itemId, bRestricted);
+ return bRestricted;
+ }
+
+ public boolean isPickupRestricted(int itemId) {
+ if (pickupRestrictionCache.containsKey(itemId)) {
+ return pickupRestrictionCache.get(itemId);
+ }
+ MapleData data = getItemData(itemId);
+ boolean bRestricted = MapleDataTool.getIntConvert("info/only", data, 0) == 1;
+ pickupRestrictionCache.put(itemId, bRestricted);
+ return bRestricted;
+ }
+
+ public Map getSkillStats(int itemId, double playerJob) {
+ Map ret = new LinkedHashMap<>();
+ MapleData item = getItemData(itemId);
+ if (item == null) {
+ return null;
+ }
+ MapleData info = item.getChildByPath("info");
+ if (info == null) {
+ return null;
+ }
+ for (MapleData data : info.getChildren()) {
+ if (data.getName().startsWith("inc")) {
+ ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
+ }
+ }
+ ret.put("masterLevel", MapleDataTool.getInt("masterLevel", info, 0));
+ ret.put("reqSkillLevel", MapleDataTool.getInt("reqSkillLevel", info, 0));
+ ret.put("success", MapleDataTool.getInt("success", info, 0));
+ MapleData skill = info.getChildByPath("skill");
+ int curskill;
+ for (int i = 0; i < skill.getChildren().size(); i++) {
+ curskill = MapleDataTool.getInt(Integer.toString(i), skill, 0);
+ if (curskill == 0) {
+ break;
+ }
+ if (curskill / 10000 == playerJob) {
+ ret.put("skillid", curskill);
+ break;
+ }
+ }
+ if (ret.get("skillid") == null) {
+ ret.put("skillid", 0);
+ }
+ return ret;
+ }
+
+ public List petsCanConsume(int itemId) {
+ List ret = new ArrayList<>();
+ MapleData data = getItemData(itemId);
+ int curPetId;
+ for (int i = 0; i < data.getChildren().size(); i++) {
+ curPetId = MapleDataTool.getInt("spec/" + Integer.toString(i), data, 0);
+ if (curPetId == 0) {
+ break;
+ }
+ ret.add(Integer.valueOf(curPetId));
+ }
+ return ret;
+ }
+
+ public boolean isQuestItem(int itemId) {
+ if (isQuestItemCache.containsKey(itemId)) {
+ return isQuestItemCache.get(itemId);
+ }
+ MapleData data = getItemData(itemId);
+ boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
+ isQuestItemCache.put(itemId, questItem);
+ return questItem;
+ }
+
+ public int getQuestIdFromItem(int itemId) {
+ MapleData data = getItemData(itemId);
+ int questItem = MapleDataTool.getIntConvert("info/quest", data, 0);
+ return questItem;
+ }
+
+ private void loadCardIdData() {
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ Connection con = null;
+ try {
+ con = DatabaseConnection.getConnection();
+ ps = con.prepareStatement("SELECT cardid, mobid FROM monstercarddata");
+ rs = ps.executeQuery();
+ while (rs.next()) {
+ monsterBookID.put(rs.getInt(1), rs.getInt(2));
+ }
+ rs.close();
+ ps.close();
+ con.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (rs != null && !rs.isClosed()) {
+ rs.close();
+ }
+ if (ps != null && !ps.isClosed()) {
+ ps.close();
+ }
+ if (con != null && !con.isClosed()) {
+ con.close();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public int getCardMobId(int id) {
+ return monsterBookID.get(id);
+ }
+
+ public boolean isUntradeableOnEquip(int itemId) {
+ if (onEquipUntradableCache.containsKey(itemId)) {
+ return onEquipUntradableCache.get(itemId);
+ }
+ boolean untradableOnEquip = MapleDataTool.getIntConvert("info/equipTradeBlock", getItemData(itemId), 0) > 0;
+ onEquipUntradableCache.put(itemId, untradableOnEquip);
+ return untradableOnEquip;
+ }
+
+ public boolean isKarmaAble(int itemId) {
+ if (karmaCache.containsKey(itemId)) {
+ return karmaCache.get(itemId);
+ }
+ boolean bRestricted = MapleDataTool.getIntConvert("info/tradeAvailable", getItemData(itemId), 0) > 0;
+ karmaCache.put(itemId, bRestricted);
+ return bRestricted;
+ }
+
+ public int getStateChangeItem(int itemId) {
+ if (triggerItemCache.containsKey(itemId)) {
+ return triggerItemCache.get(itemId);
+ } else {
+ int triggerItem = MapleDataTool.getIntConvert("info/stateChangeItem", getItemData(itemId), 0);
+ triggerItemCache.put(itemId, triggerItem);
+ return triggerItem;
+ }
+ }
+
+ public int getExpById(int itemId) {
+ if (expCache.containsKey(itemId)) {
+ return expCache.get(itemId);
+ } else {
+ int exp = MapleDataTool.getIntConvert("spec/exp", getItemData(itemId), 0);
+ expCache.put(itemId, exp);
+ return exp;
+ }
+ }
+
+ public int getMaxLevelById(int itemId) {
+ if (levelCache.containsKey(itemId)) {
+ return levelCache.get(itemId);
+ } else {
+ int level = MapleDataTool.getIntConvert("info/maxLevel", getItemData(itemId), 256);
+ levelCache.put(itemId, level);
+ return level;
+ }
+ }
+
+ public boolean isConsumeOnPickup(int itemId) {
+ if (consumeOnPickupCache.containsKey(itemId)) {
+ return consumeOnPickupCache.get(itemId);
+ }
+ MapleData data = getItemData(itemId);
+ boolean consume = MapleDataTool.getIntConvert("spec/consumeOnPickup", data, 0) == 1 || MapleDataTool.getIntConvert("specEx/consumeOnPickup", data, 0) == 1;
+ consumeOnPickupCache.put(itemId, consume);
+ return consume;
+ }
+
+ public boolean isCash(int itemId) {
+ return itemId / 1000000 == 5 || getEquipStats(itemId).get("cash") == 1;
+ }
+
+ public ArrayList> getItemDataByName(String name)
+ {
+ ArrayList> ret = new ArrayList<>();
+ for (Pair itemPair : MapleItemInformationProvider.getInstance().getAllItems()) {
+ if (itemPair.getRight().toLowerCase().contains(name.toLowerCase())) {
+ ret.add(itemPair);
+ }
+ }
+ return ret;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/Pair.java b/tools/MapleQuestItemFetcher/src/tools/Pair.java
new file mode 100644
index 0000000000..f88718cbe3
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/Pair.java
@@ -0,0 +1,121 @@
+/*
+This file is part of the OdinMS Maple Story Server
+Copyright (C) 2008 ~ 2010 Patrick Huy
+Matthias Butz
+Jan Christian Meyer
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License version 3
+as published by the Free Software Foundation. You may not use, modify
+or distribute this program under any other version of the
+GNU Affero General Public License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+ */
+package tools;
+
+/**
+ * Represents a pair of values.
+ *
+ * @author Frz
+ * @since Revision 333
+ * @version 1.0
+ *
+ * @param The type of the left value.
+ * @param The type of the right value.
+ */
+public class Pair {
+
+ public E left;
+ public F right;
+
+ /**
+ * Class constructor - pairs two objects together.
+ *
+ * @param left The left object.
+ * @param right The right object.
+ */
+ public Pair(E left, F right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Gets the left value.
+ *
+ * @return The left value.
+ */
+ public E getLeft() {
+ return left;
+ }
+
+ /**
+ * Gets the right value.
+ *
+ * @return The right value.
+ */
+ public F getRight() {
+ return right;
+ }
+
+ /**
+ * Turns the pair into a string.
+ *
+ * @return Each value of the pair as a string joined by a colon.
+ */
+ @Override
+ public String toString() {
+ return left.toString() + ":" + right.toString();
+ }
+
+ /**
+ * Gets the hash code of this pair.
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((left == null) ? 0 : left.hashCode());
+ result = prime * result + ((right == null) ? 0 : right.hashCode());
+ return result;
+ }
+
+ /**
+ * Checks to see if two pairs are equal.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Pair other = (Pair) obj;
+ if (left == null) {
+ if (other.left != null) {
+ return false;
+ }
+ } else if (!left.equals(other.left)) {
+ return false;
+ }
+ if (right == null) {
+ if (other.right != null) {
+ return false;
+ }
+ } else if (!right.equals(other.right)) {
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/tools/StringUtil.java b/tools/MapleQuestItemFetcher/src/tools/StringUtil.java
new file mode 100644
index 0000000000..b471e4aef2
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/StringUtil.java
@@ -0,0 +1,128 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools;
+
+public class StringUtil {
+ /**
+ * Gets a string padded from the left to length by
+ * padchar.
+ *
+ * @param in The input string to be padded.
+ * @param padchar The character to pad with.
+ * @param length The length to pad to.
+ * @return The padded string.
+ */
+ public static String getLeftPaddedStr(String in, char padchar, int length) {
+ StringBuilder builder = new StringBuilder(length);
+ for (int x = in.length(); x < length; x++) {
+ builder.append(padchar);
+ }
+ builder.append(in);
+ return builder.toString();
+ }
+
+ /**
+ * Gets a string padded from the right to length by
+ * padchar.
+ *
+ * @param in The input string to be padded.
+ * @param padchar The character to pad with.
+ * @param length The length to pad to.
+ * @return The padded string.
+ */
+ public static String getRightPaddedStr(String in, char padchar, int length) {
+ StringBuilder builder = new StringBuilder(in);
+ for (int x = in.length(); x < length; x++) {
+ builder.append(padchar);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Joins an array of strings starting from string start with
+ * a space.
+ *
+ * @param arr The array of strings to join.
+ * @param start Starting from which string.
+ * @return The joined strings.
+ */
+ public static String joinStringFrom(String arr[], int start) {
+ return joinStringFrom(arr, start, " ");
+ }
+
+ /**
+ * Joins an array of strings starting from string start with
+ * sep as a seperator.
+ *
+ * @param arr The array of strings to join.
+ * @param start Starting from which string.
+ * @return The joined strings.
+ */
+ public static String joinStringFrom(String arr[], int start, String sep) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = start; i < arr.length; i++) {
+ builder.append(arr[i]);
+ if (i != arr.length - 1) {
+ builder.append(sep);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Makes an enum name human readable (fixes spaces, capitalization, etc)
+ *
+ * @param enumName The name of the enum to neaten up.
+ * @return The human-readable enum name.
+ */
+ public static String makeEnumHumanReadable(String enumName) {
+ StringBuilder builder = new StringBuilder(enumName.length() + 1);
+ String[] words = enumName.split("_");
+ for (String word : words) {
+ if (word.length() <= 2) {
+ builder.append(word); // assume that it's an abbrevation
+ } else {
+ builder.append(word.charAt(0));
+ builder.append(word.substring(1).toLowerCase());
+ }
+ builder.append(' ');
+ }
+ return builder.substring(0, enumName.length());
+ }
+
+ /**
+ * Counts the number of chr's in str.
+ *
+ * @param str The string to check for instances of chr.
+ * @param chr The character to check for.
+ * @return The number of times chr occurs in str.
+ */
+ public static int countCharacters(String str, char chr) {
+ int ret = 0;
+ for (int i = 0; i < str.length(); i++) {
+ if (str.charAt(i) == chr) {
+ ret++;
+ }
+ }
+ return ret;
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/ByteArrayByteStream.java b/tools/MapleQuestItemFetcher/src/tools/data/input/ByteArrayByteStream.java
new file mode 100644
index 0000000000..eac7de21ea
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/ByteArrayByteStream.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.io.IOException;
+import tools.HexTool;
+
+public class ByteArrayByteStream implements SeekableInputStreamBytestream {
+ private int pos = 0;
+ private long bytesRead = 0;
+ private byte[] arr;
+
+ public ByteArrayByteStream(byte[] arr) {
+ this.arr = arr;
+ }
+
+ @Override
+ public long getPosition() {
+ return pos;
+ }
+
+ @Override
+ public void seek(long offset) throws IOException {
+ pos = (int) offset;
+ }
+
+ @Override
+ public long getBytesRead() {
+ return bytesRead;
+ }
+
+ @Override
+ public int readByte() {
+ bytesRead++;
+ return ((int) arr[pos++]) & 0xFF;
+ }
+
+ @Override
+ public String toString() {
+ String nows = "kevintjuh93 pwns";//I lol'd
+ if (arr.length - pos > 0) {
+ byte[] now = new byte[arr.length - pos];
+ System.arraycopy(arr, pos, now, 0, arr.length - pos);
+ nows = HexTool.toString(now);
+ }
+ return "All: " + HexTool.toString(arr) + "\nNow: " + nows;
+ }
+
+ @Override
+ public long available() {
+ return arr.length - pos;
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/ByteInputStream.java b/tools/MapleQuestItemFetcher/src/tools/data/input/ByteInputStream.java
new file mode 100644
index 0000000000..107f71843e
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/ByteInputStream.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+/**
+ * Represents an abstract stream of bytes.
+ *
+ * @author Frz
+ * @version 1.0
+ * @since Revision 323
+ */
+public interface ByteInputStream {
+ int readByte();
+ long getBytesRead();
+ long available();
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/GenericLittleEndianAccessor.java b/tools/MapleQuestItemFetcher/src/tools/data/input/GenericLittleEndianAccessor.java
new file mode 100644
index 0000000000..d08a9b8374
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/GenericLittleEndianAccessor.java
@@ -0,0 +1,239 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.awt.Point;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Provides a generic interface to a Little Endian stream of bytes.
+ *
+ * @version 1.0
+ * @author Frz
+ * @since Revision 323
+ */
+public class GenericLittleEndianAccessor implements LittleEndianAccessor {
+ private ByteInputStream bs;
+
+ /**
+ * Class constructor - Wraps the accessor around a stream of bytes.
+ *
+ * @param bs The byte stream to wrap the accessor around.
+ */
+ public GenericLittleEndianAccessor(ByteInputStream bs) {
+ this.bs = bs;
+ }
+
+ /**
+ * Read a single byte from the stream.
+ *
+ * @return The byte read.
+ * @see tools.data.input.ByteInputStream#readByte
+ */
+ @Override
+ public byte readByte() {
+ return (byte) bs.readByte();
+ }
+
+ /**
+ * Reads an integer from the stream.
+ *
+ * @return The integer read.
+ */
+ @Override
+ public int readInt() {
+ return bs.readByte() + (bs.readByte() << 8) + (bs.readByte() << 16) + (bs.readByte() << 24);
+ }
+
+ /**
+ * Reads a short integer from the stream.
+ *
+ * @return The short read.
+ */
+ @Override
+ public short readShort() {
+ return (short) (bs.readByte() + (bs.readByte() << 8));
+ }
+
+ /**
+ * Reads a single character from the stream.
+ *
+ * @return The character read.
+ */
+ @Override
+ public char readChar() {
+ return (char) readShort();
+ }
+
+ /**
+ * Reads a long integer from the stream.
+ *
+ * @return The long integer read.
+ */
+ @Override
+ public long readLong() {
+ long byte1 = bs.readByte();
+ long byte2 = bs.readByte();
+ long byte3 = bs.readByte();
+ long byte4 = bs.readByte();
+ long byte5 = bs.readByte();
+ long byte6 = bs.readByte();
+ long byte7 = bs.readByte();
+ long byte8 = bs.readByte();
+ return (byte8 << 56) + (byte7 << 48) + (byte6 << 40) + (byte5 << 32) + (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1;
+ }
+
+ /**
+ * Reads a floating point integer from the stream.
+ *
+ * @return The float-type integer read.
+ */
+ @Override
+ public float readFloat() {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * Reads a double-precision integer from the stream.
+ *
+ * @return The double-type integer read.
+ */
+ @Override
+ public double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * Reads an ASCII string from the stream with length n.
+ *
+ * @param n Number of characters to read.
+ * @return The string read.
+ */
+ public final String readAsciiString(int n) {
+ char ret[] = new char[n];
+ for (int x = 0; x < n; x++) {
+ ret[x] = (char) readByte();
+ }
+ return String.valueOf(ret);
+ }
+
+ /**
+ * Reads a null-terminated string from the stream.
+ *
+ * @return The string read.
+ */
+ public final String readNullTerminatedAsciiString() {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte b;
+ while (true) {
+ b = readByte();
+ if (b == 0) {
+ break;
+ }
+ baos.write(b);
+ }
+ byte[] buf = baos.toByteArray();
+ char[] chrBuf = new char[buf.length];
+ for (int x = 0; x < buf.length; x++) {
+ chrBuf[x] = (char) buf[x];
+ }
+ return String.valueOf(chrBuf);
+ }
+
+ /**
+ * Gets the number of bytes read from the stream so far.
+ *
+ * @return A long integer representing the number of bytes read.
+ * @see tools.data.input.ByteInputStream#getBytesRead()
+ */
+ public long getBytesRead() {
+ return bs.getBytesRead();
+ }
+
+ /**
+ * Reads a MapleStory convention lengthed ASCII string.
+ * This consists of a short integer telling the length of the string,
+ * then the string itself.
+ *
+ * @return The string read.
+ */
+ @Override
+ public String readMapleAsciiString() {
+ return readAsciiString(readShort());
+ }
+
+ /**
+ * Reads num bytes off the stream.
+ *
+ * @param num The number of bytes to read.
+ * @return An array of bytes with the length of num
+ */
+ @Override
+ public byte[] read(int num) {
+ byte[] ret = new byte[num];
+ for (int x = 0; x < num; x++) {
+ ret[x] = readByte();
+ }
+ return ret;
+ }
+
+ /**
+ * Reads a MapleStory Position information.
+ * This consists of 2 short integer.
+ *
+ * @return The Position read.
+ */
+ @Override
+ public final Point readPos() {
+ final int x = readShort();
+ final int y = readShort();
+ return new Point(x, y);
+ }
+
+ /**
+ * Skips the current position of the stream num bytes ahead.
+ *
+ * @param num Number of bytes to skip.
+ */
+ @Override
+ public void skip(int num) {
+ for (int x = 0; x < num; x++) {
+ readByte();
+ }
+ }
+
+ /**
+ * @see tools.data.input.ByteInputStream#available
+ */
+ @Override
+ public long available() {
+ return bs.available();
+ }
+
+ /**
+ * @see java.lang.Object#toString
+ */
+ @Override
+ public String toString() {
+ return bs.toString();
+ }
+}
\ No newline at end of file
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java b/tools/MapleQuestItemFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java
new file mode 100644
index 0000000000..fdd147d796
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java
@@ -0,0 +1,91 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.io.IOException;
+
+/**
+ * Provides an abstract accessor to a generic Little Endian byte stream. This
+ * accessor is seekable.
+ *
+ * @author Frz
+ * @version 1.0
+ * @since Revision 323
+ * @see tools.data.input.GenericLittleEndianAccessor
+ */
+public class GenericSeekableLittleEndianAccessor extends GenericLittleEndianAccessor implements SeekableLittleEndianAccessor {
+ private SeekableInputStreamBytestream bs;
+
+ /**
+ * Class constructor
+ * Provide a seekable input stream to wrap this object around.
+ *
+ * @param bs The byte stream to wrap this around.
+ */
+ public GenericSeekableLittleEndianAccessor(SeekableInputStreamBytestream bs) {
+ super(bs);
+ this.bs = bs;
+ }
+
+ /**
+ * Seek the pointer to offset
+ *
+ * @param offset The offset to seek to.
+ * @see tools.data.input.SeekableInputStreamBytestream#seek
+ */
+ @Override
+ public void seek(long offset) {
+ try {
+ bs.seek(offset);
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("Seek failed " + e);
+ }
+ }
+
+ /**
+ * Get the current position of the pointer.
+ *
+ * @return The current position of the pointer as a long integer.
+ * @see tools.data.input.SeekableInputStreamBytestream#getPosition
+ */
+ @Override
+ public long getPosition() {
+ try {
+ return bs.getPosition();
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("getPosition failed" + e);
+ return -1;
+ }
+ }
+
+ /**
+ * Skip num number of bytes in the stream.
+ *
+ * @param num The number of bytes to skip.
+ */
+ @Override
+ public void skip(int num) {
+ seek(getPosition() + num);
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/InputStreamByteStream.java b/tools/MapleQuestItemFetcher/src/tools/data/input/InputStreamByteStream.java
new file mode 100644
index 0000000000..70aef3489f
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/InputStreamByteStream.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides an abstract wrapper to a stream of bytes.
+ *
+ * @author Frz
+ * @version 1.0
+ * @since Revision 323
+ */
+public class InputStreamByteStream implements ByteInputStream {
+ private InputStream is;
+ private long read = 0;
+
+ /**
+ * Class constructor.
+ * Provide an input stream to wrap this around.
+ *
+ * @param is The input stream to wrap this object around.
+ */
+ public InputStreamByteStream(InputStream is) {
+ this.is = is;
+ }
+
+ /**
+ * Reads the next byte from the stream.
+ *
+ * @return Then next byte in the stream.
+ */
+ @Override
+ public int readByte() {
+ int temp;
+ try {
+ temp = is.read();
+ if (temp == -1) {
+ throw new RuntimeException("EOF");
+ }
+ read++;
+ return temp;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the number of bytes read from the stream.
+ *
+ * @return The number of bytes read as a long integer.
+ */
+ @Override
+ public long getBytesRead() {
+ return read;
+ }
+
+ /**
+ * Returns the number of bytes left in the stream.
+ *
+ * @return The number of bytes available for reading as a long integer.
+ */
+ @Override
+ public long available() {
+ try {
+ return is.available();
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("ERROR" + e);
+ return 0;
+ }
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/LittleEndianAccessor.java b/tools/MapleQuestItemFetcher/src/tools/data/input/LittleEndianAccessor.java
new file mode 100644
index 0000000000..f991dbf537
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/LittleEndianAccessor.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.awt.Point;
+
+/**
+ * @author Frz
+ */
+public interface LittleEndianAccessor {
+ byte readByte();
+ char readChar();
+ short readShort();
+ int readInt();
+ Point readPos();
+ long readLong();
+ void skip(int num);
+ byte[] read(int num);
+ float readFloat();
+ double readDouble();
+ String readAsciiString(int n);
+ String readNullTerminatedAsciiString();
+ String readMapleAsciiString();
+ long getBytesRead();
+ long available();
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/RandomAccessByteStream.java b/tools/MapleQuestItemFetcher/src/tools/data/input/RandomAccessByteStream.java
new file mode 100644
index 0000000000..c0004be17f
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/RandomAccessByteStream.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 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 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 tools.data.input;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Provides an abstract layer to a byte stream. This layer can be accessed
+ * randomly.
+ *
+ * @author Frz
+ * @version 1.0
+ * @since Revision 323
+ */
+public class RandomAccessByteStream implements SeekableInputStreamBytestream {
+ private RandomAccessFile raf;
+ private long read = 0;
+
+ public RandomAccessByteStream(RandomAccessFile raf) {
+ super();
+ this.raf = raf;
+ }
+
+ @Override
+ public int readByte() {
+ int temp;
+ try {
+ temp = raf.read();
+ if (temp == -1) {
+ throw new RuntimeException("EOF");
+ }
+ read++;
+ return temp;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void seek(long offset) throws IOException {
+ raf.seek(offset);
+ }
+
+ @Override
+ public long getPosition() throws IOException {
+ return raf.getFilePointer();
+ }
+
+ @Override
+ public long getBytesRead() {
+ return read;
+ }
+
+ @Override
+ public long available() {
+ try {
+ return raf.length() - raf.getFilePointer();
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("ERROR " + e);
+ return 0;
+ }
+ }
+}
diff --git a/tools/MapleQuestItemFetcher/src/tools/data/input/SeekableInputStreamBytestream.java b/tools/MapleQuestItemFetcher/src/tools/data/input/SeekableInputStreamBytestream.java
new file mode 100644
index 0000000000..f4922dc876
--- /dev/null
+++ b/tools/MapleQuestItemFetcher/src/tools/data/input/SeekableInputStreamBytestream.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the OdinMS Maple Story Server
+ Copyright (C) 2008 Patrick Huy
+ Matthias Butz
+ Jan Christian Meyer