diff --git a/.gitignore b/.gitignore index fc5173fbba..70e1a6afe9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,7 @@ /tools/MobBookUpdate/build/ /tools/MobBookUpdate/dist/ /tools/MobBookUpdate/nbproject/private/ + +/tools/MapleMapInfoRetriever/build/ +/tools/MapleMapInfoRetriever/dist/ +/tools/MapleMapInfoRetriever/nbproject/private/ diff --git a/dist/MapleSolaxia.jar b/dist/MapleSolaxia.jar index 98fdf4c357..488d5d75af 100644 Binary files a/dist/MapleSolaxia.jar and b/dist/MapleSolaxia.jar differ diff --git a/docs/feature_list.txt b/docs/feature_list.txt index 8c3dd52479..3645f6b153 100644 --- a/docs/feature_list.txt +++ b/docs/feature_list.txt @@ -49,7 +49,7 @@ Cash & Items: * Owl of Minerva. * Pet item ignore. -Monsters & Maps: +Monsters, Maps & Reactors: * Every monsterbook card is now droppable by overworld mobs. * Added meso drop data for basically every missing overworld mob. * Monsterbook displays drop data info conformant with the underlying DB (needs custom wz). See more on the MobBookUpdate feature. @@ -58,6 +58,7 @@ Monsters & Maps: * If multiple bosses are on the same area, client will prioritize Boss HP bar of the target of the player. * Boats, elevator and other travelling mechanics fully working. * PQs, Taxis and other event-driven situations warps players at random spawnpoints, GMS-like. +* Some reactors (PQ bonus boxes) now sprays items on the map, instead of dropping everything at once. PQ potentials: * Lobby system - Multiple PQ instances on same channel. @@ -92,6 +93,7 @@ External tools: * MapleArrowFetcher - Updates min/max quantity dropped on all arrows drop data, calculations based on mob level and whether it's a boss or not. * MapleCouponInstaller - Retrieves coupon info from the WZ and makes a SQL table with it. The server will use that table to gather info regarding rates and intervals. * MapleIdRetriever - Two behaviors: generates a SQL table with relation (id, name) of the handbook given as input. Given a file with names, outputs a file with ids. +* MapleMapInfoRetriever - Basic tool for detecting missing info nodes on the map field structures (maps failing to have an info node on the WZ is an critical issue). * MapleMesoFetcher - Creates meso drop data for mobs with more than 4 items (thus overworld mobs), calculations based on mob level and whether it's a boss or not. * MapleQuestItemFetcher - Searches the SQL tables and project files and reports in all relevant data regarding missing/erroneous quest items. * MobBookIndexer - Generates a SQL table with all relations of cardid and mobid present in the mob book. diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 9faaac6c8e..a16cad5301 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -681,3 +681,8 @@ Rearranjado ID de jogador agora come Corrigido timer de quest não saindo do cliente quando dado o termino bem-sucedido da quest. Corrigido MapleArrowFetcher atribuindo valores iguais para min e max ranges. Max deve sempre ser maior que min. Corrigido bug no ThreadTracker não mostrando os últimos locks capturados pelas threads corretamente. + +18 - 20 Novembro 2017, +Implementado items sendo dropados de reatores intervaladamente, GMS-like. +Adicionado informação ao jogador que tentar completar uma quest com item necessário equipado. +Nova ferramenta: MapleMapInfoRetriever. Detecção básica de mapas com sem nó de info em sua estrutura WZ. \ No newline at end of file diff --git a/scripts/npc/1002000.js b/scripts/npc/1002000.js index cc57a4e692..0a50b8b57a 100644 --- a/scripts/npc/1002000.js +++ b/scripts/npc/1002000.js @@ -1,7 +1,8 @@ var status = 0; +var imaps = [104000000, 102000000, 100000000, 101000000, 103000000, 120000000, 105040300]; var maps = [102000000, 100000000, 101000000, 103000000, 120000000]; var cost = [1000, 1000, 800, 1000, 800]; -var townText = [["The town you are at is Lith Harbor! Alright I'll explain to you more about #bLith Harbor#k. It's the place you landed on Victoria Island by riding The Victoria. That's Lith Harbor. A lot of beginners who just got here from Maple Island start their journey here.", "It's a quiet town with the wide body of water on the back of it, thanks to the fact that the harbot is located at the west end of the island. Most of the people here are, or used to be fisherman, so they may look intimidating, but if you strike up a conversation with them, they'll be friendly to you.", "Around town lies a beautiful prairie. Most of the monsters there are small and gentle, perfect for beginners. If you haven't chosen your job yet, this is a good place to boost up your level."],["Alright I'll explain to you more about #bPerion#k. It's a warrior-town located at the northern-most part of Victoria Island, surrounded by rocky mountains. With an unfriendly atmosphere, only the strong survives there.", "Around the highland you'll find a really skinny tree, a wild hog running around the place, and monkeys that live all over the island. There's also a deep valley, and when you go deep into it, you'll find a humongous dragon with the power to match his size. Better go in there very carefully, or don't go at all.", "If you want to be a #bWarrior#k then find #rDances with Balrog#k, the chief of Perion. If you're level 10 or higher, along with a good STR level, he may make you a warrior after all. If not, better keep training yourself until you reach that level."], ["Alright I'll explain to you more about #bEllinia#k. It's a magician-town located at the far east of Victoria Island, and covered in tall, mystic trees. You'll find some fairies there, too. They don't like humans in general so it'll be best for you to be on their good side and stay quiet.", "Near the forest you'll find green slimes, walking mushrooms, monkeys and zombie monkeys all residing there. Walk deeper into the forest and you'll find witches with the flying broomstick navigating the skies. A word of warning: Unless you are really strong, I recommend you don't go near them.", "If you want to be a #bMagician#k, search for #rGrendel the Really Old#k, the head wizard of Ellinia. He may make you a wizard if you're at or above level 8 with a decent amount of INT. If that's not the case, you may have to hunt more and train yourself to get there."], ["Alright I'll explain to you more about #bHenesys#k. It's a bowman-town located at the southernmost part of the island, made on a flatland in the midst of a deep forest and prairies. The weather's just right, and everything is plentiful around that town, perfect for living. Go check it out.", "Around the prairie you'll find weak monsters such as snails, mushrooms, and pigs. According to what I hear, though, in the deepest part of the Pig Park, which is connected to the town somewhere, you'll find a humongous, powerful mushroom called Mushmom every now and then.", "If you want to be a #bBowman#k, you need to go see #rAthena Pierce#k at Henesys. With a level at or above 10 and a decent amount of DEX, she may make you be one afterall. If not, go train yourself, make yourself stronger, then try again."], ["Alright I'll explain to you more about #bKerning City#k. It's a thief-town located at the northwest part of Victoria Island, and there are buildings up there that have just this strange feeling around them. It's mostly covered in black clouds, but if you can go up to a really high place, you'll be able to see a very beautiful sunset there.", "From Kerning City, you can go into several dungeons. You can go to a swamp where alligators and snakes are abound, or hit the subway full of ghosts and bats. At the deepest part of the underground, you'll find Lace, who is just as big and dangerous as a dragon.", "If you want to be a #bThief#k, seek #rDark Lord#k, the heart of darkness of Kerning City. He may well make you a thief if you're at or above level 10 with a good amount of DEX. If not, go hunt and train yourself to reach there."], ["Here's a little information on #b#m120000000##k. It's a submarine that's currently parked in between Ellinia and Henesys in Victoria Island. That submarine serves as home to numerous pirates. You can have just as beautiful a view of the ocean there as you do here in Lith Harbor.", "#m120000000# is parked in between Henesys and Ellinia, so if you step out just a bit, you'll be able to enjoy the view of both towns. All the pirates you'll meet in town are very gregarious and friendly as well.", "If you are serious about becoming a #bPirate#k, then you better meet the captain of #m120000000#, #r#p1090000##k. If you are over Level 10 with 20 DEX, then she may let you become one. If you aren't up to that level, then you'll need to train harder to get there!"], ["Alright I'll explain to you more about #bSleepywood#k. It's a forest town located at the southeast side of Victoria Island. It's pretty much in between Henesys and the ant-tunnel dungeon. There's a hotel there, so you can rest up after a long day at the dungeon ... it's a quiet town in general.", "In front of the hotel there's an old buddhist monk by the name of #rChrishrama#k. Nobody knows a thing about that monk. Apparently he collects materials from the travelers and create something, but I am not too sure about the details. If you have any business going around that area, please check that out for me.", "From Sleepywood, head east and you'll find the ant tunnel connected to the deepest part of the Victoria Island. Lots of nasty, powerful monsters abound so if you walk in thinking it's a walk in the park, you'll be coming out as a corpse. You need to fully prepare yourself for a rough ride before going in.", "And this is what I hear ... apparently, at Sleepywood there's a secret entrance leading you to an unknown place. Apparently, once you move in deep, you'll find a stack of black rocks that actually move around. I want to see that for myself in the near future ..."]]; +var townText = [["The town you are at is Lith Harbor! Alright I'll explain to you more about #bLith Harbor#k. It's the place you landed on Victoria Island by riding The Victoria. That's Lith Harbor. A lot of beginners who just got here from Maple Island start their journey here.", "It's a quiet town with the wide body of water on the back of it, thanks to the fact that the harbor is located at the west end of the island. Most of the people here are, or used to be fisherman, so they may look intimidating, but if you strike up a conversation with them, they'll be friendly to you.", "Around town lies a beautiful prairie. Most of the monsters there are small and gentle, perfect for beginners. If you haven't chosen your job yet, this is a good place to boost up your level."],["Alright I'll explain to you more about #bPerion#k. It's a warrior-town located at the northern-most part of Victoria Island, surrounded by rocky mountains. With an unfriendly atmosphere, only the strong survives there.", "Around the highland you'll find a really skinny tree, a wild hog running around the place, and monkeys that live all over the island. There's also a deep valley, and when you go deep into it, you'll find a humongous dragon with the power to match his size. Better go in there very carefully, or don't go at all.", "If you want to be a #bWarrior#k then find #rDances with Balrog#k, the chief of Perion. If you're level 10 or higher, along with a good STR level, he may make you a warrior after all. If not, better keep training yourself until you reach that level."], ["Alright I'll explain to you more about #bEllinia#k. It's a magician-town located at the far east of Victoria Island, and covered in tall, mystic trees. You'll find some fairies there, too. They don't like humans in general so it'll be best for you to be on their good side and stay quiet.", "Near the forest you'll find green slimes, walking mushrooms, monkeys and zombie monkeys all residing there. Walk deeper into the forest and you'll find witches with the flying broomstick navigating the skies. A word of warning: Unless you are really strong, I recommend you don't go near them.", "If you want to be a #bMagician#k, search for #rGrendel the Really Old#k, the head wizard of Ellinia. He may make you a wizard if you're at or above level 8 with a decent amount of INT. If that's not the case, you may have to hunt more and train yourself to get there."], ["Alright I'll explain to you more about #bHenesys#k. It's a bowman-town located at the southernmost part of the island, made on a flatland in the midst of a deep forest and prairies. The weather's just right, and everything is plentiful around that town, perfect for living. Go check it out.", "Around the prairie you'll find weak monsters such as snails, mushrooms, and pigs. According to what I hear, though, in the deepest part of the Pig Park, which is connected to the town somewhere, you'll find a humongous, powerful mushroom called Mushmom every now and then.", "If you want to be a #bBowman#k, you need to go see #rAthena Pierce#k at Henesys. With a level at or above 10 and a decent amount of DEX, she may make you be one afterall. If not, go train yourself, make yourself stronger, then try again."], ["Alright I'll explain to you more about #bKerning City#k. It's a thief-town located at the northwest part of Victoria Island, and there are buildings up there that have just this strange feeling around them. It's mostly covered in black clouds, but if you can go up to a really high place, you'll be able to see a very beautiful sunset there.", "From Kerning City, you can go into several dungeons. You can go to a swamp where alligators and snakes are abound, or hit the subway full of ghosts and bats. At the deepest part of the underground, you'll find Lace, who is just as big and dangerous as a dragon.", "If you want to be a #bThief#k, seek #rDark Lord#k, the heart of darkness of Kerning City. He may well make you a thief if you're at or above level 10 with a good amount of DEX. If not, go hunt and train yourself to reach there."], ["Here's a little information on #b#m120000000##k. It's a submarine that's currently parked in between Ellinia and Henesys in Victoria Island. That submarine serves as home to numerous pirates. You can have just as beautiful a view of the ocean there as you do here in Lith Harbor.", "#m120000000# is parked in between Henesys and Ellinia, so if you step out just a bit, you'll be able to enjoy the view of both towns. All the pirates you'll meet in town are very gregarious and friendly as well.", "If you are serious about becoming a #bPirate#k, then you better meet the captain of #m120000000#, #r#p1090000##k. If you are over Level 10 with 20 DEX, then she may let you become one. If you aren't up to that level, then you'll need to train harder to get there!"], ["Alright I'll explain to you more about #bSleepywood#k. It's a forest town located at the southeast side of Victoria Island. It's pretty much in between Henesys and the ant-tunnel dungeon. There's a hotel there, so you can rest up after a long day at the dungeon ... it's a quiet town in general.", "In front of the hotel there's an old buddhist monk by the name of #rChrishrama#k. Nobody knows a thing about that monk. Apparently he collects materials from the travelers and create something, but I am not too sure about the details. If you have any business going around that area, please check that out for me.", "From Sleepywood, head east and you'll find the ant tunnel connected to the deepest part of the Victoria Island. Lots of nasty, powerful monsters abound so if you walk in thinking it's a walk in the park, you'll be coming out as a corpse. You need to fully prepare yourself for a rough ride before going in.", "And this is what I hear ... apparently, at Sleepywood there's a secret entrance leading you to an unknown place. Apparently, once you move in deep, you'll find a stack of black rocks that actually move around. I want to see that for myself in the near future ..."]]; var selectedMap = -1; var town = false; @@ -17,8 +18,15 @@ function action(mode, type, selection) { cm.sendNext("There's a lot to see in this town, too. Let me know if you want to go somewhere else."); cm.dispose(); return; - }else + }else { status -= 2; + + if(status < 1) { + cm.dispose(); + return; + } + } + } if (status == 1) cm.sendSimple("It's understandable that you may be confused about this place if this is your first time around. If you got any questions about this place, fire away.\r\n#L0##bWhat kind of towns are here in Victoria Island?#l\r\n#L1#Please take me somewhere else.#k#l"); @@ -26,8 +34,8 @@ function action(mode, type, selection) { if (selection == 0){ town = true; var text = "There are 7 big towns here in Victoria Island. Which of those do you want to know more of?#b"; - for(var i = 0; i < maps.length; i++) - text += "\r\n#L" + i + "##m" + maps[i] + "##l"; + for(var i = 0; i < imaps.length; i++) + text += "\r\n#L" + i + "##m" + imaps[i] + "##l"; cm.sendSimple(text); }else if (selection == 1) { var selStr = cm.getJobId() == 0 ? "There's a special 90% discount for all beginners. Alright, where would you want to go?#b" : "Oh you aren't a beginner, huh? Then I'm afraid I may have to charge you full price. Where would you like to go?#b"; diff --git a/scripts/quest/21600.js b/scripts/quest/21600.js new file mode 100644 index 0000000000..7c0b559d87 --- /dev/null +++ b/scripts/quest/21600.js @@ -0,0 +1,47 @@ +/* + 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 . +*/ + +var status = -1; + +function start(mode, type, selection) { + if (mode == -1) { + qm.dispose(); + } else { + if(mode == 0 && type > 0) { + qm.dispose(); + return; + } + + if (mode == 1) + status++; + else + status--; + + if (status == 0) { + qm.sendNext("Hey, Aran. You seem pretty strong, since that time from when you got freed from the glacier. Suitable enough to #bride a wolf#k, if you ask me."); + } else if (status == 1) { + qm.sendAcceptDecline("Picked your interest, huh? Very well, first you must make your way to #bAqua#k, there is a person there who makes #rfood for wolf cubs#k. Bring one portion to me, and I shall deem you able to tame and take care of one. What do you say, will you try for it?"); + } else if (status == 2) { + qm.sendNext("Alright. The one you must meet is #bNanuke#k, she is on top of a #rsnowy whale#k, somewhere in the ocean. Good luck!"); + qm.forceStartQuest(); + + qm.dispose(); + } + } +} \ No newline at end of file diff --git a/scripts/reactor/2002017.js b/scripts/reactor/2002017.js index d26c2eb577..860fdeb063 100644 --- a/scripts/reactor/2002017.js +++ b/scripts/reactor/2002017.js @@ -20,10 +20,10 @@ along with this program. If not, see . */ /*@author Ronan - *Reactor : OrbisPQ Bonus Reactor - 2202004.js + *Reactor : OrbisPQ Bonus Reactor - 2002017.js * Drops all the Bonus Items */ function act() { - rm.dropItems(true, 1, 100, 400, 15); + rm.sprayItems(true, 1, 100, 400, 15); } \ No newline at end of file diff --git a/scripts/reactor/2002018.js b/scripts/reactor/2002018.js new file mode 100644 index 0000000000..51eb167db0 --- /dev/null +++ b/scripts/reactor/2002018.js @@ -0,0 +1,29 @@ +/* + 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 . +*/ +/*@author Ronan + *Reactor : OrbisPQ Bonus Reactor - 2002018.js + * Drops all the Bonus Items + */ + +function act() { + rm.sprayItems(true, 1, 100, 400, 15); +} \ No newline at end of file diff --git a/scripts/reactor/2202004.js b/scripts/reactor/2202004.js index f61f5bdf5a..2f908301ba 100644 --- a/scripts/reactor/2202004.js +++ b/scripts/reactor/2202004.js @@ -25,5 +25,5 @@ */ function act() { - rm.dropItems(true, 1, 30, 60, 15); + rm.sprayItems(true, 1, 30, 60, 15); } \ No newline at end of file diff --git a/scripts/reactor/2512001.js b/scripts/reactor/2512001.js index e139df0688..4f7ffedbe6 100644 --- a/scripts/reactor/2512001.js +++ b/scripts/reactor/2512001.js @@ -29,5 +29,5 @@ function act() { var now = eim.getIntProperty("openedChests"); var nextNum = now + 1; eim.setIntProperty("openedChests", nextNum); - rm.dropItems(true, 1, 50, 100, 15); + rm.sprayItems(true, 1, 50, 100, 15); } \ No newline at end of file diff --git a/scripts/reactor/2612000.js b/scripts/reactor/2612000.js index 96993bcae6..296e3fe143 100644 --- a/scripts/reactor/2612000.js +++ b/scripts/reactor/2612000.js @@ -24,5 +24,5 @@ */ function act() { - rm.dropItems(); + rm.sprayItems(); } \ No newline at end of file diff --git a/scripts/reactor/2612001.js b/scripts/reactor/2612001.js index ff26a29e65..3f881507dc 100644 --- a/scripts/reactor/2612001.js +++ b/scripts/reactor/2612001.js @@ -24,5 +24,5 @@ */ function act() { - rm.dropItems(); + rm.sprayItems(); } \ No newline at end of file diff --git a/scripts/reactor/2612002.js b/scripts/reactor/2612002.js index fb5c188441..4d816c0079 100644 --- a/scripts/reactor/2612002.js +++ b/scripts/reactor/2612002.js @@ -24,5 +24,5 @@ */ function act() { - rm.dropItems(); + rm.sprayItems(); } \ No newline at end of file diff --git a/scripts/reactor/2612003.js b/scripts/reactor/2612003.js index 9b55286f5e..8660dd82d5 100644 --- a/scripts/reactor/2612003.js +++ b/scripts/reactor/2612003.js @@ -24,5 +24,5 @@ */ function act() { - rm.dropItems(); + rm.sprayItems(); } \ No newline at end of file diff --git a/scripts/reactor/2612004.js b/scripts/reactor/2612004.js index 3abc42141d..11f4d68e79 100644 --- a/scripts/reactor/2612004.js +++ b/scripts/reactor/2612004.js @@ -24,5 +24,5 @@ */ function act() { - rm.dropItems(); + rm.sprayItems(); } \ No newline at end of file diff --git a/scripts/reactor/6102002.js b/scripts/reactor/6102002.js index c9d7131fb8..43e01c504e 100644 --- a/scripts/reactor/6102002.js +++ b/scripts/reactor/6102002.js @@ -25,5 +25,5 @@ */ function act() { - rm.dropItems(true, 1, 90, 360, 15); + rm.sprayItems(true, 1, 90, 360, 15); } \ No newline at end of file diff --git a/scripts/reactor/6102003.js b/scripts/reactor/6102003.js index c47e6f39a6..e64a3ebec5 100644 --- a/scripts/reactor/6102003.js +++ b/scripts/reactor/6102003.js @@ -25,5 +25,5 @@ */ function act() { - rm.dropItems(true, 1, 90, 360, 15); + rm.sprayItems(true, 1, 90, 360, 15); } \ No newline at end of file diff --git a/scripts/reactor/6102004.js b/scripts/reactor/6102004.js index d65fbe829d..cd7d66fe58 100644 --- a/scripts/reactor/6102004.js +++ b/scripts/reactor/6102004.js @@ -25,5 +25,5 @@ */ function act() { - rm.dropItems(true, 1, 90, 360, 15); + rm.sprayItems(true, 1, 90, 360, 15); } \ No newline at end of file diff --git a/scripts/reactor/6102005.js b/scripts/reactor/6102005.js index 269ba15fc2..ec8bd18894 100644 --- a/scripts/reactor/6102005.js +++ b/scripts/reactor/6102005.js @@ -25,5 +25,5 @@ */ function act() { - rm.dropItems(true, 1, 90, 360, 15); + rm.sprayItems(true, 1, 90, 360, 15); } \ No newline at end of file diff --git a/scripts/reactor/6702003.js b/scripts/reactor/6702003.js index 19b156a46a..ba3daa9652 100644 --- a/scripts/reactor/6702003.js +++ b/scripts/reactor/6702003.js @@ -29,6 +29,6 @@ function act() { if (rand < 1) rand = 1; //We'll make it drop a lot of crap :D for (var i = 0; i + 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 . +*/ +/** + *AmoriaPQ Bonus Reactor + *6702012.js + */ + +function act() { + rand = Math.floor(Math.random() * 4); + if (rand < 1) rand = 1; + //We'll make it drop a lot of crap :D + for (var i = 0; i 80) { //Hmm - if (!theSkill.getAction()) { + if (!mySkill.getAction()) { AutobanFactory.FAST_ATTACK.autoban(chr, "WZ Edit; adding action to a skill: " + display); return null; } diff --git a/src/scripting/reactor/ReactorActionManager.java b/src/scripting/reactor/ReactorActionManager.java index c8ef2172b3..dfe6418cdb 100644 --- a/src/scripting/reactor/ReactorActionManager.java +++ b/src/scripting/reactor/ReactorActionManager.java @@ -21,6 +21,7 @@ */ package scripting.reactor; +import client.MapleCharacter; import client.MapleClient; import client.inventory.Equip; import client.inventory.Item; @@ -53,6 +54,7 @@ public class ReactorActionManager extends AbstractPlayerInteraction { private MapleReactor reactor; private MapleClient client; private Invocable iv; + private ScheduledFuture sprayTask = null; public ReactorActionManager(MapleClient c, MapleReactor reactor, Invocable iv) { super(c); @@ -69,6 +71,22 @@ public class ReactorActionManager extends AbstractPlayerInteraction { reactor.getMap().destroyNPC(npcId); } + public void sprayItems() { + sprayItems(false, 0, 0, 0, 0); + } + + public void sprayItems(boolean meso, int mesoChance, int minMeso, int maxMeso) { + sprayItems(meso, mesoChance, minMeso, maxMeso, 0); + } + + public void sprayItems(boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) { + sprayItems((int)reactor.getPosition().getX(), (int)reactor.getPosition().getY(), meso, mesoChance, minMeso, maxMeso, minItems); + } + + public void sprayItems(int posX, int posY, boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) { + dropItems(true, posX, posY, meso, mesoChance, minMeso, maxMeso, minItems); + } + public void dropItems() { dropItems(false, 0, 0, 0, 0); } @@ -82,6 +100,10 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } public void dropItems(int posX, int posY, boolean meso, int mesoChance, int minMeso, int maxMeso, int minItems) { + dropItems(false, posX, posY, meso, mesoChance, minMeso, maxMeso, minItems); + } + + public void dropItems(boolean delayed, int posX, int posY, boolean meso, int mesoChance, final int minMeso, final int maxMeso, int minItems) { List chances = getDropChances(); List items = new LinkedList<>(); int numItems = 0; @@ -105,24 +127,61 @@ public class ReactorActionManager extends AbstractPlayerInteraction { final Point dropPos = new Point(posX, posY); dropPos.x -= (12 * numItems); - for (ReactorDropEntry d : items) { - if (d.itemId == 0) { - int range = maxMeso - minMeso; - int displayDrop = (int) (Math.random() * range) + minMeso; - int mesoDrop = (displayDrop * client.getWorldServer().getMesoRate()); - reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, client.getPlayer(), false, (byte) 2); - } else { - Item drop; - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - if (ii.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) { - drop = new Item(d.itemId, (short) 0, (short) 1); + if(!delayed) { + for (ReactorDropEntry d : items) { + if (d.itemId == 0) { + int range = maxMeso - minMeso; + int displayDrop = (int) (Math.random() * range) + minMeso; + int mesoDrop = (displayDrop * client.getWorldServer().getMesoRate()); + reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, client.getPlayer(), false, (byte) 2); } else { - drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId)); + Item drop; + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + if (ii.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) { + drop = new Item(d.itemId, (short) 0, (short) 1); + } else { + drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId)); + } + + reactor.getMap().dropFromReactor(getPlayer(), reactor, drop, dropPos, (short)d.questid); } - - reactor.getMap().dropFromReactor(getPlayer(), reactor, drop, dropPos, (short)d.questid); + dropPos.x += 25; } - dropPos.x += 25; + } else { + final MapleCharacter chr = client.getPlayer(); + final MapleReactor r = reactor; + final List dropItems = items; + final int worldMesoRate = client.getWorldServer().getMesoRate(); + + sprayTask = TimerManager.getInstance().register(new Runnable() { + @Override + public void run() { + if(dropItems.isEmpty()) { + sprayTask.cancel(false); + return; + } + + ReactorDropEntry d = dropItems.remove(0); + if (d.itemId == 0) { + int range = maxMeso - minMeso; + int displayDrop = (int) (Math.random() * range) + minMeso; + int mesoDrop = (displayDrop * worldMesoRate); + r.getMap().spawnMesoDrop(mesoDrop, r.getMap().calcDropPos(dropPos, r.getPosition()), r, chr, false, (byte) 2); + } else { + Item drop; + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + if (ii.getInventoryType(d.itemId) != MapleInventoryType.EQUIP) { + drop = new Item(d.itemId, (short) 0, (short) 1); + } else { + drop = ii.randomizeStats((Equip) ii.getEquipById(d.itemId)); + } + + r.getMap().dropFromReactor(getPlayer(), r, drop, dropPos, (short)d.questid); + } + + dropPos.x += 25; + } + }, 100); } } diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index dd9de7369a..30211f9985 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -52,7 +52,9 @@ import java.util.Map.Entry; import java.util.Random; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; +import tools.locks.MonitoredReentrantLock; import tools.locks.MonitoredReentrantReadWriteLock; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; @@ -90,6 +92,8 @@ import tools.locks.MonitoredLockType; public class MapleMap { private static final List rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR); + private static final Map> dropBoundsCache = new HashMap<>(100); + private Map mapobjects = new LinkedHashMap<>(); private Collection monsterSpawn = Collections.synchronizedList(new LinkedList()); private Collection allMonsterSpawn = Collections.synchronizedList(new LinkedList()); @@ -104,6 +108,7 @@ public class MapleMap { private LinkedList> registeredDrops = new LinkedList<>(); private List areas = new ArrayList<>(); private MapleFootholdTree footholds = null; + private Pair xLimits; // caches the min and max x's with available footholds private Rectangle mapArea = new Rectangle(); private int mapid; private AtomicInteger runningOid = new AtomicInteger(1000000001); @@ -148,12 +153,16 @@ public class MapleMap { private MapleSnowball snowball0 = null; private MapleSnowball snowball1 = null; private MapleCoconut coconut; + //locks private final ReadLock chrRLock; private final WriteLock chrWLock; private final ReadLock objectRLock; private final WriteLock objectWLock; + // due to the nature of loadMapFromWz (synchronized), sole function that calls 'generateMapDropRangeCache', this lock remains optional. + private static final Lock bndLock = new MonitoredReentrantLock(MonitoredLockType.MAP_BOUNDS, true); + public MapleMap(int mapid, int world, int channel, int returnMapId, float monsterRate) { this.mapid = mapid; this.channel = channel; @@ -437,17 +446,63 @@ public class MapleMap { return new Point(initial.x, dropY); } + public void generateMapDropRangeCache() { + bndLock.lock(); + try { + Integer mapId = Integer.valueOf(mapid); + Pair bounds = dropBoundsCache.get(mapId); + + if(bounds != null) { + xLimits = bounds; + } else { + Point lp = new Point(mapArea.x, mapArea.y), rp = new Point(mapArea.x + mapArea.width, mapArea.y), fallback = new Point(mapArea.x + (mapArea.width / 2), mapArea.y); + + lp = bsearchDropPos(lp, fallback); + rp = bsearchDropPos(rp, fallback); + + xLimits = new Pair<>(lp.x, rp.x); + dropBoundsCache.put(mapId, xLimits); + } + } finally { + bndLock.unlock(); + } + } + + public Point bsearchDropPos(Point initial, Point fallback) { + Point res, dropPos = null; + + int awayx = fallback.x; + int homex = initial.x; + + int y = initial.y - 85; + + do { + int distx = awayx - homex; + int dx = distx / 2; + + int searchx = homex + dx; + if((res = calcPointBelow(new Point(searchx, y))) != null) { + awayx = searchx; + dropPos = res; + } else { + homex = searchx; + } + } while(Math.abs(homex - awayx) > 5); + + return (dropPos != null) ? dropPos : fallback; + } + public Point calcDropPos(Point initial, Point fallback) { + if(initial.x < xLimits.left) initial.x = xLimits.left; + else if(initial.x > xLimits.right) initial.x = xLimits.right; + Point ret = calcPointBelow(new Point(initial.x, initial.y - 85)); if (ret == null) { + ret = bsearchDropPos(initial, fallback); + } + + if(!mapArea.contains(ret)) { // found drop pos outside the map :O return fallback; - } else if(!mapArea.contains(ret)) { - if(initial.y > mapArea.y + mapArea.height) return fallback; // found drop pos underneath the map :O - - int borderX = (initial.x < mapArea.x) ? mapArea.x : mapArea.x + mapArea.width; - ret = calcPointBelow(new Point(borderX, initial.y - 85)); - - if(ret == null) return fallback; } return ret; diff --git a/src/server/maps/MapleMapFactory.java b/src/server/maps/MapleMapFactory.java index 956ade98eb..747b87664c 100644 --- a/src/server/maps/MapleMapFactory.java +++ b/src/server/maps/MapleMapFactory.java @@ -275,7 +275,9 @@ public class MapleMapFactory { e.printStackTrace(); // swallow cause I'm cool } + map.setBackgroundTypes(backTypes); + map.generateMapDropRangeCache(); mapsWLock.lock(); try { diff --git a/src/server/quest/requirements/ItemRequirement.java b/src/server/quest/requirements/ItemRequirement.java index 1e9351b404..a91dd60c9e 100644 --- a/src/server/quest/requirements/ItemRequirement.java +++ b/src/server/quest/requirements/ItemRequirement.java @@ -73,10 +73,19 @@ public class ItemRequirement extends MapleQuestRequirement { count += item.getQuantity(); } //Weird stuff, nexon made some quests only available when wearing gm clothes. This enables us to accept it >< - if (iType.equals(MapleInventoryType.EQUIP) && chr.isGM()) { - for (Item item : chr.getInventory(MapleInventoryType.EQUIPPED).listById(itemId)) { - count += item.getQuantity(); - } + if (iType.equals(MapleInventoryType.EQUIP)) { + if(chr.isGM()) { + for (Item item : chr.getInventory(MapleInventoryType.EQUIPPED).listById(itemId)) { + count += item.getQuantity(); + } + } else { + if(count < countNeeded) { + if(chr.getInventory(MapleInventoryType.EQUIPPED).countById(itemId) + count >= countNeeded) { + chr.dropMessage(5, "Unequip the required " + ii.getName(itemId) + " before trying this quest operation."); + return false; + } + } + } } if(count < countNeeded || countNeeded <= 0 && count > 0) { diff --git a/src/tools/locks/MonitoredLockType.java b/src/tools/locks/MonitoredLockType.java index 25f80c8d46..2c3fc4cd50 100644 --- a/src/tools/locks/MonitoredLockType.java +++ b/src/tools/locks/MonitoredLockType.java @@ -66,8 +66,9 @@ public enum MonitoredLockType { MAP_OBJS(37), MAP_FACTORY(38), MAP_ITEM(39), - MINIDUNGEON(40), - REACTOR(41); + MAP_BOUNDS(41), + MINIDUNGEON(41), + REACTOR(42); private final int i; diff --git a/tools/MapleMapInfoRetriever/build.xml b/tools/MapleMapInfoRetriever/build.xml new file mode 100644 index 0000000000..cf88a68eb8 --- /dev/null +++ b/tools/MapleMapInfoRetriever/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project MapleMapInfoRetriever. + + + diff --git a/tools/MapleMapInfoRetriever/lib/MapReport.txt b/tools/MapleMapInfoRetriever/lib/MapReport.txt new file mode 100644 index 0000000000..ab46af9362 --- /dev/null +++ b/tools/MapleMapInfoRetriever/lib/MapReport.txt @@ -0,0 +1 @@ +All map files contains 'info' node. diff --git a/tools/MapleMapInfoRetriever/lib/commons-io-2.6.jar b/tools/MapleMapInfoRetriever/lib/commons-io-2.6.jar new file mode 100644 index 0000000000..00556b119d Binary files /dev/null and b/tools/MapleMapInfoRetriever/lib/commons-io-2.6.jar differ diff --git a/tools/MapleMapInfoRetriever/manifest.mf b/tools/MapleMapInfoRetriever/manifest.mf new file mode 100644 index 0000000000..328e8e5bc3 --- /dev/null +++ b/tools/MapleMapInfoRetriever/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/tools/MapleMapInfoRetriever/nbproject/build-impl.xml b/tools/MapleMapInfoRetriever/nbproject/build-impl.xml new file mode 100644 index 0000000000..4689696128 --- /dev/null +++ b/tools/MapleMapInfoRetriever/nbproject/build-impl.xml @@ -0,0 +1,1448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set platform.home + Must set platform.bootcp + Must set platform.java + Must set platform.javac + + The J2SE Platform is not correctly set up. + Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. + Either open the project in the IDE and setup the Platform with the same name or add it manually. + For example like this: + ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file) + or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + ${platform.java} -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/MapleMapInfoRetriever/nbproject/genfiles.properties b/tools/MapleMapInfoRetriever/nbproject/genfiles.properties new file mode 100644 index 0000000000..d33257510b --- /dev/null +++ b/tools/MapleMapInfoRetriever/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=8863f245 +build.xml.script.CRC32=86cbb34a +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=8863f245 +nbproject/build-impl.xml.script.CRC32=187fba9b +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/tools/MapleMapInfoRetriever/nbproject/project.properties b/tools/MapleMapInfoRetriever/nbproject/project.properties new file mode 100644 index 0000000000..787026132a --- /dev/null +++ b/tools/MapleMapInfoRetriever/nbproject/project.properties @@ -0,0 +1,77 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=MapleMapInfoRetriever +application.vendor=RonanLana +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Os arquivos em build.classes.dir que devem ser exclu\u00eddos do jar de distribui\u00e7\u00e3o +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/MapleMapInfoRetriever.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.commons-io-2.6.jar=lib/commons-io-2.6.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.commons-io-2.6.jar} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.7 +javac.target=1.7 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=maplemapinforetriever.MapleMapInfoRetriever +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=JDK_1.7 +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/tools/MapleMapInfoRetriever/nbproject/project.xml b/tools/MapleMapInfoRetriever/nbproject/project.xml new file mode 100644 index 0000000000..b7399e9dce --- /dev/null +++ b/tools/MapleMapInfoRetriever/nbproject/project.xml @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + MapleMapInfoRetriever + + + + + + + + + + diff --git a/tools/MapleMapInfoRetriever/src/maplemapinforetriever/MapleMapInfoRetriever.java b/tools/MapleMapInfoRetriever/src/maplemapinforetriever/MapleMapInfoRetriever.java new file mode 100644 index 0000000000..9612ffba90 --- /dev/null +++ b/tools/MapleMapInfoRetriever/src/maplemapinforetriever/MapleMapInfoRetriever.java @@ -0,0 +1,182 @@ +/* + 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 maplemapinforetriever; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.apache.commons.io.FileUtils; + +/** + * + * @author RonanLana + * + * The main objective of this tool is to locate all mapids that doesn't have + * the "info" node in their WZ node tree. + */ +public class MapleMapInfoRetriever { + static String mapWzPath = "../../wz/Map.wz/Map"; + static String newFile = "lib/MapReport.txt"; + + static List missingInfo = new ArrayList<>(); + + static PrintWriter printWriter = null; + static InputStreamReader fileReader = null; + static BufferedReader bufferedReader = null; + static byte status = 0; + static boolean hasInfo; + + 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[50]; + token.getChars(i, j, dest, 0); + + d = new String(dest); + return(d.trim()); + } + + private static void forwardCursor(int st) { + String line = null; + + try { + while(status >= st && (line = bufferedReader.readLine()) != null) { + simpleToken(line); + } + } + catch(Exception e) { + e.printStackTrace(); + } + } + + private static void simpleToken(String token) { + if(token.contains("/imgdir")) { + status -= 1; + } + else if(token.contains("imgdir")) { + status += 1; + } + } + + private static boolean translateToken(String token) { + String d; + int temp; + + if(token.contains("/imgdir")) { + status -= 1; + } + else if(token.contains("imgdir")) { + if(status == 1) { + d = getName(token); + if(d.contains("info")) { + hasInfo = true; + return true; + } + + temp = status; + forwardCursor(temp); + } + + status += 1; + } + + return false; + } + + private static void searchMapDirectory(int mapArea) { + try { + Iterator iter = FileUtils.iterateFiles(new File(mapWzPath + "/Map" + mapArea), new String[]{"xml"}, true); + System.out.println("Parsing map area " + mapArea); + + while(iter.hasNext()) { + File file = (File) iter.next(); + searchMapFile(file); + } + } catch(IllegalArgumentException e) {} + } + + private static void searchMapFile(File file) { + // This will reference one line at a time + String line = null; + + try { + fileReader = new InputStreamReader(new FileInputStream(file), "UTF-8"); + bufferedReader = new BufferedReader(fileReader); + + hasInfo = false; + status = 0; + + while((line = bufferedReader.readLine()) != null) { + if(translateToken(line)) { + break; + } + } + + if(!hasInfo) missingInfo.add(Integer.valueOf(file.getName().split(".img.xml")[0])); + + bufferedReader.close(); + fileReader.close(); + } + + catch(IOException ex) { + System.out.println("Error reading file '" + file.getName() + "'"); + } + catch(Exception e) { + e.printStackTrace(); + } + } + + private static void writeReport() { + try { + printWriter = new PrintWriter(newFile, "UTF-8"); + + if(!missingInfo.isEmpty()) { + for(Integer i : missingInfo) { + printWriter.println(i); + } + } else { + printWriter.println("All map files contains 'info' node."); + } + + printWriter.close(); + } catch(IOException e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + for(int i = 0; i < 10; i++) { + searchMapDirectory(i); + } + writeReport(); + } + +} diff --git a/tools/MapleQuestItemFetcher/nbproject/private/private.xml b/tools/MapleQuestItemFetcher/nbproject/private/private.xml index 35ad24d01c..6807a2ba19 100644 --- a/tools/MapleQuestItemFetcher/nbproject/private/private.xml +++ b/tools/MapleQuestItemFetcher/nbproject/private/private.xml @@ -2,8 +2,6 @@ - - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java - + diff --git a/tools/MobBookUpdate/nbproject/private/private.xml b/tools/MobBookUpdate/nbproject/private/private.xml index 6be0bf5534..6807a2ba19 100644 --- a/tools/MobBookUpdate/nbproject/private/private.xml +++ b/tools/MobBookUpdate/nbproject/private/private.xml @@ -2,8 +2,6 @@ - - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/tools/MobBookUpdate/src/mobbookupdate/MobBookUpdate.java - +