diff --git a/build/built-jar.properties b/build/built-jar.properties index 06a37cbd0d..98066efaee 100644 --- a/build/built-jar.properties +++ b/build/built-jar.properties @@ -1,4 +1,4 @@ -#Sat, 28 Oct 2017 23:16:56 -0200 +#Tue, 31 Oct 2017 11:20:58 -0200 C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2= diff --git a/build/classes/client/MapleCharacter$1.class b/build/classes/client/MapleCharacter$1.class index da5ee830d5..87398f4d80 100644 Binary files a/build/classes/client/MapleCharacter$1.class and b/build/classes/client/MapleCharacter$1.class differ diff --git a/build/classes/client/MapleCharacter$10.class b/build/classes/client/MapleCharacter$10.class index 57ae677db0..eff6f78768 100644 Binary files a/build/classes/client/MapleCharacter$10.class and b/build/classes/client/MapleCharacter$10.class differ diff --git a/build/classes/client/MapleCharacter$11.class b/build/classes/client/MapleCharacter$11.class index 54555bacb8..e0a2a33c7a 100644 Binary files a/build/classes/client/MapleCharacter$11.class and b/build/classes/client/MapleCharacter$11.class differ diff --git a/build/classes/client/MapleCharacter$12.class b/build/classes/client/MapleCharacter$12.class index 7463c88d0d..50664fb8c9 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 256b4edd77..f77c87cfc3 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 4f3f3c8552..30e9380844 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 b44992588b..aa84d348ef 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 84b1eff0c0..f663b38dd9 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 84375f2f2f..1cc80b6723 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 ff901e8fbc..7270f391d5 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 4fc9d400f8..c5d622de8d 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$2.class b/build/classes/client/MapleCharacter$2.class index 73f924764d..1f87caa233 100644 Binary files a/build/classes/client/MapleCharacter$2.class and b/build/classes/client/MapleCharacter$2.class differ diff --git a/build/classes/client/MapleCharacter$3.class b/build/classes/client/MapleCharacter$3.class index 6e085c17af..020c0f7762 100644 Binary files a/build/classes/client/MapleCharacter$3.class and b/build/classes/client/MapleCharacter$3.class differ diff --git a/build/classes/client/MapleCharacter$4.class b/build/classes/client/MapleCharacter$4.class index 2d5be9fd72..d559e93775 100644 Binary files a/build/classes/client/MapleCharacter$4.class and b/build/classes/client/MapleCharacter$4.class differ diff --git a/build/classes/client/MapleCharacter$5.class b/build/classes/client/MapleCharacter$5.class index d81759f696..20d1f4b110 100644 Binary files a/build/classes/client/MapleCharacter$5.class and b/build/classes/client/MapleCharacter$5.class differ diff --git a/build/classes/client/MapleCharacter$6.class b/build/classes/client/MapleCharacter$6.class index e094e91f35..636bd00563 100644 Binary files a/build/classes/client/MapleCharacter$6.class and b/build/classes/client/MapleCharacter$6.class differ diff --git a/build/classes/client/MapleCharacter$7.class b/build/classes/client/MapleCharacter$7.class index 04993b21e7..303f3ecd45 100644 Binary files a/build/classes/client/MapleCharacter$7.class and b/build/classes/client/MapleCharacter$7.class differ diff --git a/build/classes/client/MapleCharacter$8.class b/build/classes/client/MapleCharacter$8.class index 5b6bbb77a0..2b3a7ebf0d 100644 Binary files a/build/classes/client/MapleCharacter$8.class and b/build/classes/client/MapleCharacter$8.class differ diff --git a/build/classes/client/MapleCharacter$9.class b/build/classes/client/MapleCharacter$9.class index 14db0f1ff4..b47a0da589 100644 Binary files a/build/classes/client/MapleCharacter$9.class and b/build/classes/client/MapleCharacter$9.class differ diff --git a/build/classes/client/MapleCharacter$FameStatus.class b/build/classes/client/MapleCharacter$FameStatus.class index a8cc4a25f2..2180fcb4c5 100644 Binary files a/build/classes/client/MapleCharacter$FameStatus.class and b/build/classes/client/MapleCharacter$FameStatus.class differ diff --git a/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class b/build/classes/client/MapleCharacter$MapleBuffStatValueHolder.class index 1b6503f9b6..b9fca1d6f8 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 ad1d0550fa..4ff5af6d31 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 934a9752f1..e15774c7ec 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 1a9d6c42f6..11ac99aead 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 026abb3fdb..26c329a4f6 100644 Binary files a/build/classes/client/command/Commands.class and b/build/classes/client/command/Commands.class differ diff --git a/build/classes/client/inventory/MaplePet.class b/build/classes/client/inventory/MaplePet.class index f6baec8743..a53437ccad 100644 Binary files a/build/classes/client/inventory/MaplePet.class and b/build/classes/client/inventory/MaplePet.class differ diff --git a/build/classes/net/server/guild/MapleAlliance.class b/build/classes/net/server/guild/MapleAlliance.class index 6f98eb2b78..4df2e188be 100644 Binary files a/build/classes/net/server/guild/MapleAlliance.class and b/build/classes/net/server/guild/MapleAlliance.class differ diff --git a/build/classes/net/server/guild/MapleGuild$BCOp.class b/build/classes/net/server/guild/MapleGuild$BCOp.class index 59aef5a9a5..9ecd950385 100644 Binary files a/build/classes/net/server/guild/MapleGuild$BCOp.class and b/build/classes/net/server/guild/MapleGuild$BCOp.class differ diff --git a/build/classes/net/server/guild/MapleGuild.class b/build/classes/net/server/guild/MapleGuild.class index 463fab59ef..48cad75b36 100644 Binary files a/build/classes/net/server/guild/MapleGuild.class and b/build/classes/net/server/guild/MapleGuild.class differ diff --git a/build/classes/server/MaplePlayerShop.class b/build/classes/server/MaplePlayerShop.class index 4617a9106d..d9f2584b50 100644 Binary files a/build/classes/server/MaplePlayerShop.class and b/build/classes/server/MaplePlayerShop.class differ diff --git a/dist/MapleSolaxia.jar b/dist/MapleSolaxia.jar index 5f125551bb..6a909156ad 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 9c46f20edf..2a68a933f1 100644 --- a/docs/feature_list.txt +++ b/docs/feature_list.txt @@ -45,6 +45,18 @@ Cash & Items: * New scroll: antibanish. For use only in cases where bosses send a player back to town. * Inventory system properly checks for item slot free space and ownership. * Storage with "Arrange Items" feature functional. +* Vega's spell. +* Owl of Minerva. +* Pet item ignore. + +Monsters & Maps: +* 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. +* Every skill/mastery book is now droppable by mobs. +* Added Boss HP Bar for dozens of bosses (needs provided custom wz). +* 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. PQ potentials: * Lobby system - Multiple PQ instances on same channel. @@ -52,36 +64,28 @@ PQ potentials: * Guild queue system - Guilds can register themselves on a queue for the GPQ. * EIM Pool system - After the first instance setup, next event instances are loaded beforehand and set on a pooling queue, optimizing future loadouts. -Server potentials: -* Multi-worlds 100%. +Player potentials: * Adventurer Mount quests 100%. * All Equipment levels up. * Player level rates. * Gain fame by quests. -* Every monsterbook card is now droppable by overworld mobs. -* Monsterbook displays drop data info conformant with the underlying DB (needs custom wz). See more on the MobBookUpdate feature. -* Mastery book announcer displays droppers of needed books of a player, by reading underlying DB. -* Every skill/mastery book is now droppable by mobs. + +Server potentials: +* Multi-worlds 100%. * Inventory auto-gather and auto-sorting feature. * Enhanced auto-pot system: pet uses as many potions as necessary to reach the desired threshold. * Enhanced buff system: smartly checks for the best available buff effects to be active on the player. * Enhanced AP auto-assigner: exactly matches AP with the needed for the player's current level, surplus assigned to the primary attribute. -* Added Boss HP Bar for dozens of bosses (needs provided custom wz). -* If multiple bosses are on the same area, client will prioritize Boss HP bar of the target of the player. +* Mastery book announcer displays droppers of needed books of a player, by reading underlying DB. * Custom jail system (needs provided custom wz). * Delete Character 100% (requires ENABLE_PIC activated). -* Boats, elevator and other travelling mechanics fully working. -* Enabled Hired Merchant being able to be used anywhere but FM Entrance and other few places. -* Vega's spell. -* Owl of Minerva. -* Pet item ignore. * Autosaver (periodically saves on DB current state of every player in-game). -* Fixed and randomized versions of HP/MP growth rate, regarding player job. Placeholder for HP/MP washing feature. +* Both fixed and randomized versions of HP/MP growth rate abailable, regarding player job (enable one at ServerConstants). Placeholder for HP/MP washing feature. Admin/GM commands: * Server commands layered by GM levels. -* New commands. * Spawn Zakum/Horntail/Pinkbean 100%. +* New commands. Project: * Organized project code. diff --git a/docs/mcpq/2042002.js b/docs/mcpq/blob/2042002.js similarity index 100% rename from docs/mcpq/2042002.js rename to docs/mcpq/blob/2042002.js diff --git a/docs/mcpq/MCBattlefield.java b/docs/mcpq/blob/MCBattlefield.java similarity index 100% rename from docs/mcpq/MCBattlefield.java rename to docs/mcpq/blob/MCBattlefield.java diff --git a/docs/mcpq/MCField.java b/docs/mcpq/blob/MCField.java similarity index 100% rename from docs/mcpq/MCField.java rename to docs/mcpq/blob/MCField.java diff --git a/docs/mcpq/MCGuardian.java b/docs/mcpq/blob/MCGuardian.java similarity index 100% rename from docs/mcpq/MCGuardian.java rename to docs/mcpq/blob/MCGuardian.java diff --git a/docs/mcpq/MCParty.java b/docs/mcpq/blob/MCParty.java similarity index 100% rename from docs/mcpq/MCParty.java rename to docs/mcpq/blob/MCParty.java diff --git a/docs/mcpq/MCSkill.java b/docs/mcpq/blob/MCSkill.java similarity index 100% rename from docs/mcpq/MCSkill.java rename to docs/mcpq/blob/MCSkill.java diff --git a/docs/mcpq/MCSkillFactory.java b/docs/mcpq/blob/MCSkillFactory.java similarity index 100% rename from docs/mcpq/MCSkillFactory.java rename to docs/mcpq/blob/MCSkillFactory.java diff --git a/docs/mcpq/MCTracker.java b/docs/mcpq/blob/MCTracker.java similarity index 100% rename from docs/mcpq/MCTracker.java rename to docs/mcpq/blob/MCTracker.java diff --git a/docs/mcpq/MCWZData.java b/docs/mcpq/blob/MCWZData.java similarity index 100% rename from docs/mcpq/MCWZData.java rename to docs/mcpq/blob/MCWZData.java diff --git a/docs/mcpq/MonsterCarnival.java b/docs/mcpq/blob/MonsterCarnival.java similarity index 100% rename from docs/mcpq/MonsterCarnival.java rename to docs/mcpq/blob/MonsterCarnival.java diff --git a/docs/mcpq/readme.txt b/docs/mcpq/readme.txt index 940af38fdd..8b5fcb5a4e 100644 --- a/docs/mcpq/readme.txt +++ b/docs/mcpq/readme.txt @@ -1 +1,3 @@ -Extra classes for Monster Carnival. Can possibly be used for implementing MCPQ. \ No newline at end of file +Blob contains extra classes for Monster Carnival. Can possibly be used for implementing MCPQ. + +Scripts and Src contains the code changed on OdinMS to have CPQ working. \ No newline at end of file diff --git a/docs/mcpq/scripts/npc/2042000.js b/docs/mcpq/scripts/npc/2042000.js new file mode 100644 index 0000000000..a081c3f01d --- /dev/null +++ b/docs/mcpq/scripts/npc/2042000.js @@ -0,0 +1,82 @@ +/** * [MENTION=19862]id[/MENTION] 2042000 + * [MENTION=806871]NPC[/MENTION] Spiegelmann + * [MENTION=836108]Function[/MENTION] Monster Carnival Lobby NPC + * @author s4nta + */ + +// Relevant Monster Carnival classes +var MonsterCarnival = net.sf.odinms.server.partyquest.mcpq.MonsterCarnival; +var MCTracker = net.sf.odinms.server.partyquest.mcpq.MCTracker; +var MCParty = net.sf.odinms.server.partyquest.mcpq.MCParty; +var MCField = net.sf.odinms.server.partyquest.mcpq.MCField; +var MCTeam = net.sf.odinms.server.partyquest.mcpq.MCField.MCTeam; + +// NPC variables +var status = -1; +var carnival, field; +var room = -1; + +function start() { + if (cm.getMapId() != 980000000) { + MCTracker.log("Spiegelmann called on invalid map " + cm.getMapId() + " by player " + cm.getName()); + cm.sendOk("You are not authorized to do this."); + cm.dispose(); + return; + } + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + return; + } + if (mode == 1) status++; + else status--; + + if (status == 0) { + if (cm.getParty() == null) { + cm.sendOk("You are not in a party."); + cm.dispose(); + return; + } else if (!cm.isLeader()) { + cm.sendOk("If you want to try Carnival PQ, please tell the #bleader of your party#k to talk to me."); + cm.dispose(); + return; + } + carnival = MonsterCarnival.getMonsterCarnival(cm.getChannel()); + cm.sendSimple(carnival.getNPCAvailableFields()); + } else if (status == 1) { + room = selection; + if (room < 1 || room > 6) { + cm.sendOk("That is not a valid room."); + cm.dispose(); + return; + } + var code = carnival.registerStatus(cm.getParty(), selection); + if (code == MonsterCarnival.STATUS_FIELD_FULL) { + cm.sendOk("This room is currently full.") + } else if (code == MonsterCarnival.STATUS_PARTY_SIZE) { + cm.sendOk("Your party is not the right size for this field."); + } else if (code == MonsterCarnival.STATUS_PARTY_LEVEL) { + cm.sendOk("Please check to see that the members in your party are between level 30 and 50."); + } else if (code == MonsterCarnival.STATUS_PARTY_MISSING) { + cm.sendOk("Please make sure everyone in your party is in this lobby."); + } else if (code == MonsterCarnival.STATUS_FIELD_INVALID) { + cm.sendOk("Unauthorized request."); + } + + if (code == MonsterCarnival.STATUS_PROCEED) { + field = carnival.getField(room); + party = carnival.createParty(cm.getParty()); + field.register(party, MCTeam.RED); + cm.sendOk("You will have 3 minutes to accept challenges from other parties."); + } else if (code == MonsterCarnival.STATUS_REQUEST) { + cm.sendOk("Sending request to room " + room + ". You will be automatically warped in if they accept your challenge."); + field = carnival.getField(room); + party = carnival.createParty(cm.getParty()); + field.request(party); + } + cm.dispose(); + } +} \ No newline at end of file diff --git a/docs/mcpq/scripts/npc/2042002.js b/docs/mcpq/scripts/npc/2042002.js new file mode 100644 index 0000000000..c8ec9d2d58 --- /dev/null +++ b/docs/mcpq/scripts/npc/2042002.js @@ -0,0 +1,326 @@ +/** * [MENTION=19862]id[/MENTION] 2042002 + * [MENTION=806871]NPC[/MENTION] Spiegelmann + * [MENTION=836108]Function[/MENTION] Monster Carnival NPC + * @author s4nta + * [MENTION=497496]cred[/MENTION]its xirengfx (for store code, CPQ description) + */ +var DISABLED = false; + +var SavedLocationType = Packages.net.sf.odinms.server.maps.SavedLocationType; + +// Relevant Monster Carnival classes +var MonsterCarnival = Packages.net.sf.odinms.server.partyquest.mcpq.MonsterCarnival; +var MCTracker = Packages.net.sf.odinms.server.partyquest.mcpq.MCTracker; +var MCParty = Packages.net.sf.odinms.server.partyquest.mcpq.MCParty; +var MCField = Packages.net.sf.odinms.server.partyquest.mcpq.MCField; + +// NPC variables +var status = -1; +var store = false; +var ctx = -1; //context +var storeInfo; +var purchaseId; +var purchaseCost; + +// Reference +var coinId = 4001129; +var coinIcon = "#i" + coinId + "#"; +var infoMaps = [220000000, 200000000, 103000000, 540000000]; // ludi, orbis, kerning, singapore +var gradeS = 600 +var gradeA = 500 +var gradeB = 400 +var gradeC = 300 +var gradeD = 200 +var gradeE = 100 + +var expRewards = [[150000, 100000], // S Winner/Loser + [100000, 70000], // A Winner/Loser + [75000, 43250], // B Winner/Loser + [50000, 25000], // C Winner/Loser + [25000, 12500], // D Winner/Loser + [12500, 6250], // E Winner/Loser + [5000, 2500] // F Winner/Loser + ]; + +// Exchange stores +var warrior = [[1302004, 7], [1402006, 7], [1302009, 10], [1402007, 10], + [1302010, 20], [1402003, 20], [1312006, 7], [1412004, 7], + [1312007, 10], [1412005, 10], [1312018, 20], [1412003, 20], + [1322015, 7], [1422008, 7], [1322016, 10], [1422007, 10], + [1322017, 20], [1422005, 20], [1432003, 7], [1442003, 7], + [1432005, 10], [1442009, 10], [1442005, 20], [1432004, 20]]; + +var magician = [[1372001, 7], [1382018, 7], [1372012, 10], [1382019, 10], + [1382001, 20], [1372007, 20]]; + +var archer = [[1452006, 7], [1452007, 10], [1452008, 20], [1462005, 7], + [1462006, 10], [1462007, 20]]; + +var thief = [[1472013, 7], [1472017, 10], [1472021, 20], [1332014, 7], + [1332011, 10], [1332031, 10], [1332016, 20], [1332034, 20]]; + +var pirate = [[1482005, 7], [1482006, 10], [1482007, 20], [1492005, 7], + [1492006, 10], [1492007, 20]]; + +var necklace = [[1122007, 50], [2041211, 40]]; + +// Long Text Descriptions +var infoText = "You wish to know about the Monster Carnival? Very well. The Monster Carnival is a place of trilling battles and exciting competiton against people just as strong and motivated as yourself. You must summon monsters and defeat the monsters summoned by the opposing party. That's the essence of the Monster Carnival. Once you enter the Carnival Field, the task is to earn CP by hunter monsters from the opposing party and use those CP's to distract the opposing party from hunting monsters. There are three ways to distract the other party; Summon a Monster, Skill or Protector. Please remember this though, it's never a good idea to save up CP just for the sake of it. The CP's you've used will also help determine the winner and the loser of the carnival."; +var no = "You do not have enough Maple Coins for this item. Come back to me when you acquire more!"; + +function getGrade(cp) { + // Returns index of corresponding expRewards pair. + if (cp >= gradeS) { + return 0; + } else if (cp >= gradeA) { + return 1; + } else if (cp >= gradeB) { + return 2; + } else if (cp >= gradeC) { + return 3; + } else if (cp >= gradeD) { + return 4; + } else if (cp >= gradeE) { + return 5; + } else { + return 6; + } +} + +function isTownMap(map) { + for (var i = 0; i < infoMaps.length; i++) { + if (infoMaps[i] == map) { + return true; + } + } + return false; +} + +function isExitMap(map) { + return map == 980000010; +} + +function isWinnerMap(map) { + return (map >= 980000000 && map <= 980000700 && map % 10 == 3); +} + +function isLoserMap(map) { + return (map >= 980000000 && map <= 980000700 && map % 10 == 4); +} + +var CONTEXT_NONE = -1; +var CONTEXT_TOWN = 0; +var CONTEXT_EXIT = 1; +var CONTEXT_WIN = 2; +var CONTEXT_LOSE = 3; + +function start() { + if (DISABLED) { + cm.sendOk("CPQ is temporarily unavailable."); + cm.dispose(); + return; + } + m = cm.getMapId(); + if (isTownMap(m)) { + ctx = CONTEXT_TOWN; + } else if (isExitMap(m)) { + ctx = CONTEXT_EXIT; + } else if (isWinnerMap(m)) { + ctx = CONTEXT_WIN; + } else if (isLoserMap(m)) { + ctx = CONTEXT_LOSE; + } else { + ctx = CONTEXT_NONE; + } + + action(1, 0, 0); +} + +function doLoserMap(mode, type, selection) { + if (cm.getPlayer().getMCPQParty() == null) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + return; + } + + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 1) status++; + else status--; + + if (status == 0) { + cm.sendNext("Unfortunately, you did not manage to win this round. Better luck next time!"); + } else if (status == 1) { + var points = cm.getPlayer().getMCPQParty().getTotalCP(); + var grade = getGrade(points); + var letterGrade = "ABCDF"[grade]; + var expReward = expRewards[grade][1]; + + cm.sendNext("Your grade is: #b" + letterGrade + "\r\n\r\n#kEXP Reward: " + expReward); + cm.gainExp(expReward); + } else if (status == 2) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + } + } +} + +function doWinnerMap(mode, type, selection) { + if (cm.getPlayer().getMCPQParty() == null) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + return; + } + + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 1) status++; + else status--; + + if (status == 0) { + cm.sendNext("Congratulations! You managed to defeat the enemy team!"); + } else if (status == 1) { + var points = cm.getPlayer().getMCPQParty().getTotalCP(); + var grade = getGrade(points); + var letterGrade = "ABCDF"[grade]; + var expReward = expRewards[grade][0]; + + cm.sendNext("Your grade is: #b" + letterGrade + "\r\n\r\n#kEXP Reward: " + expReward); + cm.gainExp(expReward); + } else if (status == 2) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + } + } +} + +function doTown(mode, type, selection) { + if (mode == -1) { + cm.sendOk("Be sure to vote for the server every 24 hours!"); + cm.dispose(); + } else { + if (mode == 1) status++; + else status--; + + if (status == 0) { + cm.sendSimple("What would you like to do? If you have never participated in the Monster Carnival, you'll need to know a thing or two about it before joining.\r\n\r\n#b#L0#Go to the Monster Carnival Field#l\r\n#L1#Learn about the Monster Carnival#l\r\n#L2#Trade Maple Coin#l"); + } else if (status == 1) { + if (selection == 0) { + if (cm.getChar().getLevel() < MonsterCarnival.MIN_LEVEL || cm.getChar().getLevel() > MonsterCarnival.MAX_LEVEL) { + cm.sendOk("You must be between level " + MonsterCarnival.MIN_LEVEL + " and level " + MonsterCarnival.MAX_LEVEL + " to enter."); + cm.dispose(); + return; + } + cm.getChar().saveLocation(SavedLocationType.MONSTER_CARNIVAL); + cm.warp(MonsterCarnival.MAP_LOBBY, 4); + cm.dispose(); + return; + } else if (selection == 1) { + cm.sendPrev(infoText); + cm.dispose(); + return; + } else if (selection == 2) { + store = true; + cm.sendSimple("Select a category:\r\n" + + "#L101##bTrade Maple Coins for Warrior Weapons\r\n" + + "#L102#Trade Maple Coins for Magician Weapons\r\n" + + "#L103#Trade Maple Coins for Bowman Weapons\r\n" + + "#L104#Trade Maple Coins for Thief Weapons\r\n" + + "#L105#Trade Maple Coins for Pirate Weapons\r\n" + + "#L106#Trade Maple Coins for a Necklace"); + } + } else if (status == 2) { + if (store) { + switch (selection) { + case 101: + storeInfo = warrior; + break; + case 102: + storeInfo = magician; + break; + case 103: + storeInfo = archer; + break; + case 104: + storeInfo = thief; + break; + case 105: + storeInfo = pirate; + break; + case 106: + storeInfo = necklace; + break; + default: + storeInfo = []; + } + if (storeInfo.length == 0) { + cm.sendOk("That store doesn't exist."); + cm.dispose(); + return; + } + var storeText = ""; + for (var i = 0; i < storeInfo.length; ++i) { + var wepId = storeInfo[i][0]; + var cost = storeInfo[i][1]; + storeText += "#L" + i + "##v" + wepId + "# - #z" + wepId + "# - " + cost + " " + coinIcon + "#l\r\n"; + } + cm.sendSimple(storeText); + } else { + MCTracker.log("[MCPQ_Info] CONTEXT_TOWN: Invalid status 2"); + } + } else if (status == 3) { + if (store) { + purchaseId = storeInfo[selection][0]; + purchaseCost = storeInfo[selection][1]; + + if (cm.haveItem(coinId, purchaseCost)) { + cm.sendYesNo("Are you sure you want to purchase #i" + purchaseId + "#? You will have #r#e" + (cm.itemQuantity(coinId) - purchaseCost) + " " + coinIcon + "##k#n remaining."); + } else { + cm.sendOk("You don't have enough " + coinIcon + "."); + cm.dispose(); + } + } else { + MCTracker.log("[MCPQ_Info] CONTEXT_TOWN: Invalid status 3"); + } + } else if (status == 4) { + if (store) { + if (cm.haveItem(coinId, purchaseCost)) { + cm.gainItem(coinId, -purchaseCost); + cm.gainItem(purchaseId); + cm.sendOk("Congratulations! Enjoy your new item."); + cm.dispose(); + } + } else { + MCTracker.log("[MCPQ_Info] CONTEXT_TOWN: Invalid status 4"); + } + } + } +} + +function doExit() { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.sendOk("Hope you had fun in the Carnival PQ!"); + cm.dispose(); +} + +function action(mode, type, selection) { + switch (ctx) { + case CONTEXT_TOWN: + doTown(mode, type, selection); + break; + case CONTEXT_EXIT: + doExit(); + break; + case CONTEXT_LOSE: + doLoserMap(mode, type, selection); + break; + case CONTEXT_WIN: + doWinnerMap(mode, type, selection); + break; + default: + MCTracker.log("[MCPQ_INFO] Invalid context (value: " + ctx + ")"); + cm.dispose(); + } +} \ No newline at end of file diff --git a/docs/mcpq/scripts/npc/2042003.js b/docs/mcpq/scripts/npc/2042003.js new file mode 100644 index 0000000000..3b55415e3b --- /dev/null +++ b/docs/mcpq/scripts/npc/2042003.js @@ -0,0 +1,88 @@ +/** * [MENTION=19862]id[/MENTION] 2042003 + * [MENTION=806871]NPC[/MENTION] Assistant Red + * [MENTION=836108]Function[/MENTION] Monster Carnival Waiting Room NPC + * @author s4nta + */ + +// Relevant Monster Carnival classes +var MonsterCarnival = net.sf.odinms.server.partyquest.mcpq.MonsterCarnival; +var MCTracker = net.sf.odinms.server.partyquest.mcpq.MCTracker; +var MCParty = net.sf.odinms.server.partyquest.mcpq.MCParty; +var MCField = net.sf.odinms.server.partyquest.mcpq.MCField; +var MCTeam = net.sf.odinms.server.partyquest.mcpq.MCField.MCTeam; + +// NPC variables +var status = -1; +var carnival, field; +var room = -1; + +function start() { + if (!MonsterCarnival.isLobbyMap(cm.getMapId())) { + MCTracker.log("Assistant called on invalid map " + cm.getMapId() + " by player " + cm.getName()); + cm.sendOk("You are not authorized to do this."); + cm.dispose(); + return; + } + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + return; + } + if (mode == 1) status++; + else status--; + + if (status == 0) { + if (cm.getParty() == null) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + return; + } + options = ["#L1#Leave the room #r#e(WARNING: Abusing this will block you from future Carnival PQs)#b#n.#l", + "#L2#Close NPC#l"]; + if (cm.isLeader()) { + options.unshift("#L0#View pending challenges#l"); + } + + text = "Welcome to Carnival PQ. I am #rAssistant Red#k. What can I do for you?#b\r\n"; + for (var i = 0; i < options.length; i++) { + text += options[i]; + text += "\r\n"; + } + cm.sendSimple(text); + } else if (status == 1) { + field = cm.getChar().getMCPQField(); + if (selection == 0) { + if (!cm.isLeader()) { + cm.sendOk("You are not authorized to do this."); + cm.dispose(); + return; + } + if (!field.hasPendingRequests()) { + cm.sendOk("There are no pending requests at this time."); + cm.dispose(); + return; + } + cm.sendSimple(field.getNPCRequestString()); + } else if (selection == 1) { + if (field != null) { + field.deregister(true); + } else { + cm.warp(MonsterCarnival.MAP_EXIT); + } + cm.dispose(); + } else { + cm.dispose(); + } + } else if (status == 2) { + var code = field.acceptRequest(selection); + if (code == 1) { + cm.sendOk("The challenge was accepted."); + } else { + cm.sendOk("An unknown error occurred."); + } + cm.dispose(); + } +} \ No newline at end of file diff --git a/docs/mcpq/scripts/npc/2042004.js b/docs/mcpq/scripts/npc/2042004.js new file mode 100644 index 0000000000..33d074269e --- /dev/null +++ b/docs/mcpq/scripts/npc/2042004.js @@ -0,0 +1,88 @@ +/** * [MENTION=19862]id[/MENTION] 2042004 + * [MENTION=806871]NPC[/MENTION] Assistant Blue + * [MENTION=836108]Function[/MENTION] Monster Carnival Waiting Room NPC + * @author s4nta + */ + +// Relevant Monster Carnival classes +var MonsterCarnival = net.sf.odinms.server.partyquest.mcpq.MonsterCarnival; +var MCTracker = net.sf.odinms.server.partyquest.mcpq.MCTracker; +var MCParty = net.sf.odinms.server.partyquest.mcpq.MCParty; +var MCField = net.sf.odinms.server.partyquest.mcpq.MCField; +var MCTeam = net.sf.odinms.server.partyquest.mcpq.MCField.MCTeam; + +// NPC variables +var status = -1; +var carnival, field; +var room = -1; + +function start() { + if (!MonsterCarnival.isLobbyMap(cm.getMapId())) { + MCTracker.log("Assistant called on invalid map " + cm.getMapId() + " by player " + cm.getName()); + cm.sendOk("You are not authorized to do this."); + cm.dispose(); + return; + } + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + return; + } + if (mode == 1) status++; + else status--; + + if (status == 0) { + if (cm.getParty() == null) { + cm.warp(MonsterCarnival.MAP_LOBBY); + cm.dispose(); + return; + } + options = ["#L1#Leave the room #r#e(WARNING: Abusing this will block you from future Carnival PQs)#b#n.#l", + "#L2#Close NPC#l"]; + if (cm.isLeader()) { + options.unshift("#L0#View pending challenges#l"); + } + + text = "Welcome to Carnival PQ. I am #bAssistant Blue#k. What can I do for you?#b\r\n"; + for (var i = 0; i < options.length; i++) { + text += options[i]; + text += "\r\n"; + } + cm.sendSimple(text); + } else if (status == 1) { + field = cm.getChar().getMCPQField(); + if (selection == 0) { + if (!cm.isLeader()) { + cm.sendOk("You are not authorized to do this."); + cm.dispose(); + return; + } + if (!field.hasPendingRequests()) { + cm.sendOk("There are no pending requests at this time."); + cm.dispose(); + return; + } + cm.sendSimple(field.getNPCRequestString()); + } else if (selection == 1) { + if (field != null) { + field.deregister(true); + } else { + cm.warp(MonsterCarnival.MAP_EXIT); + } + cm.dispose(); + } else { + cm.dispose(); + } + } else if (status == 2) { + var code = field.acceptRequest(selection); + if (code == 1) { + cm.sendOk("The challenge was accepted."); + } else { + cm.sendOk("An unknown error occurred."); + } + cm.dispose(); + } +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive1.js b/docs/mcpq/scripts/portal/MCrevive1.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive1.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive2.js b/docs/mcpq/scripts/portal/MCrevive2.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive2.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive3.js b/docs/mcpq/scripts/portal/MCrevive3.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive3.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive4.js b/docs/mcpq/scripts/portal/MCrevive4.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive4.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive5.js b/docs/mcpq/scripts/portal/MCrevive5.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive5.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/MCrevive6.js b/docs/mcpq/scripts/portal/MCrevive6.js new file mode 100644 index 0000000000..bb940cab4c --- /dev/null +++ b/docs/mcpq/scripts/portal/MCrevive6.js @@ -0,0 +1,8 @@ +function enter(pi) { player = pi.getPlayer(); + if (player.getMCPQField() != null) { + player.getMCPQField().onRevive(player); + } else { + pi.warp(980000000); + } + return true; +} \ No newline at end of file diff --git a/docs/mcpq/scripts/portal/mc_out.js b/docs/mcpq/scripts/portal/mc_out.js new file mode 100644 index 0000000000..728e8ed2f0 --- /dev/null +++ b/docs/mcpq/scripts/portal/mc_out.js @@ -0,0 +1,51 @@ +/* + 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 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 . +*/ + +importPackage(Packages.net.sf.odinms.server.maps); + +/* +Return from MCPQ map. +*/ + +function enter(pi) { + var returnMap = pi.getPlayer().getSavedLocation(SavedLocationType.MONSTER_CARNIVAL); + if (returnMap < 0) { + returnMap = 100000000; // to fix people who entered the fm trough an unconventional way + } + var target = pi.getPlayer().getClient().getChannelServer().getMapFactory().getMap(returnMap); + var targetPortal; + + if (returnMap == 230000000) { + targetPortal = target.getPortal("market01"); + } else { + targetPortal = target.getPortal("market00"); + } + + if (targetPortal == null) + targetPortal = target.getPortal(0); + + if (pi.getPlayer().getMapId() != target) { + pi.getPlayer().clearSavedLocation(SavedLocationType.MONSTER_CARNIVAL); + pi.getPlayer().changeMap(target, targetPortal); + return true; + } + return false; +} \ No newline at end of file diff --git a/docs/mcpq/src/ChangeMapHandler.txt b/docs/mcpq/src/ChangeMapHandler.txt new file mode 100644 index 0000000000..ad631236d3 --- /dev/null +++ b/docs/mcpq/src/ChangeMapHandler.txt @@ -0,0 +1,5 @@ +Under the respawn map change code (!c.getPlayer().isAlive()), add before executeStandardPath is done: +PHP Code: +if (player.getMCPQField() != null) { player.getMCPQField().onPlayerRespawn(player); + return; +} \ No newline at end of file diff --git a/docs/mcpq/src/ItemPickupHandler.txt b/docs/mcpq/src/ItemPickupHandler.txt new file mode 100644 index 0000000000..949abab24e --- /dev/null +++ b/docs/mcpq/src/ItemPickupHandler.txt @@ -0,0 +1,22 @@ +Add before items are added to inventory, or after mesos are handled: +PHP Code: + +else if (c.getPlayer().getMCPQField() != null) { // CPQ Handling boolean consumed = c.getPlayer().getMCPQField().onItemPickup(c.getPlayer(), mapitem); + if (consumed) { + c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 2, c.getPlayer().getId()), + mapitem.getPosition()); + c.getPlayer().getCheatTracker().pickupComplete(); + c.getPlayer().getMap().removeMapObject(ob); + } else { + if (MapleInventoryManipulator.addFromDrop(c, mapitem.getItem(), true)) { + c.getPlayer().getMap().broadcastMessage( + MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 2, c.getPlayer().getId()), + mapitem.getPosition()); + c.getPlayer().getCheatTracker().pickupComplete(); + c.getPlayer().getMap().removeMapObject(ob); + } else { + c.getPlayer().getCheatTracker().pickupComplete(); + return; + } + } +} \ No newline at end of file diff --git a/docs/mcpq/src/MapleCharacter.txt b/docs/mcpq/src/MapleCharacter.txt new file mode 100644 index 0000000000..87f8ca1b0b --- /dev/null +++ b/docs/mcpq/src/MapleCharacter.txt @@ -0,0 +1,73 @@ +client/MapleCharacter.java +Add fields: +PHP Code: +private MCField.MCTeam MCPQTeam;private MCParty MCPQParty; +private MCField MCPQField; +private int availableCP = 0; +private int totalCP = 0; +under playerDead() method: +PHP Code: +if (player.getMap().isTown()) { XPdummy *= 0.01; +} else if (MonsterCarnival.isBattlefieldMap(player.getMapId())) { + XPdummy = 0; +} +under the giveDebuff() method, add a field that force adds the disease if some variable cpq is set, regardless of buffs. +method signature: +PHP Code: +public void giveDebuff(MapleDisease disease, MobSkill skill, boolean cpq) +Add these methods: +PHP Code: +public int getTeam() { if (this.MCPQTeam == null) { + return -1; + } + return this.MCPQTeam.code; +} + +public MCField.MCTeam getMCPQTeam() { + return MCPQTeam; +} + +public void setMCPQTeam(MCField.MCTeam MCPQTeam) { + this.MCPQTeam = MCPQTeam; +} + +public MCParty getMCPQParty() { + return MCPQParty; +} + +public void setMCPQParty(MCParty MCPQParty) { + this.MCPQParty = MCPQParty; +} + +public MCField getMCPQField() { + return MCPQField; +} + +public void setMCPQField(MCField MCPQField) { + this.MCPQField = MCPQField; +} + +public int getAvailableCP() { + return availableCP; +} + +public void setAvailableCP(int availableCP) { + this.availableCP = availableCP; +} + +public int getTotalCP() { + return totalCP; +} + +public void setTotalCP(int totalCP) { + this.totalCP = totalCP; +} + +public void gainCP(int cp) { + this.availableCP += cp; + this.totalCP += cp; +} + +public void loseCP(int cp) { + this.availableCP -= cp; +} diff --git a/docs/mcpq/src/MapleClient.txt b/docs/mcpq/src/MapleClient.txt new file mode 100644 index 0000000000..12d5d27364 --- /dev/null +++ b/docs/mcpq/src/MapleClient.txt @@ -0,0 +1,5 @@ +Add this under disconnect() (right after event instance calls onPlayerDisconnect, preferably): +PHP Code: +if (chr.getMCPQField() != null) { + chr.getMCPQField().onPlayerDisconnected(player); +} \ No newline at end of file diff --git a/docs/mcpq/src/MapleLifeFactory.txt b/docs/mcpq/src/MapleLifeFactory.txt new file mode 100644 index 0000000000..bd11eaec18 --- /dev/null +++ b/docs/mcpq/src/MapleLifeFactory.txt @@ -0,0 +1,3 @@ +Add to getMonster(int monsterId): +PHP Code: +stats.setCp(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0)); \ No newline at end of file diff --git a/docs/mcpq/src/MapleMap.txt b/docs/mcpq/src/MapleMap.txt new file mode 100644 index 0000000000..bb1fdf1adc --- /dev/null +++ b/docs/mcpq/src/MapleMap.txt @@ -0,0 +1,80 @@ +Add fields: +PHP Code: +private boolean respawning = true; +private MCWZData mcpqData; +Add methods: +PHP Code: +public final List getAllMonsters() { return getAllMapObjects(MapleMapObjectType.MONSTER); +} + +public void addMonsterSpawn(MapleMonster monster, int mobTime, int team) { + Point newpos = calcPointBelow(monster.getPosition()); + newpos.y -= 1; + SpawnPoint sp = new SpawnPoint(monster, newpos, mobTime, team); + monsterSpawn.add(sp); + if (!respawning) return; + + if (sp.shouldSpawn() || mobTime == -1) { + sp.spawnMonster(this); + } +} + +public void setReactorState(MapleReactor reactor, byte state) { + synchronized (this.mapobjects) { + reactor.setState(state); + broadcastMessage(MaplePacketCreator.triggerReactor(reactor, state)); + } +} + +public List getAllMapObjects(MapleMapObjectType type) { + List ret = new ArrayList<>(); + synchronized (mapobjects) { + for (MapleMapObject l : mapobjects.values()) { + if (l.getType() == type) { + ret.add((E) l); + } + } + } + return ret; +} + +public void clearDrops() { + List items = getAllMapObjects(MapleMapObjectType.ITEM); + for (MapleMapItem itemmo : items) { + removeMapObject(itemmo); + broadcastMessage(MaplePacketCreator.removeItemFromMap(itemmo.getObjectId(), 0, 0)); + } +} + +public Collection getSpawnPoints() { + return monsterSpawn; +} + +public void respawn() { + for (SpawnPoint sp : this.monsterSpawn) { + if (sp.shouldSpawn()) { + sp.spawnMonster(this); + } + } +} + +public void beginSpawning() { + this.respawning = true; + this.respawn(); +} + +public boolean isRespawning() { + return respawning; +} + +public void setRespawning(boolean respawning) { + this.respawning = respawning; +} + +public MCWZData getMCPQData() { + return this.mcpqData; +} + +public void setMCPQData(MCWZData data) { + this.mcpqData = data; +} diff --git a/docs/mcpq/src/MapleMapFactory.txt b/docs/mcpq/src/MapleMapFactory.txt new file mode 100644 index 0000000000..9686986231 --- /dev/null +++ b/docs/mcpq/src/MapleMapFactory.txt @@ -0,0 +1,22 @@ +Add to getMap() method, under where it parses PQ areas: +PHP Code: +MapleData mcData = mapData.getChildByPath("monsterCarnival");if (mcData != null) { + MCWZData mcpqInfo = new MCWZData(mcData); + map.setMCPQData(mcpqInfo); + map.setRespawning(false); +} +Add to getMap() method, under where it parses mobTime: +PHP Code: +int team = MapleDataTool.getInt("team", life, -1); +Change addMonsterSpawn() method call to the following, using the new SpawnPoint construction we defined in MapleMap: +PHP Code: +map.addMonsterSpawn(monster, mobTime, team); +Add the method: +PHP Code: +public MapleMap instanceMap(int mapid, boolean respawns, boolean npcs) { return instanceMap(mapid, respawns, npcs, true); +} +and + +PHP Code: +public MapleMap instanceMap(int mapid, boolean respawns, boolean npcs, boolean reactors) +, where the code is the same as getMap but does not try to load from cache and does not store into cache. diff --git a/docs/mcpq/src/MapleMonster.txt b/docs/mcpq/src/MapleMonster.txt new file mode 100644 index 0000000000..5adb975020 --- /dev/null +++ b/docs/mcpq/src/MapleMonster.txt @@ -0,0 +1,31 @@ +Add fields: +PHP Code: +private int team = -1; + +Add methods: +PHP Code: +public int getCP() { return stats.getCp(); +} + +public int getTeam() { + return team; +} + +public void setTeam(int team) { + this.team = team; +} + +public void dispel() { + if (!isAlive()) return; + + for (MonsterStatus i : MonsterStatus.values()) { + if (monsterBuffs.contains(i)) { + removeMonsterBuff(i); + MaplePacket packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), Collections.singletonMap(i, Integer.valueOf(1))); + map.broadcastMessage(packet, getPosition()); + if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) { + getController().getClient().getSession().write(packet); + } + } + } +} diff --git a/docs/mcpq/src/MapleMonsterStats.txt b/docs/mcpq/src/MapleMonsterStats.txt new file mode 100644 index 0000000000..196b71b9ea --- /dev/null +++ b/docs/mcpq/src/MapleMonsterStats.txt @@ -0,0 +1,13 @@ +Add field: +PHP Code: +private int cp; + +Add methods: +PHP Code: +public int getCp() { + return cp; +} + +public void setCp(int cp) { + this.cp = cp; +} \ No newline at end of file diff --git a/docs/mcpq/src/MapleReactor.txt b/docs/mcpq/src/MapleReactor.txt new file mode 100644 index 0000000000..2ea3c55073 --- /dev/null +++ b/docs/mcpq/src/MapleReactor.txt @@ -0,0 +1,6 @@ +Under hitReactor(), add before standard handling: +PHP Code: +if (c.getPlayer().getMCPQField() != null) { + c.getPlayer().getMCPQField().onGuardianHit(c.getPlayer(), this); + return; +} \ No newline at end of file diff --git a/docs/mcpq/src/MapleStatEffect.txt b/docs/mcpq/src/MapleStatEffect.txt new file mode 100644 index 0000000000..041bf661c4 --- /dev/null +++ b/docs/mcpq/src/MapleStatEffect.txt @@ -0,0 +1,27 @@ +Add fields: +PHP Code: +private boolean consumeOnPickup, party; +private int cp, nuffSkill; + +Add to stat parsing (loadFromData()): +PHP Code: + +ret.cp = MapleDataTool.getInt("cp", source, 0);ret.party = MapleDataTool.getInt("party", source, 0) > 0; +ret.consumeOnPickup = MapleDataTool.getInt("consumeOnPickup", source, 0) > 0; +ret.nuffSkill = MapleDataTool.getInt("nuffSkill", source, -1); +Add methods: +PHP Code: +public int getCP() { return cp; +} + +public boolean isParty() { + return party; +} + +public boolean isConsumeOnPickup() { + return consumeOnPickup; +} + +public int getNuffSkill() { + return nuffSkill; +} \ No newline at end of file diff --git a/docs/mcpq/src/MobSkill.txt b/docs/mcpq/src/MobSkill.txt new file mode 100644 index 0000000000..c36ef0b9b0 --- /dev/null +++ b/docs/mcpq/src/MobSkill.txt @@ -0,0 +1,23 @@ +Add to applyEffect(): + +PHP Code: +case 150: monStat = MonsterStatus.WEAPON_ATTACK_UP; + break; +case 151: + monStat = MonsterStatus.WEAPON_DEFENSE_UP; + break; +case 152: + monStat = MonsterStatus.MAGIC_ATTACK_UP; + break; +case 153: + monStat = MonsterStatus.MAGIC_DEFENSE_UP; + break; +case 154: + monStat = MonsterStatus.ACC; + break; +case 155: + monStat = MonsterStatus.AVOID; + break; +case 156: + monStat = MonsterStatus.SPEED; + break; diff --git a/docs/mcpq/src/MonterCarnivalHandler.txt b/docs/mcpq/src/MonterCarnivalHandler.txt new file mode 100644 index 0000000000..c34ec7fc8d --- /dev/null +++ b/docs/mcpq/src/MonterCarnivalHandler.txt @@ -0,0 +1,41 @@ +package net.sf.odinms.net.channel.handler; +import net.sf.odinms.client.MapleCharacter; +import net.sf.odinms.client.MapleClient; +import net.sf.odinms.net.AbstractMaplePacketHandler; +import net.sf.odinms.server.partyquest.mcpq.MCField; +import net.sf.odinms.server.partyquest.mcpq.MCTracker; +import net.sf.odinms.server.partyquest.mcpq.MonsterCarnival; +import net.sf.odinms.tools.data.input.SeekableLittleEndianAccessor; + +/** + * Packet handler for Monster Carnival. + * @author s4nta + */ +public class MonsterCarnivalHandler extends AbstractMaplePacketHandler { + + @Override + public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { + int tab = slea.readByte(); + int num = slea.readByte(); + MapleCharacter chr = c.getPlayer(); + + if (MonsterCarnival.DEBUG) { + MCTracker.log("[MCHandler] " + chr.getName() + " used tab " + tab + " num " + num); + System.out.println("[MCHandler] " + chr.getName() + " used tab " + tab + " num " + num); + } + + if (chr.getMCPQField() == null || chr.getMCPQParty() == null) { + MCTracker.log("[MCHandler] " + chr.getName() + " attempting to use Monster Carnival handler without being in Monster Carnival"); + return; + } + + MCField field = chr.getMCPQField(); + if (tab == 0) { + field.onAddSpawn(c.getPlayer(), num); + } else if (tab == 1) { + field.onUseSkill(c.getPlayer(), num); + } else if (tab == 2) { // status + field.onGuardianSummon(c.getPlayer(), num); + } + } +} \ No newline at end of file diff --git a/docs/mcpq/src/PetLootHandler.txt b/docs/mcpq/src/PetLootHandler.txt new file mode 100644 index 0000000000..2c1f32caa2 --- /dev/null +++ b/docs/mcpq/src/PetLootHandler.txt @@ -0,0 +1,20 @@ +else if (c.getPlayer().getMCPQField() != null) { // CPQ Handling + boolean consumed = c.getPlayer().getMCPQField().onItemPickup(c.getPlayer(), mapitem); + if (consumed) { + c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 2, c.getPlayer().getId()), + mapitem.getPosition()); + c.getPlayer().getCheatTracker().pickupComplete(); + c.getPlayer().getMap().removeMapObject(ob); + } else { + if (MapleInventoryManipulator.addFromDrop(c, mapitem.getItem(), true)) { + c.getPlayer().getMap().broadcastMessage( + MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 2, c.getPlayer().getId()), + mapitem.getPosition()); + c.getPlayer().getCheatTracker().pickupComplete(); + c.getPlayer().getMap().removeMapObject(ob); + } else { + c.getPlayer().getCheatTracker().pickupComplete(); + return; + } + } + } \ No newline at end of file diff --git a/docs/mcpq/src/SpawnPoint.txt b/docs/mcpq/src/SpawnPoint.txt new file mode 100644 index 0000000000..107be7067d --- /dev/null +++ b/docs/mcpq/src/SpawnPoint.txt @@ -0,0 +1,35 @@ +Add field: +PHP Code: +private int team = -1; +Add constructor: +PHP Code: +public SpawnPoint(MapleMonster monster, Point pos, int mobTime, int team) { super(); + this.monster = monster; + this.pos = new Point(pos); + this.mobTime = mobTime; + this.immobile = !monster.isMobile(); + this.nextPossibleSpawn = System.currentTimeMillis(); + this.team = team; +} +Add monster death listener under spawnMonster(): +PHP Code: +if (team > -1) { final int cp = mob.getCP(); + mob.addListener(new MonsterListener() { + + @Override + public void monsterKilled(MapleMonster monster, MapleCharacter highestDamageChar) { + if (highestDamageChar == null) { + return; + } + + if (highestDamageChar.getMCPQParty() == null) { + MCTracker.log("Attempted to give CP to character without assigned MCPQ Party."); + return; + } + + highestDamageChar.getMCPQField().monsterKilled(highestDamageChar, cp); + + } + }); + mob.setTeam(team); +} \ No newline at end of file diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 2b4d1e3111..af2f4aa868 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -118,7 +118,7 @@ Inclus 01 - 02 Abril 2017, Correção de bug que impedia carregamento do mapa Singapore: Spooky World. -Adição dos cards de mob restantes no drop_data do BD. +Adição dos cards de mob restantes no drop_data do DB. 03 Abril 2017, Inclusão de scripts para interceptar condições de corrida em eventos de viagem. @@ -623,4 +623,12 @@ Corrigido storage n Corrigido sistema de buffs não computando buffs com valor zero não sendo apropriadamente ativados no jogador. 29 Outubro 2017, -Adicionado drop data para diversas versões de Fairy, Yetis e Pepes. \ No newline at end of file +Adicionado drop data para diversas versões de Fairy, Yetis e Pepes. +Adicionado proteção contra acesso concorrente em MapleGuild e MapleAlliance. + +30 Outubro 2017, +Adicionado drop data de mesos para o restante dos mobs que dropam 4 ou mais itens. + +31 Outubro 2017, +Corrigido bug ao mudar classe de Aran desconectando o jogador. +Corrigido drop data de flechas agora dropando bundles ao invés de uma quantidade unitária. \ No newline at end of file diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index e01a05efb0..3287222d26 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -2,8 +2,6 @@ - - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/quest/21001.js - + diff --git a/scripts/npc/1200003.js b/scripts/npc/1200003.js index 61cacaf292..e7ba9a1040 100644 --- a/scripts/npc/1200003.js +++ b/scripts/npc/1200003.js @@ -33,20 +33,20 @@ function action(mode, type, selection) { status++; if (status == 0) { for(var i=0; i < menu.length; i++) { - var display = "\r\n#L"+i+"##b Lith Harbor (800 mesos)#k"; - } - cm.sendSimple("Are you trying to leave Rien? Board this ship and I'll take you from #bRien#k to #bLith Harbor#k and back. for a #bfee of 800#k Mesos. Would you like to head over to Lith Harbor now? It'll take about a minute to get there.\r\n"+display); + var display = "\r\n#L"+i+"##b Lith Harbor (800 mesos)#k"; + } + cm.sendSimple("Are you trying to leave Rien? Board this ship and I'll take you from #bRien#k to #bLith Harbor#k and back. for a #bfee of 800#k Mesos. Would you like to head over to Lith Harbor now? It'll take about a minute to get there.\r\n"+display); - } else if(status == 1) { - { if(cm.getMeso() < 800) { - cm.sendNext("Hmm... Are you sure you have #b800#k Mesos? Check your Inventory and make sure you have enough. You must pay the fee or I can't let you get on..."); - cm.dispose(); - } else { - cm.gainMeso(-800); - cm.warp(200090070); - cm.dispose(); - } - } - } - } - } \ No newline at end of file + } else if(status == 1) { + if(cm.getMeso() < 800) { + cm.sendNext("Hmm... Are you sure you have #b800#k Mesos? Check your Inventory and make sure you have enough. You must pay the fee or I can't let you get on..."); + cm.dispose(); + } else { + cm.gainMeso(-800); + cm.warp(200090070); + cm.dispose(); + } + + } + } +} \ No newline at end of file diff --git a/scripts/npc/1200004.js b/scripts/npc/1200004.js index 663933462e..12d99695b7 100644 --- a/scripts/npc/1200004.js +++ b/scripts/npc/1200004.js @@ -33,20 +33,19 @@ function action(mode, type, selection) { status++; if (status == 0) { for(var i=0; i < menu.length; i++) { - var display = "\r\n#L"+i+"##b Rien (800 mesos)#k"; - } - cm.sendSimple("Are you thinking about leaving Victoria Island and heading to our town? If you board this ship, I can take you from #bLith Harbor#k to #bRien#k and back. But you must pay a #bfee of 800#k Mesos. Would you like to go to Rien? It'll take about a minute to get there.\r\n"+display); + var display = "\r\n#L"+i+"##b Rien (800 mesos)#k"; + } + cm.sendSimple("Are you thinking about leaving Victoria Island and heading to our town? If you board this ship, I can take you from #bLith Harbor#k to #bRien#k and back. But you must pay a #bfee of 800#k Mesos. Would you like to go to Rien? It'll take about a minute to get there.\r\n"+display); - } else if(status == 1) { - { if(cm.getMeso() < 800) { - cm.sendNext("Hmm... Are you sure you have #b800#k Mesos? Check your Inventory and make sure you have enough. You must pay the fee or I can't let you get on..."); - cm.dispose(); - } else { - cm.gainMeso(-800); - cm.warp(200090060); - cm.dispose(); - } - } - } - } - } \ No newline at end of file + } else if(status == 1) { + if(cm.getMeso() < 800) { + cm.sendNext("Hmm... Are you sure you have #b800#k Mesos? Check your Inventory and make sure you have enough. You must pay the fee or I can't let you get on..."); + cm.dispose(); + } else { + cm.gainMeso(-800); + cm.warp(200090060); + cm.dispose(); + } + } + } +} \ No newline at end of file diff --git a/scripts/portal/enterInfo.js b/scripts/portal/enterInfo.js index 8b26f3ef55..4bd6a91d19 100644 --- a/scripts/portal/enterInfo.js +++ b/scripts/portal/enterInfo.js @@ -1,4 +1,5 @@ function enter(pi) { pi.playPortalSound(); pi.warp(104000004, 1); + return true; } \ No newline at end of file diff --git a/scripts/quest/21101.js b/scripts/quest/21101.js index c535686ce3..c1f5e1d1a1 100644 --- a/scripts/quest/21101.js +++ b/scripts/quest/21101.js @@ -38,22 +38,19 @@ function start(mode, type, selection) { } else if (status == 1) { if (qm.getPlayer().getJob().getId() == 2000) { if(!qm.canHold(1142129)) { - cm.sendOk("Wow, your #bequip#k inventory is full. I need you to make at least 1 empty slot to complete this quest."); + cm.sendOk("Wow, your #bequip#k inventory is full. You need to make at least 1 empty slot to complete this quest."); qm.dispose(); return; } qm.gainItem(1142129, true); - qm.completeQuest(); + qm.changeJobById(2100); - qm.getPlayer().setStr(35); - qm.getPlayer().setDex(4); - qm.getPlayer().setRemainingAp((qm.getPlayer().getLevel() - 1) * 5 - 22); - qm.getPlayer().setRemainingSp((qm.getPlayer().getLevel() - 10) * 3 + 1); - qm.getPlayer().setMaxHp(qm.getPlayer().getMaxHp() + 275); - qm.getPlayer().setMaxMp(qm.getPlayer().getMaxMp() + 15); + qm.resetStats(); //qm.teachSkill(21000000, 0, 10, -1); //learned later... //qm.teachSkill(21001003, 0, 20, -1); //learned later... + + qm.completeQuest(); //qm.getPlayer().changeSkillLevel(SkillFactory.getSkill(20009000), 0, -1); //qm.getPlayer().changeSkillLevel(SkillFactory.getSkill(20009000), 1, 0); diff --git a/scripts/quest/21201.js b/scripts/quest/21201.js index 134aa6b5be..c43ed93259 100644 --- a/scripts/quest/21201.js +++ b/scripts/quest/21201.js @@ -56,12 +56,13 @@ function end(mode, type, selection) { } qm.gainItem(1142130, true); - qm.getPlayer().setMaxMp(qm.getPlayer().getMaxMp() + 275); + qm.changeJobById(2110); qm.teachSkill(21100000, 0, 20, -1); qm.teachSkill(21100002, 0, 30, -1); qm.teachSkill(21100004, 0, 20, -1); qm.teachSkill(21100005, 0, 20, -1); + qm.completeQuest(); } qm.sendNext("Your level isn't what it used to be back in your glory days, so I can't restore all of your old abilities. But the few I can restore should help you level up faster. Now hurry up and train so you can return to the old you."); diff --git a/scripts/quest/21302.js b/scripts/quest/21302.js index 7871a5cf1d..db20a8e9a7 100644 --- a/scripts/quest/21302.js +++ b/scripts/quest/21302.js @@ -44,10 +44,10 @@ function end(mode, type, selection) { } qm.gainItem(1142131, true); - qm.getPlayer().setMaxMp(qm.getPlayer().getMaxMp() + 275); - qm.getPlayer().setMaxHp(qm.getPlayer().getMaxHp() + 275); + qm.changeJobById(2111); qm.teachSkill(21110002, 0, 20, -1); + qm.completeQuest(); } qm.sendNext("Come on, keep training so you can get all your abilities back, and that way we can explore together once more!"); diff --git a/scripts/quest/21766.js b/scripts/quest/21766.js new file mode 100644 index 0000000000..f26db43190 --- /dev/null +++ b/scripts/quest/21766.js @@ -0,0 +1,22 @@ +var status = -1; + +function start(mode, type, selection) { + status++; + if (status == 0) { + qm.sendNext("Hey! Can you do me a favor? #p20000# seems a bit strange these days..."); + } else if (status == 1) { + qm.sendNext("He used to scowl and whine about his arthritis until just recently, but he''s suddenly become all happy and smiley!!"); + } else if (status == 2) { + qm.sendNext("I have a feeling there is a secret behind that wooden box. Could you stealthily look into the wooden box next to #p20000#?"); + } else { + qm.sendNext("You know where #p20000# is, right? He''s to the right. Just keep going until you see where Vikin is, then head down past the hanging shark and octopus, and you''ll see John. The box should be right next to him."); + qm.forceStartQuest(); + qm.dispose(); + } +} + +function end(mode, type, selection) { + qm.gainExp(200 * qm.getPlayer().getExpRate()); + qm.forceCompleteQuest(); + qm.dispose(); +} \ No newline at end of file diff --git a/scripts/quest/21767.js b/scripts/quest/21767.js new file mode 100644 index 0000000000..390278e171 --- /dev/null +++ b/scripts/quest/21767.js @@ -0,0 +1,16 @@ +var status = -1; + +function start(mode, type, selection) { + status++; + if (status == 0) { + qm.sendNext("#bHm, there's a medicinal substance in the box. What could this be? You better take this to John and ask him what it is.#k"); + } else { + qm.gainItem(4032423,1); + qm.forceCompleteQuest(); + qm.dispose(); + } +} + +function end(mode, type, selection) { + qm.dispose(); +} \ No newline at end of file diff --git a/sql/db_drops.sql b/sql/db_drops.sql index 2fa31ed7fe..7ac09ad9af 100644 --- a/sql/db_drops.sql +++ b/sql/db_drops.sql @@ -19557,16 +19557,16 @@ USE `maplesolaxia`; (9300027, 4001035, 1, 1, 0, 999999), (9300033, 4001035, 1, 1, 0, 999999), (9400585, 4032004, 1, 1, 0, 200000), -(9400585, 0, 310, 500, 0, 200000), +(9400585, 0, 310, 500, 0, 400000), (9400586, 4032004, 1, 1, 0, 200000), -(9400586, 0, 310, 500, 0, 200000), +(9400586, 0, 310, 500, 0, 400000), (9400587, 4000018, 1, 1, 0, 200000), (9400587, 4032003, 1, 1, 0, 150000), -(9400587, 0, 210, 380, 0, 200000), +(9400587, 0, 210, 380, 0, 400000), (9400588, 4000018, 1, 1, 0, 200000), (9400588, 4032003, 1, 1, 0, 150000), -(9400588, 0, 210, 380, 0, 200000), -(9400583, 0, 562, 1096, 0, 200000), +(9400588, 0, 210, 380, 0, 400000), +(9400583, 0, 562, 1096, 0, 400000), (9400583, 4032031, 1, 1, 0, 80000), (9400583, 4030012, 1, 1, 0, 300), (9400583, 4010006, 1, 1, 0, 40000), @@ -20594,54 +20594,6 @@ USE `maplesolaxia`; (9300341, 4020005, 1, 1, 0, 9000), (9300341, 4030000, 1, 1, 0, 10000), (9300341, 4031273, 1, 1, 2104, 500000), -(9300342, 4000012, 1, 1, 0, 600000), -(9300342, 2000000, 1, 1, 0, 20000), -(9300342, 2043102, 1, 1, 0, 300), -(9300342, 2000003, 1, 1, 0, 20000), -(9300342, 4020003, 1, 1, 0, 9000), -(9300342, 1322000, 1, 1, 0, 700), -(9300342, 2060000, 1, 1, 0, 30000), -(9300342, 1041044, 1, 1, 0, 800), -(9300342, 1061037, 1, 1, 0, 800), -(9300342, 4010004, 1, 1, 0, 9000), -(9300342, 1092008, 1, 1, 0, 700), -(9300342, 1041017, 1, 1, 0, 800), -(9300342, 1061012, 1, 1, 0, 800), -(9300342, 1462002, 1, 1, 0, 500), -(9300342, 2061000, 1, 1, 0, 30000), -(9300342, 1041063, 1, 1, 0, 800), -(9300342, 1061059, 1, 1, 0, 800), -(9300342, 1452003, 1, 1, 0, 500), -(9300342, 2048000, 1, 1, 0, 300), -(9300342, 1002033, 1, 1, 0, 1500), -(9300342, 1302007, 1, 1, 0, 700), -(9300342, 4020002, 1, 1, 0, 9000), -(9300342, 1032001, 1, 1, 0, 1000), -(9300342, 1002010, 1, 1, 0, 1500), -(9300342, 2000001, 1, 1, 0, 20000), -(9300342, 1002143, 1, 1, 0, 1500), -(9300342, 1432005, 1, 1, 0, 500), -(9300342, 1412012, 1, 1, 0, 700), -(9300342, 1072285, 1, 1, 0, 800), -(9300342, 1482001, 1, 1, 0, 500), -(9300342, 2380011, 1, 1, 0, 8000), -(9300342, 0, 28, 42, 0, 400000), -(9300342, 4031146, 1, 1, 2065, 1000000), -(9300342, 2040902, 1, 1, 0, 750), -(9300342, 2041020, 1, 1, 0, 750), -(9300342, 2048001, 1, 1, 0, 750), -(9300342, 2048003, 1, 1, 0, 750), -(9300342, 2044701, 1, 1, 0, 750), -(9300342, 4010005, 1, 1, 0, 7000), -(9300342, 1302020, 1, 1, 0, 700), -(9300342, 1302030, 1, 1, 0, 700), -(9300342, 1442013, 1, 1, 0, 700), -(9300342, 1412002, 1, 1, 0, 700), -(9300342, 1382012, 1, 1, 0, 700), -(9300342, 1041018, 1, 1, 0, 700), -(9300342, 1452022, 1, 1, 0, 700), -(9300342, 1060031, 1, 1, 0, 700), -(9300342, 4001369, 1, 1, 28259, 10000), (9300343, 0, 14, 21, 0, 400000), (9300343, 1002008, 1, 1, 0, 1500), (9300343, 1002610, 1, 1, 0, 1500), @@ -20671,6 +20623,10 @@ USE `maplesolaxia`; (9300343, 4032340, 1, 1, 21710, 200000); -- Copying drops from some mobs to other versions of them + + INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) + SELECT 9300342, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance` FROM drop_data WHERE dropperid = 1210102; + INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) SELECT 6300001, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance` FROM drop_data WHERE dropperid = 6300000; @@ -21354,4 +21310,1213 @@ USE `maplesolaxia`; DELETE FROM `reactordrops` WHERE itemid=4022023; DELETE FROM `reactordrops` WHERE itemid=4032362; DELETE FROM `reactordrops` WHERE itemid=4032363; - DELETE FROM `reactordrops` WHERE itemid=4032980; \ No newline at end of file + DELETE FROM `reactordrops` WHERE itemid=4032980; + + # MapleMesoFetcher ftw! Set meso drop for remaining mobs which drops more than 4 items. + INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES +(100122, 0, 14, 20, 0, 400000), +(100123, 0, 19, 29, 0, 400000), +(100124, 0, 25, 37, 0, 400000), +(100130, 0, 2, 4, 0, 400000), +(100131, 0, 8, 12, 0, 400000), +(100132, 0, 14, 20, 0, 400000), +(100133, 0, 19, 29, 0, 400000), +(100134, 0, 25, 37, 0, 400000), +(1110130, 0, 42, 62, 0, 400000), +(1140130, 0, 54, 79, 0, 400000), +(2100100, 0, 56, 83, 0, 400000), +(2100101, 0, 59, 87, 0, 400000), +(2100106, 0, 68, 100, 0, 400000), +(2100107, 0, 76, 112, 0, 400000), +(2100108, 0, 82, 121, 0, 400000), +(2110300, 0, 68, 100, 0, 400000), +(2110301, 0, 82, 121, 0, 400000), +(2230105, 0, 65, 96, 0, 400000), +(2230107, 0, 68, 100, 0, 400000), +(2230110, 0, 65, 96, 0, 400000), +(2230111, 0, 68, 100, 0, 400000), +(2230131, 0, 68, 100, 0, 400000), +(3000005, 0, 85, 125, 0, 400000), +(3100101, 0, 91, 133, 0, 400000), +(3100102, 0, 85, 125, 0, 400000), +(3110301, 0, 91, 133, 0, 400000), +(3110302, 0, 99, 146, 0, 400000), +(3110303, 0, 108, 158, 0, 400000), +(3220000, 0, 297, 1460, 0, 400000), +(3220001, 0, 324, 1580, 0, 400000), +(3300000, 0, 85, 125, 0, 400000), +(3300001, 0, 85, 125, 0, 400000), +(3300002, 0, 88, 129, 0, 400000), +(3300003, 0, 91, 133, 0, 400000), +(3300004, 0, 93, 137, 0, 400000), +(3300005, 0, 99, 146, 0, 400000), +(3300006, 0, 99, 146, 0, 400000), +(3300007, 0, 99, 146, 0, 400000), +(3300008, 0, 324, 1580, 0, 400000), +(4110300, 0, 119, 175, 0, 400000), +(4110301, 0, 128, 187, 0, 400000), +(4130103, 0, 399, 1960, 0, 400000), +(4220000, 0, 384, 1870, 0, 400000), +(4230122, 0, 119, 175, 0, 400000), +(4230125, 0, 125, 183, 0, 400000), +(4230400, 0, 128, 187, 0, 400000), +(4230502, 0, 122, 179, 0, 400000), +(4230503, 0, 128, 187, 0, 400000), +(4230504, 0, 128, 187, 0, 400000), +(4230600, 0, 113, 167, 0, 400000), +(4240000, 0, 139, 204, 0, 400000), +(4250000, 0, 119, 175, 0, 400000), +(4250001, 0, 131, 192, 0, 400000), +(5110300, 0, 142, 208, 0, 400000), +(5120500, 0, 159, 233, 0, 400000), +(5120501, 0, 150, 221, 0, 400000), +(5120502, 0, 153, 225, 0, 400000), +(5120505, 0, 165, 242, 0, 400000), +(5120506, 0, 156, 229, 0, 400000), +(5130105, 0, 159, 233, 0, 400000), +(5130108, 0, 162, 238, 0, 400000), +(5220000, 0, 468, 2290, 0, 400000), +(5220002, 0, 426, 2080, 0, 400000), +(5220003, 0, 504, 2460, 0, 400000), +(5220004, 0, 426, 2080, 0, 400000), +(5250000, 0, 156, 229, 0, 400000), +(5250001, 0, 145, 213, 0, 400000), +(5250002, 0, 162, 238, 0, 400000), +(6110300, 0, 185, 271, 0, 400000), +(6130102, 0, 170, 250, 0, 400000), +(6130103, 0, 170, 250, 0, 400000), +(6130203, 0, 170, 250, 0, 400000), +(6130207, 0, 176, 258, 0, 400000), +(6130209, 0, 187, 275, 0, 400000), +(6220000, 0, 555, 2710, 0, 400000), +(6220001, 0, 555, 2710, 0, 400000), +(6230100, 0, 176, 258, 0, 400000), +(6230401, 0, 179, 263, 0, 400000), +(6300005, 0, 555, 2710, 0, 400000), +(6400006, 0, 375, 1830, 0, 400000), +(6400008, 0, 468, 2290, 0, 400000), +(6400009, 0, 468, 2290, 0, 400000), +(7110300, 0, 213, 313, 0, 400000), +(7110301, 0, 207, 304, 0, 400000), +(7120103, 0, 199, 292, 0, 400000), +(7120104, 0, 202, 296, 0, 400000), +(7120106, 0, 213, 313, 0, 400000), +(7120107, 0, 213, 313, 0, 400000), +(7120108, 0, 219, 321, 0, 400000), +(7120109, 0, 225, 329, 0, 400000), +(7130000, 0, 207, 304, 0, 400000), +(7130002, 0, 205, 300, 0, 400000), +(7130003, 0, 216, 317, 0, 400000), +(7130004, 0, 222, 325, 0, 400000), +(7130102, 0, 222, 325, 0, 400000), +(7130103, 0, 207, 304, 0, 400000), +(7130400, 0, 597, 2920, 0, 400000), +(7130401, 0, 597, 2920, 0, 400000), +(7130402, 0, 597, 2920, 0, 400000), +(7130601, 0, 216, 317, 0, 400000), +(7220000, 0, 606, 2960, 0, 400000), +(7220001, 0, 597, 2920, 0, 400000), +(7220002, 0, 657, 3210, 0, 400000), +(8110300, 0, 227, 334, 0, 400000), +(8120102, 0, 233, 342, 0, 400000), +(8120103, 0, 239, 350, 0, 400000), +(8120104, 0, 244, 359, 0, 400000), +(8120105, 0, 250, 367, 0, 400000), +(8120106, 0, 253, 371, 0, 400000), +(8120107, 0, 253, 371, 0, 400000), +(8140000, 0, 227, 334, 0, 400000), +(8140100, 0, 233, 342, 0, 400000), +(8140511, 0, 615, 1130, 0, 400000), +(8140512, 0, 628, 1154, 0, 400000), +(8140600, 0, 622, 1142, 0, 400000), +(8140702, 0, 642, 1179, 0, 400000), +(8140703, 0, 655, 1204, 0, 400000), +(8141300, 0, 635, 1167, 0, 400000), +(8150000, 0, 2028, 12410, 0, 400000), +(8150100, 0, 676, 1241, 0, 400000), +(8150101, 0, 689, 1266, 0, 400000), +(8150200, 0, 676, 1241, 0, 400000), +(8150201, 0, 710, 1303, 0, 400000), +(8150300, 0, 655, 1204, 0, 400000), +(8150301, 0, 683, 1254, 0, 400000), +(8150302, 0, 696, 1279, 0, 400000), +(8190001, 0, 710, 1303, 0, 400000), +(8220003, 0, 2433, 14900, 0, 400000), +(8220005, 0, 2655, 16260, 0, 400000), +(8220006, 0, 2859, 17510, 0, 400000), +(8220007, 0, 1824, 11170, 0, 400000), +(8220009, 0, 726, 3550, 0, 400000), +(8830000, 0, 2130, 13030, 0, 400000), +(9001009, 0, 681, 3340, 0, 400000), +(9001011, 0, 99, 146, 0, 400000), +(9200016, 0, 85, 125, 0, 400000), +(9200019, 0, 165, 242, 0, 400000), +(9300011, 0, 111, 162, 0, 400000), +(9300058, 0, 19, 29, 0, 400000), +(9300059, 0, 28, 41, 0, 400000), +(9300060, 0, 119, 175, 0, 400000), +(9300078, 0, 710, 1303, 0, 400000), +(9300080, 0, 193, 284, 0, 400000), +(9300096, 0, 250, 367, 0, 400000), +(9300105, 0, 537, 2630, 0, 400000), +(9300106, 0, 579, 2840, 0, 400000), +(9300127, 0, 85, 125, 0, 400000), +(9300129, 0, 85, 125, 0, 400000), +(9300131, 0, 111, 162, 0, 400000), +(9300132, 0, 85, 125, 0, 400000), +(9300133, 0, 85, 125, 0, 400000), +(9300134, 0, 85, 125, 0, 400000), +(9300136, 0, 255, 1250, 0, 400000), +(9300139, 0, 690, 3380, 0, 400000), +(9300155, 0, 19, 29, 0, 400000), +(9300160, 0, 384, 1870, 0, 400000), +(9300161, 0, 384, 1870, 0, 400000), +(9300163, 0, 811, 1490, 0, 400000), +(9300164, 0, 811, 1490, 0, 400000), +(9300165, 0, 811, 1490, 0, 400000), +(9300182, 0, 726, 3550, 0, 400000), +(9300184, 0, 168, 830, 0, 400000), +(9300185, 0, 297, 1460, 0, 400000), +(9300186, 0, 324, 1580, 0, 400000), +(9300187, 0, 339, 1670, 0, 400000), +(9300188, 0, 426, 2080, 0, 400000), +(9300189, 0, 426, 2080, 0, 400000), +(9300190, 0, 468, 2290, 0, 400000), +(9300191, 0, 510, 2500, 0, 400000), +(9300192, 0, 477, 2330, 0, 400000), +(9300193, 0, 504, 2460, 0, 400000), +(9300194, 0, 555, 2710, 0, 400000), +(9300195, 0, 555, 2710, 0, 400000), +(9300196, 0, 555, 2710, 0, 400000), +(9300197, 0, 555, 2710, 0, 400000), +(9300198, 0, 510, 2500, 0, 400000), +(9300199, 0, 597, 2920, 0, 400000), +(9300200, 0, 606, 2960, 0, 400000), +(9300201, 0, 726, 3550, 0, 400000), +(9300202, 0, 657, 3210, 0, 400000), +(9300203, 0, 681, 3340, 0, 400000), +(9300204, 0, 708, 3460, 0, 400000), +(9300205, 0, 690, 3380, 0, 400000), +(9300206, 0, 726, 3550, 0, 400000), +(9300207, 0, 726, 3550, 0, 400000), +(9300208, 0, 1824, 11170, 0, 400000), +(9300209, 0, 1824, 11170, 0, 400000), +(9300210, 0, 2028, 12410, 0, 400000), +(9300211, 0, 2130, 13030, 0, 400000), +(9300212, 0, 2130, 13030, 0, 400000), +(9300213, 0, 2433, 14900, 0, 400000), +(9300214, 0, 2535, 15520, 0, 400000), +(9300215, 0, 3042, 18620, 0, 400000), +(9300217, 0, 5, 8, 0, 400000), +(9300218, 0, 11, 16, 0, 400000), +(9300219, 0, 11, 16, 0, 400000), +(9300220, 0, 48, 71, 0, 400000), +(9300221, 0, 71, 104, 0, 400000), +(9300222, 0, 79, 116, 0, 400000), +(9300223, 0, 17, 25, 0, 400000), +(9300224, 0, 105, 154, 0, 400000), +(9300225, 0, 105, 154, 0, 400000), +(9300226, 0, 113, 167, 0, 400000), +(9300227, 0, 105, 154, 0, 400000), +(9300228, 0, 136, 200, 0, 400000), +(9300229, 0, 22, 33, 0, 400000), +(9300230, 0, 116, 171, 0, 400000), +(9300231, 0, 131, 192, 0, 400000), +(9300232, 0, 96, 142, 0, 400000), +(9300233, 0, 113, 167, 0, 400000), +(9300234, 0, 91, 133, 0, 400000), +(9300235, 0, 148, 217, 0, 400000), +(9300236, 0, 159, 233, 0, 400000), +(9300237, 0, 168, 246, 0, 400000), +(9300238, 0, 68, 100, 0, 400000), +(9300239, 0, 119, 175, 0, 400000), +(9300240, 0, 128, 187, 0, 400000), +(9300241, 0, 193, 284, 0, 400000), +(9300242, 0, 199, 292, 0, 400000), +(9300243, 0, 159, 233, 0, 400000), +(9300244, 0, 159, 233, 0, 400000), +(9300245, 0, 170, 250, 0, 400000), +(9300246, 0, 176, 258, 0, 400000), +(9300247, 0, 185, 271, 0, 400000), +(9300248, 0, 187, 275, 0, 400000), +(9300249, 0, 199, 292, 0, 400000), +(9300250, 0, 213, 313, 0, 400000), +(9300251, 0, 207, 304, 0, 400000), +(9300252, 0, 128, 187, 0, 400000), +(9300253, 0, 142, 208, 0, 400000), +(9300254, 0, 207, 304, 0, 400000), +(9300255, 0, 133, 196, 0, 400000), +(9300256, 0, 170, 250, 0, 400000), +(9300257, 0, 170, 250, 0, 400000), +(9300258, 0, 185, 271, 0, 400000), +(9300259, 0, 56, 83, 0, 400000), +(9300260, 0, 227, 334, 0, 400000), +(9300261, 0, 250, 367, 0, 400000), +(9300262, 0, 250, 367, 0, 400000), +(9300263, 0, 250, 367, 0, 400000), +(9300264, 0, 696, 1279, 0, 400000), +(9300265, 0, 683, 1254, 0, 400000), +(9300266, 0, 606, 2960, 0, 400000), +(9300267, 0, 681, 3340, 0, 400000), +(9300268, 0, 606, 2960, 0, 400000), +(9300269, 0, 168, 830, 0, 400000), +(9300270, 0, 227, 334, 0, 400000), +(9300274, 0, 22, 33, 0, 400000), +(9300289, 0, 1824, 11170, 0, 400000), +(9300294, 0, 2028, 12410, 0, 400000), +(9300315, 0, 435, 2130, 0, 400000), +(9300316, 0, 450, 2210, 0, 400000), +(9300317, 0, 468, 2290, 0, 400000), +(9300318, 0, 486, 2380, 0, 400000), +(9300319, 0, 504, 2460, 0, 400000), +(9300320, 0, 519, 2540, 0, 400000), +(9300321, 0, 537, 2630, 0, 400000), +(9300322, 0, 555, 2710, 0, 400000), +(9300332, 0, 113, 167, 0, 400000), +(9300334, 0, 139, 204, 0, 400000), +(9300335, 0, 116, 171, 0, 400000), +(9300336, 0, 131, 192, 0, 400000), +(9300337, 0, 131, 192, 0, 400000), +(9300367, 0, 84, 410, 0, 400000), +(9300368, 0, 168, 830, 0, 400000), +(9300369, 0, 255, 1250, 0, 400000), +(9300370, 0, 339, 1670, 0, 400000), +(9300371, 0, 426, 2080, 0, 400000), +(9300372, 0, 510, 2500, 0, 400000), +(9300373, 0, 597, 2920, 0, 400000), +(9300374, 0, 681, 3340, 0, 400000), +(9300375, 0, 1824, 11170, 0, 400000), +(9300376, 0, 1824, 11170, 0, 400000), +(9300377, 0, 2229, 13660, 0, 400000), +(9303000, 0, 28, 41, 0, 400000), +(9303001, 0, 28, 41, 0, 400000), +(9303003, 0, 28, 41, 0, 400000), +(9303004, 0, 28, 41, 0, 400000), +(9303005, 0, 74, 108, 0, 400000), +(9303006, 0, 74, 108, 0, 400000), +(9303007, 0, 74, 108, 0, 400000), +(9303008, 0, 74, 108, 0, 400000), +(9303009, 0, 145, 213, 0, 400000), +(9303010, 0, 145, 213, 0, 400000), +(9303011, 0, 145, 213, 0, 400000), +(9303013, 0, 230, 338, 0, 400000), +(9303014, 0, 230, 338, 0, 400000), +(9303016, 0, 230, 338, 0, 400000), +(9400009, 0, 1352, 2483, 0, 400000), +(9400012, 0, 170, 250, 0, 400000), +(9400120, 0, 1926, 11790, 0, 400000), +(9400122, 0, 1926, 11790, 0, 400000), +(9400200, 0, 156, 229, 0, 400000), +(9400203, 0, 113, 167, 0, 400000), +(9400205, 0, 1824, 11170, 0, 400000), +(9400238, 0, 85, 125, 0, 400000), +(9400239, 0, 68, 100, 0, 400000), +(9400241, 0, 19, 29, 0, 400000), +(9400242, 0, 28, 41, 0, 400000), +(9400243, 0, 156, 229, 0, 400000), +(9400244, 0, 168, 246, 0, 400000), +(9400245, 0, 68, 100, 0, 400000), +(9400246, 0, 62, 91, 0, 400000), +(9400247, 0, 85, 125, 0, 400000), +(9400248, 0, 68, 100, 0, 400000), +(9400500, 0, 6, 40, 0, 400000), +(9400501, 0, 14, 20, 0, 400000), +(9400502, 0, 42, 200, 0, 400000), +(9400503, 0, 42, 200, 0, 400000), +(9400504, 0, 2, 4, 0, 400000), +(9400538, 0, 54, 79, 0, 400000), +(9400539, 0, 59, 87, 0, 400000), +(9400540, 0, 71, 104, 0, 400000), +(9400541, 0, 71, 104, 0, 400000), +(9400542, 0, 102, 150, 0, 400000), +(9400543, 0, 116, 171, 0, 400000), +(9400544, 0, 142, 208, 0, 400000), +(9400546, 0, 125, 183, 0, 400000), +(9400547, 0, 76, 112, 0, 400000), +(9400548, 0, 85, 125, 0, 400000), +(9400550, 0, 76, 112, 0, 400000), +(9400556, 0, 59, 87, 0, 400000), +(9400558, 0, 85, 125, 0, 400000), +(9400560, 0, 142, 208, 0, 400000), +(9400561, 0, 170, 250, 0, 400000), +(9400562, 0, 170, 250, 0, 400000), +(9400563, 0, 113, 167, 0, 400000), +(9400565, 0, 59, 87, 0, 400000), +(9400570, 0, 42, 62, 0, 400000), +(9400571, 0, 426, 2080, 0, 400000), +(9400573, 0, 113, 167, 0, 400000), +(9400574, 0, 676, 1241, 0, 400000), +(9400576, 0, 199, 292, 0, 400000), +(9400578, 0, 608, 1117, 0, 400000), +(9400579, 0, 676, 1241, 0, 400000), +(9400580, 0, 642, 1179, 0, 400000), +(9400581, 0, 227, 334, 0, 400000), +(9400582, 0, 811, 1490, 0, 400000), +(9400609, 0, 213, 1040, 0, 400000), +(9400612, 0, 213, 1040, 0, 400000), +(9400633, 0, 273, 1330, 0, 400000), +(9400644, 0, 28, 41, 0, 400000), +(9410014, 0, 242, 355, 0, 400000), +(9410015, 0, 726, 3550, 0, 400000), +(9420507, 0, 136, 200, 0, 400000), +(9420527, 0, 128, 187, 0, 400000), +(9420528, 0, 133, 196, 0, 400000), +(9420529, 0, 148, 217, 0, 400000), +(9420530, 0, 159, 233, 0, 400000), +(9420531, 0, 168, 246, 0, 400000), +(9420532, 0, 168, 246, 0, 400000), +(9420533, 0, 173, 254, 0, 400000), +(9420534, 0, 185, 271, 0, 400000), +(9420535, 0, 193, 284, 0, 400000), +(9420536, 0, 205, 300, 0, 400000), +(9420537, 0, 213, 313, 0, 400000), +(9420538, 0, 233, 342, 0, 400000), +(9420539, 0, 247, 363, 0, 400000), +(9420545, 0, 168, 246, 0, 400000), +(9420550, 0, 168, 246, 0, 400000), +(9500101, 0, 19, 29, 0, 400000), +(9500102, 0, 22, 33, 0, 400000), +(9500103, 0, 42, 62, 0, 400000), +(9500104, 0, 34, 50, 0, 400000), +(9500105, 0, 42, 62, 0, 400000), +(9500106, 0, 62, 91, 0, 400000), +(9500107, 0, 85, 125, 0, 400000), +(9500108, 0, 91, 133, 0, 400000), +(9500109, 0, 91, 133, 0, 400000), +(9500110, 0, 99, 146, 0, 400000), +(9500111, 0, 99, 146, 0, 400000), +(9500112, 0, 99, 146, 0, 400000), +(9500113, 0, 102, 150, 0, 400000), +(9500115, 0, 105, 154, 0, 400000), +(9500116, 0, 113, 167, 0, 400000), +(9500117, 0, 102, 150, 0, 400000), +(9500118, 0, 111, 162, 0, 400000), +(9500119, 0, 111, 162, 0, 400000), +(9500120, 0, 128, 187, 0, 400000), +(9500121, 0, 136, 200, 0, 400000), +(9500122, 0, 139, 204, 0, 400000), +(9500123, 0, 168, 246, 0, 400000), +(9500124, 0, 510, 2500, 0, 400000), +(9500125, 0, 170, 250, 0, 400000), +(9500126, 0, 182, 267, 0, 400000), +(9500127, 0, 190, 279, 0, 400000), +(9500128, 0, 193, 284, 0, 400000), +(9500129, 0, 199, 292, 0, 400000), +(9500130, 0, 597, 2920, 0, 400000), +(9500131, 0, 207, 304, 0, 400000), +(9500132, 0, 213, 313, 0, 400000), +(9500134, 0, 227, 334, 0, 400000), +(9500135, 0, 242, 355, 0, 400000), +(9500136, 0, 662, 1217, 0, 400000), +(9500137, 0, 642, 1179, 0, 400000), +(9500138, 0, 608, 1117, 0, 400000), +(9500139, 0, 681, 3340, 0, 400000), +(9500140, 0, 2028, 12410, 0, 400000), +(9500156, 0, 136, 200, 0, 400000), +(9500157, 0, 99, 146, 0, 400000), +(9500158, 0, 597, 2920, 0, 400000), +(9500159, 0, 597, 2920, 0, 400000), +(9500160, 0, 597, 2920, 0, 400000), +(9500161, 0, 227, 334, 0, 400000), +(9500162, 0, 227, 334, 0, 400000), +(9500163, 0, 236, 346, 0, 400000), +(9500164, 0, 250, 367, 0, 400000), +(9500165, 0, 250, 367, 0, 400000), +(9500166, 0, 250, 367, 0, 400000), +(9500178, 0, 113, 167, 0, 400000), +(9500180, 0, 1824, 11170, 0, 400000), +(9500181, 0, 1824, 11170, 0, 400000), +(9500306, 0, 168, 830, 0, 400000), +(9500307, 0, 297, 1460, 0, 400000), +(9500308, 0, 426, 2080, 0, 400000), +(9500309, 0, 468, 2290, 0, 400000), +(9500310, 0, 504, 2460, 0, 400000), +(9500311, 0, 555, 2710, 0, 400000), +(9500312, 0, 597, 2920, 0, 400000), +(9500313, 0, 606, 2960, 0, 400000), +(9500314, 0, 657, 3210, 0, 400000), +(9500317, 0, 84, 410, 0, 400000), +(9500318, 0, 339, 1670, 0, 400000), +(9500319, 0, 597, 2920, 0, 400000), +(9500321, 0, 28, 41, 0, 400000), +(9500326, 0, 384, 1870, 0, 400000), +(9500327, 0, 255, 1250, 0, 400000), +(9500328, 0, 297, 1460, 0, 400000), +(9500331, 0, 468, 2290, 0, 400000), +(9500332, 0, 384, 1870, 0, 400000), +(9500333, 0, 426, 2080, 0, 400000), +(9500334, 0, 468, 2290, 0, 400000), +(9500335, 0, 426, 2080, 0, 400000), +(9500366, 0, 42, 62, 0, 400000), +(9500367, 0, 42, 62, 0, 400000), +(9500368, 0, 42, 62, 0, 400000), +(9500369, 0, 42, 62, 0, 400000), +(9500370, 0, 42, 62, 0, 400000), +(9500371, 0, 42, 62, 0, 400000), +(9500372, 0, 42, 62, 0, 400000); + + DELETE FROM drop_data WHERE dropperid >= 9300184 AND dropperid <= 9300215 AND itemid = 0; + + # MapleArrowFetcher! Set proper arrow quantity drop for them mobs. +UPDATE drop_data +SET minimum_quantity = CASE + WHEN dropperid = 100100 AND itemid = 2060000 THEN 1 + WHEN dropperid = 100100 AND itemid = 2061000 THEN 1 + WHEN dropperid = 100101 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100101 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100120 AND itemid = 2060000 THEN 1 + WHEN dropperid = 100120 AND itemid = 2061000 THEN 1 + WHEN dropperid = 100121 AND itemid = 2060000 THEN 5 + WHEN dropperid = 100123 AND itemid = 2061000 THEN 13 + WHEN dropperid = 100124 AND itemid = 2060000 THEN 17 + WHEN dropperid = 100124 AND itemid = 2061000 THEN 17 + WHEN dropperid = 120100 AND itemid = 2060000 THEN 3 + WHEN dropperid = 120100 AND itemid = 2061000 THEN 3 + WHEN dropperid = 130100 AND itemid = 2060000 THEN 7 + WHEN dropperid = 130100 AND itemid = 2061000 THEN 7 + WHEN dropperid = 130101 AND itemid = 2060000 THEN 7 + WHEN dropperid = 130101 AND itemid = 2061000 THEN 7 + WHEN dropperid = 210100 AND itemid = 2060000 THEN 11 + WHEN dropperid = 210100 AND itemid = 2061000 THEN 11 + WHEN dropperid = 1110100 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1110100 AND itemid = 2061000 THEN 29 + WHEN dropperid = 1110101 AND itemid = 2060000 THEN 19 + WHEN dropperid = 1110101 AND itemid = 2061000 THEN 19 + WHEN dropperid = 1110130 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1110130 AND itemid = 2061000 THEN 29 + WHEN dropperid = 1120100 AND itemid = 2060000 THEN 23 + WHEN dropperid = 1120100 AND itemid = 2061000 THEN 23 + WHEN dropperid = 1130100 AND itemid = 2060000 THEN 33 + WHEN dropperid = 1130100 AND itemid = 2061000 THEN 33 + WHEN dropperid = 1140100 AND itemid = 2060000 THEN 36 + WHEN dropperid = 1140100 AND itemid = 2061000 THEN 36 + WHEN dropperid = 1140130 AND itemid = 2060000 THEN 36 + WHEN dropperid = 1140130 AND itemid = 2061000 THEN 36 + WHEN dropperid = 1210100 AND itemid = 2060000 THEN 13 + WHEN dropperid = 1210100 AND itemid = 2061000 THEN 13 + WHEN dropperid = 1210101 AND itemid = 2060000 THEN 19 + WHEN dropperid = 1210101 AND itemid = 2061000 THEN 19 + WHEN dropperid = 1210102 AND itemid = 2060000 THEN 15 + WHEN dropperid = 1210102 AND itemid = 2061000 THEN 15 + WHEN dropperid = 1210103 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1210103 AND itemid = 2061000 THEN 29 + WHEN dropperid = 2100100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2100100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 2100101 AND itemid = 2060000 THEN 40 + WHEN dropperid = 2100101 AND itemid = 2061000 THEN 40 + WHEN dropperid = 2100102 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2100102 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2100103 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2100103 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2100104 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2100104 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2100105 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2100105 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2100106 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2100106 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2100107 AND itemid = 2060000 THEN 52 + WHEN dropperid = 2100107 AND itemid = 2061000 THEN 52 + WHEN dropperid = 2100108 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2100108 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2110200 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2110200 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2110300 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2110300 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2110301 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2110301 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2130100 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2130100 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2220000 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2220000 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2220100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2220100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 2230100 AND itemid = 2060000 THEN 52 + WHEN dropperid = 2230100 AND itemid = 2061000 THEN 52 + WHEN dropperid = 2230101 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230101 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230102 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2230102 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2230103 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230103 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230104 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2230104 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2230105 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230105 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230106 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2230106 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2230107 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230107 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230108 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2230108 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2230109 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2230109 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2230110 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230110 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230111 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230111 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230131 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230131 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230200 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2230200 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2300100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2300100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 3000000 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000000 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3000005 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000005 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3000006 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000006 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3100101 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3100101 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3100102 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3100102 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3110101 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110101 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110102 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110102 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110300 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110300 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110301 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110301 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110302 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3110302 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3110303 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3110303 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3210100 AND itemid = 2060005 THEN 10 + WHEN dropperid = 3210203 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210203 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210204 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210204 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210205 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210205 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210206 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210206 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210207 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210207 AND itemid = 2060005 THEN 11 + WHEN dropperid = 3210207 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210208 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210208 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210450 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210450 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210800 AND itemid = 2060005 THEN 12 + WHEN dropperid = 3220000 AND itemid = 2060000 THEN 95 + WHEN dropperid = 3220000 AND itemid = 2061000 THEN 95 + WHEN dropperid = 3230100 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230100 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230103 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230103 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3230200 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230200 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230302 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230302 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230303 AND itemid = 2060000 THEN 72 + WHEN dropperid = 3230303 AND itemid = 2061000 THEN 72 + WHEN dropperid = 3230304 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230304 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3230305 AND itemid = 2060000 THEN 75 + WHEN dropperid = 3230305 AND itemid = 2061000 THEN 75 + WHEN dropperid = 3230306 AND itemid = 2060000 THEN 72 + WHEN dropperid = 3230306 AND itemid = 2061000 THEN 72 + WHEN dropperid = 3230307 AND itemid = 2060000 THEN 60 + WHEN dropperid = 3230307 AND itemid = 2061000 THEN 60 + WHEN dropperid = 3230308 AND itemid = 2060000 THEN 75 + WHEN dropperid = 3230308 AND itemid = 2061000 THEN 75 + WHEN dropperid = 3230400 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3230400 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3230405 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230405 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3300000 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3300000 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3300001 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3300001 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3300002 AND itemid = 2060000 THEN 60 + WHEN dropperid = 3300002 AND itemid = 2061000 THEN 60 + WHEN dropperid = 3300003 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3300003 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3300004 AND itemid = 2060000 THEN 64 + WHEN dropperid = 3300004 AND itemid = 2061000 THEN 64 + WHEN dropperid = 3300006 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3300006 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3300007 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3300007 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3300008 AND itemid = 2060000 THEN 103 + WHEN dropperid = 3300008 AND itemid = 2061000 THEN 103 + WHEN dropperid = 4110300 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4110300 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4110301 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4110301 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4130103 AND itemid = 2060000 THEN 128 + WHEN dropperid = 4130103 AND itemid = 2061000 THEN 128 + WHEN dropperid = 4230103 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230103 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230106 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230106 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230108 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230108 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230109 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230109 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230110 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230110 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230111 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230111 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230112 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230112 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230113 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230113 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230114 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230114 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230115 AND itemid = 2060000 THEN 89 + WHEN dropperid = 4230115 AND itemid = 2061000 THEN 89 + WHEN dropperid = 4230116 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230116 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230117 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230117 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230118 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230118 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230119 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230119 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230120 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230120 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230121 AND itemid = 2060000 THEN 89 + WHEN dropperid = 4230121 AND itemid = 2061000 THEN 89 + WHEN dropperid = 4230123 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230123 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230124 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230124 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230125 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230125 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230126 AND itemid = 2060000 THEN 91 + WHEN dropperid = 4230126 AND itemid = 2061000 THEN 91 + WHEN dropperid = 4230201 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230201 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230300 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230300 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230400 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230400 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230500 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230500 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230501 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230501 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230502 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230502 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230503 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230503 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230504 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230504 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230600 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230600 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4240000 AND itemid = 2060000 THEN 95 + WHEN dropperid = 4240000 AND itemid = 2061000 THEN 95 + WHEN dropperid = 5120100 AND itemid = 2060000 THEN 147 + WHEN dropperid = 5120100 AND itemid = 2061000 THEN 147 + WHEN dropperid = 5130104 AND itemid = 2060000 THEN 107 + WHEN dropperid = 5130104 AND itemid = 2061000 THEN 107 + WHEN dropperid = 5140000 AND itemid = 2060000 THEN 112 + WHEN dropperid = 5140000 AND itemid = 2061000 THEN 112 + WHEN dropperid = 5150000 AND itemid = 2060000 THEN 114 + WHEN dropperid = 5150000 AND itemid = 2061000 THEN 114 + WHEN dropperid = 5200000 AND itemid = 2060001 THEN 22 + WHEN dropperid = 5200000 AND itemid = 2061001 THEN 22 + WHEN dropperid = 5200001 AND itemid = 2060001 THEN 29 + WHEN dropperid = 5200001 AND itemid = 2061001 THEN 29 + WHEN dropperid = 5200002 AND itemid = 2060001 THEN 29 + WHEN dropperid = 5200002 AND itemid = 2061001 THEN 29 + WHEN dropperid = 5220000 AND itemid = 2060000 THEN 149 + WHEN dropperid = 5220000 AND itemid = 2061000 THEN 149 + WHEN dropperid = 5220002 AND itemid = 2060000 THEN 136 + WHEN dropperid = 5220002 AND itemid = 2061000 THEN 136 + WHEN dropperid = 5220003 AND itemid = 2060000 THEN 160 + WHEN dropperid = 5220003 AND itemid = 2061000 THEN 160 + WHEN dropperid = 5400000 AND itemid = 2060001 THEN 34 + WHEN dropperid = 5400000 AND itemid = 2061001 THEN 34 + WHEN dropperid = 6220000 AND itemid = 2060000 THEN 177 + WHEN dropperid = 6220000 AND itemid = 2061000 THEN 177 + WHEN dropperid = 7120103 AND itemid = 2060003 THEN 34 + WHEN dropperid = 7220000 AND itemid = 2060001 THEN 96 + WHEN dropperid = 7220000 AND itemid = 2061001 THEN 96 + WHEN dropperid = 7220001 AND itemid = 2060001 THEN 95 + WHEN dropperid = 7220001 AND itemid = 2061001 THEN 95 + WHEN dropperid = 7220002 AND itemid = 2060001 THEN 104 + WHEN dropperid = 7220002 AND itemid = 2061001 THEN 104 + WHEN dropperid = 8220000 AND itemid = 2060001 THEN 113 + WHEN dropperid = 8220000 AND itemid = 2061001 THEN 113 + WHEN dropperid = 8220001 AND itemid = 2060001 THEN 122 + WHEN dropperid = 8220001 AND itemid = 2061001 THEN 122 + WHEN dropperid = 9300011 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9300011 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9300060 AND itemid = 2060000 THEN 81 + WHEN dropperid = 9300060 AND itemid = 2061000 THEN 81 + WHEN dropperid = 9300131 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9300131 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9300132 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9300132 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9300133 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9300160 AND itemid = 2060000 THEN 122 + WHEN dropperid = 9300160 AND itemid = 2061000 THEN 122 + WHEN dropperid = 9300161 AND itemid = 2060000 THEN 122 + WHEN dropperid = 9300161 AND itemid = 2061000 THEN 122 + WHEN dropperid = 9300274 AND itemid = 2060000 THEN 15 + WHEN dropperid = 9300274 AND itemid = 2061000 THEN 15 + WHEN dropperid = 9300332 AND itemid = 2060000 THEN 77 + WHEN dropperid = 9300334 AND itemid = 2060000 THEN 95 + WHEN dropperid = 9300341 AND itemid = 2060000 THEN 11 + WHEN dropperid = 9300341 AND itemid = 2061000 THEN 11 + WHEN dropperid = 9300342 AND itemid = 2060000 THEN 15 + WHEN dropperid = 9300342 AND itemid = 2061000 THEN 15 + WHEN dropperid = 9300343 AND itemid = 2060000 THEN 13 + WHEN dropperid = 9300343 AND itemid = 2061000 THEN 13 + WHEN dropperid = 9303005 AND itemid = 2060001 THEN 25 + WHEN dropperid = 9303005 AND itemid = 2061001 THEN 25 + WHEN dropperid = 9303008 AND itemid = 2060001 THEN 25 + WHEN dropperid = 9303008 AND itemid = 2061001 THEN 25 + WHEN dropperid = 9303009 AND itemid = 2060001 THEN 49 + WHEN dropperid = 9303009 AND itemid = 2061001 THEN 49 + WHEN dropperid = 9400000 AND itemid = 2060001 THEN 24 + WHEN dropperid = 9400009 AND itemid = 2060001 THEN 194 + WHEN dropperid = 9400011 AND itemid = 2060002 THEN 25 + WHEN dropperid = 9400100 AND itemid = 2060003 THEN 21 + WHEN dropperid = 9400101 AND itemid = 2061003 THEN 22 + WHEN dropperid = 9400204 AND itemid = 2060003 THEN 26 + WHEN dropperid = 9400239 AND itemid = 2060000 THEN 46 + WHEN dropperid = 9400239 AND itemid = 2061000 THEN 46 + WHEN dropperid = 9400244 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9400244 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9400248 AND itemid = 2060000 THEN 46 + WHEN dropperid = 9400248 AND itemid = 2061000 THEN 46 + WHEN dropperid = 9400540 AND itemid = 2060004 THEN 9 + WHEN dropperid = 9400540 AND itemid = 2061004 THEN 9 + WHEN dropperid = 9400541 AND itemid = 2060004 THEN 9 + WHEN dropperid = 9400541 AND itemid = 2061004 THEN 9 + WHEN dropperid = 9400542 AND itemid = 2060004 THEN 14 + WHEN dropperid = 9400542 AND itemid = 2061004 THEN 14 + WHEN dropperid = 9400543 AND itemid = 2060004 THEN 15 + WHEN dropperid = 9400543 AND itemid = 2061004 THEN 15 + WHEN dropperid = 9400547 AND itemid = 2060000 THEN 52 + WHEN dropperid = 9400547 AND itemid = 2061000 THEN 52 + WHEN dropperid = 9400548 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9400548 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9400550 AND itemid = 2060000 THEN 52 + WHEN dropperid = 9400550 AND itemid = 2061000 THEN 52 + WHEN dropperid = 9400558 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9400558 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9400563 AND itemid = 2060000 THEN 77 + WHEN dropperid = 9400563 AND itemid = 2061000 THEN 77 + WHEN dropperid = 9400638 AND itemid = 2060000 THEN 38 + WHEN dropperid = 9400638 AND itemid = 2061000 THEN 38 + WHEN dropperid = 9420500 AND itemid = 2060000 THEN 54 + WHEN dropperid = 9420500 AND itemid = 2061000 THEN 54 + WHEN dropperid = 9420502 AND itemid = 2060000 THEN 35 + WHEN dropperid = 9420502 AND itemid = 2061000 THEN 35 + WHEN dropperid = 9420506 AND itemid = 2060000 THEN 44 + WHEN dropperid = 9420506 AND itemid = 2061000 THEN 44 + WHEN dropperid = 9420508 AND itemid = 2060000 THEN 83 + WHEN dropperid = 9420508 AND itemid = 2061000 THEN 83 + WHEN dropperid = 9420527 AND itemid = 2060001 THEN 43 + WHEN dropperid = 9420527 AND itemid = 2061001 THEN 43 + WHEN dropperid = 9420531 AND itemid = 2060001 THEN 57 + WHEN dropperid = 9420531 AND itemid = 2061001 THEN 57 + WHEN dropperid = 9500112 AND itemid = 2060001 THEN 34 + WHEN dropperid = 9500112 AND itemid = 2061001 THEN 34 + WHEN dropperid = 9500119 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9500119 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9500120 AND itemid = 2060000 THEN 87 + WHEN dropperid = 9500120 AND itemid = 2061000 THEN 87 + WHEN dropperid = 9500122 AND itemid = 2060000 THEN 95 + WHEN dropperid = 9500123 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9500123 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9500308 AND itemid = 2060000 THEN 136 + WHEN dropperid = 9500308 AND itemid = 2061000 THEN 136 + WHEN dropperid = 9500310 AND itemid = 2060000 THEN 160 + WHEN dropperid = 9500310 AND itemid = 2061000 THEN 160 + WHEN dropperid = 9500312 AND itemid = 2060001 THEN 95 + WHEN dropperid = 9500312 AND itemid = 2061001 THEN 95 + WHEN dropperid = 9500313 AND itemid = 2060001 THEN 96 + WHEN dropperid = 9500313 AND itemid = 2061001 THEN 96 + WHEN dropperid = 9500314 AND itemid = 2060001 THEN 104 + WHEN dropperid = 9500314 AND itemid = 2061001 THEN 104 + WHEN dropperid = 9500321 AND itemid = 2060001 THEN 9 + WHEN dropperid = 9500321 AND itemid = 2061001 THEN 9 + WHEN dropperid = 9500366 AND itemid = 2060000 THEN 29 + WHEN dropperid = 9500369 AND itemid = 2060000 THEN 29 + ELSE minimum_quantity END, + maximum_quantity = CASE + WHEN dropperid = 100100 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100100 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100101 AND itemid = 2060000 THEN 9 + WHEN dropperid = 100101 AND itemid = 2061000 THEN 9 + WHEN dropperid = 100120 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100120 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100121 AND itemid = 2060000 THEN 15 + WHEN dropperid = 100123 AND itemid = 2061000 THEN 39 + WHEN dropperid = 100124 AND itemid = 2060000 THEN 51 + WHEN dropperid = 100124 AND itemid = 2061000 THEN 51 + WHEN dropperid = 120100 AND itemid = 2060000 THEN 9 + WHEN dropperid = 120100 AND itemid = 2061000 THEN 9 + WHEN dropperid = 130100 AND itemid = 2060000 THEN 21 + WHEN dropperid = 130100 AND itemid = 2061000 THEN 21 + WHEN dropperid = 130101 AND itemid = 2060000 THEN 21 + WHEN dropperid = 130101 AND itemid = 2061000 THEN 21 + WHEN dropperid = 210100 AND itemid = 2060000 THEN 33 + WHEN dropperid = 210100 AND itemid = 2061000 THEN 33 + WHEN dropperid = 1110100 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1110100 AND itemid = 2061000 THEN 87 + WHEN dropperid = 1110101 AND itemid = 2060000 THEN 57 + WHEN dropperid = 1110101 AND itemid = 2061000 THEN 57 + WHEN dropperid = 1110130 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1110130 AND itemid = 2061000 THEN 87 + WHEN dropperid = 1120100 AND itemid = 2060000 THEN 69 + WHEN dropperid = 1120100 AND itemid = 2061000 THEN 69 + WHEN dropperid = 1130100 AND itemid = 2060000 THEN 99 + WHEN dropperid = 1130100 AND itemid = 2061000 THEN 99 + WHEN dropperid = 1140100 AND itemid = 2060000 THEN 108 + WHEN dropperid = 1140100 AND itemid = 2061000 THEN 108 + WHEN dropperid = 1140130 AND itemid = 2060000 THEN 108 + WHEN dropperid = 1140130 AND itemid = 2061000 THEN 108 + WHEN dropperid = 1210100 AND itemid = 2060000 THEN 39 + WHEN dropperid = 1210100 AND itemid = 2061000 THEN 39 + WHEN dropperid = 1210101 AND itemid = 2060000 THEN 57 + WHEN dropperid = 1210101 AND itemid = 2061000 THEN 57 + WHEN dropperid = 1210102 AND itemid = 2060000 THEN 45 + WHEN dropperid = 1210102 AND itemid = 2061000 THEN 45 + WHEN dropperid = 1210103 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1210103 AND itemid = 2061000 THEN 87 + WHEN dropperid = 2100100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2100100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 2100101 AND itemid = 2060000 THEN 120 + WHEN dropperid = 2100101 AND itemid = 2061000 THEN 120 + WHEN dropperid = 2100102 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2100102 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2100103 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2100103 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2100104 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2100104 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2100105 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2100105 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2100106 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2100106 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2100107 AND itemid = 2060000 THEN 156 + WHEN dropperid = 2100107 AND itemid = 2061000 THEN 156 + WHEN dropperid = 2100108 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2100108 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2110200 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2110200 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2110300 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2110300 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2110301 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2110301 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2130100 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2130100 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2220000 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2220000 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2220100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2220100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 2230100 AND itemid = 2060000 THEN 156 + WHEN dropperid = 2230100 AND itemid = 2061000 THEN 156 + WHEN dropperid = 2230101 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230101 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230102 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2230102 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2230103 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230103 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230104 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2230104 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2230105 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230105 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230106 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2230106 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2230107 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230107 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230108 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2230108 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2230109 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2230109 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2230110 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230110 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230111 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230111 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230131 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230131 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230200 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2230200 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2300100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2300100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 3000000 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000000 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3000005 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000005 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3000006 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000006 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3100101 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3100101 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3100102 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3100102 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3110101 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110101 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110102 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110102 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110300 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110300 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110301 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110301 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110302 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3110302 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3110303 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3110303 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3210100 AND itemid = 2060005 THEN 31 + WHEN dropperid = 3210203 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210203 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210204 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210204 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210205 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210205 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210206 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210206 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210207 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210207 AND itemid = 2060005 THEN 33 + WHEN dropperid = 3210207 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210208 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210208 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210450 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210450 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210800 AND itemid = 2060005 THEN 36 + WHEN dropperid = 3220000 AND itemid = 2060000 THEN 285 + WHEN dropperid = 3220000 AND itemid = 2061000 THEN 285 + WHEN dropperid = 3230100 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230100 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230103 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230103 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3230200 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230200 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230302 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230302 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230303 AND itemid = 2060000 THEN 216 + WHEN dropperid = 3230303 AND itemid = 2061000 THEN 216 + WHEN dropperid = 3230304 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230304 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3230305 AND itemid = 2060000 THEN 225 + WHEN dropperid = 3230305 AND itemid = 2061000 THEN 225 + WHEN dropperid = 3230306 AND itemid = 2060000 THEN 216 + WHEN dropperid = 3230306 AND itemid = 2061000 THEN 216 + WHEN dropperid = 3230307 AND itemid = 2060000 THEN 180 + WHEN dropperid = 3230307 AND itemid = 2061000 THEN 180 + WHEN dropperid = 3230308 AND itemid = 2060000 THEN 225 + WHEN dropperid = 3230308 AND itemid = 2061000 THEN 225 + WHEN dropperid = 3230400 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3230400 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3230405 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230405 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3300000 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3300000 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3300001 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3300001 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3300002 AND itemid = 2060000 THEN 180 + WHEN dropperid = 3300002 AND itemid = 2061000 THEN 180 + WHEN dropperid = 3300003 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3300003 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3300004 AND itemid = 2060000 THEN 192 + WHEN dropperid = 3300004 AND itemid = 2061000 THEN 192 + WHEN dropperid = 3300006 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3300006 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3300007 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3300007 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3300008 AND itemid = 2060000 THEN 309 + WHEN dropperid = 3300008 AND itemid = 2061000 THEN 309 + WHEN dropperid = 4110300 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4110300 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4110301 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4110301 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4130103 AND itemid = 2060000 THEN 384 + WHEN dropperid = 4130103 AND itemid = 2061000 THEN 384 + WHEN dropperid = 4230103 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230103 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230106 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230106 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230108 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230108 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230109 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230109 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230110 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230110 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230111 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230111 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230112 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230112 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230113 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230113 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230114 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230114 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230115 AND itemid = 2060000 THEN 267 + WHEN dropperid = 4230115 AND itemid = 2061000 THEN 267 + WHEN dropperid = 4230116 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230116 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230117 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230117 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230118 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230118 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230119 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230119 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230120 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230120 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230121 AND itemid = 2060000 THEN 267 + WHEN dropperid = 4230121 AND itemid = 2061000 THEN 267 + WHEN dropperid = 4230123 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230123 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230124 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230124 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230125 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230125 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230126 AND itemid = 2060000 THEN 273 + WHEN dropperid = 4230126 AND itemid = 2061000 THEN 273 + WHEN dropperid = 4230201 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230201 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230300 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230300 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230400 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230400 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230500 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230500 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230501 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230501 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230502 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230502 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230503 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230503 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230504 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230504 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230600 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230600 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4240000 AND itemid = 2060000 THEN 285 + WHEN dropperid = 4240000 AND itemid = 2061000 THEN 285 + WHEN dropperid = 5120100 AND itemid = 2060000 THEN 441 + WHEN dropperid = 5120100 AND itemid = 2061000 THEN 441 + WHEN dropperid = 5130104 AND itemid = 2060000 THEN 321 + WHEN dropperid = 5130104 AND itemid = 2061000 THEN 321 + WHEN dropperid = 5140000 AND itemid = 2060000 THEN 336 + WHEN dropperid = 5140000 AND itemid = 2061000 THEN 336 + WHEN dropperid = 5150000 AND itemid = 2060000 THEN 342 + WHEN dropperid = 5150000 AND itemid = 2061000 THEN 342 + WHEN dropperid = 5200000 AND itemid = 2060001 THEN 66 + WHEN dropperid = 5200000 AND itemid = 2061001 THEN 66 + WHEN dropperid = 5200001 AND itemid = 2060001 THEN 87 + WHEN dropperid = 5200001 AND itemid = 2061001 THEN 87 + WHEN dropperid = 5200002 AND itemid = 2060001 THEN 87 + WHEN dropperid = 5200002 AND itemid = 2061001 THEN 87 + WHEN dropperid = 5220000 AND itemid = 2060000 THEN 447 + WHEN dropperid = 5220000 AND itemid = 2061000 THEN 447 + WHEN dropperid = 5220002 AND itemid = 2060000 THEN 408 + WHEN dropperid = 5220002 AND itemid = 2061000 THEN 408 + WHEN dropperid = 5220003 AND itemid = 2060000 THEN 480 + WHEN dropperid = 5220003 AND itemid = 2061000 THEN 480 + WHEN dropperid = 5400000 AND itemid = 2060001 THEN 102 + WHEN dropperid = 5400000 AND itemid = 2061001 THEN 102 + WHEN dropperid = 6220000 AND itemid = 2060000 THEN 531 + WHEN dropperid = 6220000 AND itemid = 2061000 THEN 531 + WHEN dropperid = 7120103 AND itemid = 2060003 THEN 102 + WHEN dropperid = 7220000 AND itemid = 2060001 THEN 289 + WHEN dropperid = 7220000 AND itemid = 2061001 THEN 289 + WHEN dropperid = 7220001 AND itemid = 2060001 THEN 285 + WHEN dropperid = 7220001 AND itemid = 2061001 THEN 285 + WHEN dropperid = 7220002 AND itemid = 2060001 THEN 313 + WHEN dropperid = 7220002 AND itemid = 2061001 THEN 313 + WHEN dropperid = 8220000 AND itemid = 2060001 THEN 339 + WHEN dropperid = 8220000 AND itemid = 2061001 THEN 339 + WHEN dropperid = 8220001 AND itemid = 2060001 THEN 367 + WHEN dropperid = 8220001 AND itemid = 2061001 THEN 367 + WHEN dropperid = 9300011 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9300011 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9300060 AND itemid = 2060000 THEN 243 + WHEN dropperid = 9300060 AND itemid = 2061000 THEN 243 + WHEN dropperid = 9300131 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9300131 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9300132 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9300132 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9300133 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9300160 AND itemid = 2060000 THEN 366 + WHEN dropperid = 9300160 AND itemid = 2061000 THEN 366 + WHEN dropperid = 9300161 AND itemid = 2060000 THEN 366 + WHEN dropperid = 9300161 AND itemid = 2061000 THEN 366 + WHEN dropperid = 9300274 AND itemid = 2060000 THEN 45 + WHEN dropperid = 9300274 AND itemid = 2061000 THEN 45 + WHEN dropperid = 9300332 AND itemid = 2060000 THEN 231 + WHEN dropperid = 9300334 AND itemid = 2060000 THEN 285 + WHEN dropperid = 9300341 AND itemid = 2060000 THEN 33 + WHEN dropperid = 9300341 AND itemid = 2061000 THEN 33 + WHEN dropperid = 9300342 AND itemid = 2060000 THEN 45 + WHEN dropperid = 9300342 AND itemid = 2061000 THEN 45 + WHEN dropperid = 9300343 AND itemid = 2060000 THEN 39 + WHEN dropperid = 9300343 AND itemid = 2061000 THEN 39 + WHEN dropperid = 9303005 AND itemid = 2060001 THEN 75 + WHEN dropperid = 9303005 AND itemid = 2061001 THEN 75 + WHEN dropperid = 9303008 AND itemid = 2060001 THEN 75 + WHEN dropperid = 9303008 AND itemid = 2061001 THEN 75 + WHEN dropperid = 9303009 AND itemid = 2060001 THEN 148 + WHEN dropperid = 9303009 AND itemid = 2061001 THEN 148 + WHEN dropperid = 9400000 AND itemid = 2060001 THEN 72 + WHEN dropperid = 9400009 AND itemid = 2060001 THEN 583 + WHEN dropperid = 9400011 AND itemid = 2060002 THEN 77 + WHEN dropperid = 9400100 AND itemid = 2060003 THEN 65 + WHEN dropperid = 9400101 AND itemid = 2061003 THEN 68 + WHEN dropperid = 9400204 AND itemid = 2060003 THEN 80 + WHEN dropperid = 9400239 AND itemid = 2060000 THEN 138 + WHEN dropperid = 9400239 AND itemid = 2061000 THEN 138 + WHEN dropperid = 9400244 AND itemid = 2060000 THEN 342 + WHEN dropperid = 9400244 AND itemid = 2061000 THEN 342 + WHEN dropperid = 9400248 AND itemid = 2060000 THEN 138 + WHEN dropperid = 9400248 AND itemid = 2061000 THEN 138 + WHEN dropperid = 9400540 AND itemid = 2060004 THEN 28 + WHEN dropperid = 9400540 AND itemid = 2061004 THEN 28 + WHEN dropperid = 9400541 AND itemid = 2060004 THEN 28 + WHEN dropperid = 9400541 AND itemid = 2061004 THEN 28 + WHEN dropperid = 9400542 AND itemid = 2060004 THEN 42 + WHEN dropperid = 9400542 AND itemid = 2061004 THEN 42 + WHEN dropperid = 9400543 AND itemid = 2060004 THEN 47 + WHEN dropperid = 9400543 AND itemid = 2061004 THEN 47 + WHEN dropperid = 9400547 AND itemid = 2060000 THEN 156 + WHEN dropperid = 9400547 AND itemid = 2061000 THEN 156 + WHEN dropperid = 9400548 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9400548 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9400550 AND itemid = 2060000 THEN 156 + WHEN dropperid = 9400550 AND itemid = 2061000 THEN 156 + WHEN dropperid = 9400558 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9400558 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9400563 AND itemid = 2060000 THEN 231 + WHEN dropperid = 9400563 AND itemid = 2061000 THEN 231 + WHEN dropperid = 9400638 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9400638 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9420500 AND itemid = 2060000 THEN 162 + WHEN dropperid = 9420500 AND itemid = 2061000 THEN 162 + WHEN dropperid = 9420502 AND itemid = 2060000 THEN 105 + WHEN dropperid = 9420502 AND itemid = 2061000 THEN 105 + WHEN dropperid = 9420506 AND itemid = 2060000 THEN 132 + WHEN dropperid = 9420506 AND itemid = 2061000 THEN 132 + WHEN dropperid = 9420508 AND itemid = 2060000 THEN 249 + WHEN dropperid = 9420508 AND itemid = 2061000 THEN 249 + WHEN dropperid = 9420527 AND itemid = 2060001 THEN 130 + WHEN dropperid = 9420527 AND itemid = 2061001 THEN 130 + WHEN dropperid = 9420531 AND itemid = 2060001 THEN 171 + WHEN dropperid = 9420531 AND itemid = 2061001 THEN 171 + WHEN dropperid = 9500112 AND itemid = 2060001 THEN 102 + WHEN dropperid = 9500112 AND itemid = 2061001 THEN 102 + WHEN dropperid = 9500119 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9500119 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9500120 AND itemid = 2060000 THEN 261 + WHEN dropperid = 9500120 AND itemid = 2061000 THEN 261 + WHEN dropperid = 9500122 AND itemid = 2060000 THEN 285 + WHEN dropperid = 9500123 AND itemid = 2060000 THEN 342 + WHEN dropperid = 9500123 AND itemid = 2061000 THEN 342 + WHEN dropperid = 9500308 AND itemid = 2060000 THEN 408 + WHEN dropperid = 9500308 AND itemid = 2061000 THEN 408 + WHEN dropperid = 9500310 AND itemid = 2060000 THEN 480 + WHEN dropperid = 9500310 AND itemid = 2061000 THEN 480 + WHEN dropperid = 9500312 AND itemid = 2060001 THEN 285 + WHEN dropperid = 9500312 AND itemid = 2061001 THEN 285 + WHEN dropperid = 9500313 AND itemid = 2060001 THEN 289 + WHEN dropperid = 9500313 AND itemid = 2061001 THEN 289 + WHEN dropperid = 9500314 AND itemid = 2060001 THEN 313 + WHEN dropperid = 9500314 AND itemid = 2061001 THEN 313 + WHEN dropperid = 9500321 AND itemid = 2060001 THEN 28 + WHEN dropperid = 9500321 AND itemid = 2061001 THEN 28 + WHEN dropperid = 9500366 AND itemid = 2060000 THEN 87 + WHEN dropperid = 9500369 AND itemid = 2060000 THEN 87 + ELSE maximum_quantity END +; \ No newline at end of file diff --git a/sql/db_shopupdate.sql b/sql/db_shopupdate.sql index 18eecf7210..6b59ca52d1 100644 --- a/sql/db_shopupdate.sql +++ b/sql/db_shopupdate.sql @@ -267,6 +267,7 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `pitch`, `position`) VALU (1200002, 2070000, 500, 0, 108), (1200002, 2061000, 1, 0, 120), (1200002, 2060000, 1, 0, 124), + (1200002, 2030100, 400, 0, 128), (1200002, 2030000, 400, 0, 132), (1200002, 2020028, 3000, 0, 136), (1200002, 2010004, 310, 0, 140), @@ -284,20 +285,21 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `pitch`, `position`) VALU (1200002, 2000002, 320, 0, 188), (1200002, 2000001, 160, 0, 192), (1200002, 2000000, 50, 0, 196), - (1301000, 2330000, 600, 0, 1), - (1301000, 2070000, 500, 0, 2), - (1301000, 2061000, 1, 0, 3), - (1301000, 2060000, 1, 0, 4), - (1301000, 2030000, 400, 0, 5), - (1301000, 2022000, 1650, 0, 6), - (1301000, 2022003, 1100, 0, 7), - (1301000, 2002005, 500, 0, 8), - (1301000, 2002004, 500, 0, 9), - (1301000, 2002002, 500, 0, 10), - (1301000, 2002001, 400, 0, 11), - (1301000, 2002000, 500, 0, 12), - (1301000, 2000006, 620, 0, 13), - (1301000, 2000003, 200, 0, 14), - (1301000, 2000002, 320, 0, 15), - (1301000, 2000015, 160, 0, 16), - (1301000, 2000000, 50, 0, 17); \ No newline at end of file + (1301000, 2330000, 600, 0, 104), + (1301000, 2070000, 500, 0, 108), + (1301000, 2061000, 1, 0, 112), + (1301000, 2060000, 1, 0, 116), + (1301000, 2030100, 400, 0, 120), + (1301000, 2030000, 400, 0, 124), + (1301000, 2022000, 1650, 0, 128), + (1301000, 2022003, 1100, 0, 132), + (1301000, 2002005, 500, 0, 136), + (1301000, 2002004, 500, 0, 140), + (1301000, 2002002, 500, 0, 144), + (1301000, 2002001, 400, 0, 148), + (1301000, 2002000, 500, 0, 152), + (1301000, 2000006, 620, 0, 156), + (1301000, 2000003, 200, 0, 160), + (1301000, 2000002, 320, 0, 164), + (1301000, 2000015, 160, 0, 168), + (1301000, 2000000, 50, 0, 172); \ No newline at end of file diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index 1b5ce9d560..be2abcb976 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -1008,45 +1008,62 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { this.remainingAp += 5; } int job_ = job.getId() % 1000; // lame temp "fix" - if (job_ == 100) { + if (job_ == 100) { // 1st warrior maxhp += Randomizer.rand(200, 250); - } else if (job_ == 200) { + } else if (job_ == 200) { // 1st mage maxmp += Randomizer.rand(100, 150); - } else if (job_ % 100 == 0) { + } else if (job_ % 100 == 0) { // 1st others maxhp += Randomizer.rand(100, 150); maxhp += Randomizer.rand(25, 50); - } else if (job_ > 0 && job_ < 200) { + } else if (job_ > 0 && job_ < 200) { // 2nd~4th warrior maxhp += Randomizer.rand(300, 350); - } else if (job_ < 300) { + } else if (job_ < 300) { // 2nd~4th mage maxmp += Randomizer.rand(450, 500); - } //handle KoC here (undone) - else if (job_ > 0 && job_ != 1000) { + } else if (job_ > 0) { // 2nd~4th others maxhp += Randomizer.rand(300, 350); maxmp += Randomizer.rand(150, 200); } + + /* + //aran perks? + int newJobId = newJob.getId(); + if(newJobId == 2100) { // become aran1 + maxhp += 275; + maxmp += 15; + } else if(newJobId == 2110) { // become aran2 + maxmp += 275; + } else if(newJobId == 2111) { // become aran3 + maxhp += 275; + maxmp += 275; + } + */ + if (maxhp >= 30000) { maxhp = 30000; } if (maxmp >= 30000) { maxmp = 30000; } + if (!isGM()) { for (byte i = 1; i < 5; i++) { gainSlots(i, 4, true); } } + List> statup = new ArrayList<>(5); statup.add(new Pair<>(MapleStat.MAXHP, Integer.valueOf(maxhp))); statup.add(new Pair<>(MapleStat.MAXMP, Integer.valueOf(maxmp))); statup.add(new Pair<>(MapleStat.AVAILABLEAP, remainingAp)); statup.add(new Pair<>(MapleStat.AVAILABLESP, remainingSp[GameConstants.getSkillBook(job.getId())])); statup.add(new Pair<>(MapleStat.JOB, Integer.valueOf(job.getId()))); + client.announce(MaplePacketCreator.updatePlayerStats(statup, this)); + if (dragon != null) { getMap().broadcastMessage(MaplePacketCreator.removeDragon(dragon.getObjectId())); dragon = null; } recalcLocalStats(); - client.announce(MaplePacketCreator.updatePlayerStats(statup, this)); silentPartyUpdate(); if (this.guildid > 0) { getGuild().broadcast(MaplePacketCreator.jobMessage(0, job.getId(), name), this.getId()); @@ -1062,7 +1079,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { if (getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null) { cancelBuffStats(MapleBuffStat.MONSTER_RIDING); } - createDragon(); + createDragon(); } } @@ -3162,21 +3179,26 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } private boolean isSingletonStatup(MapleBuffStat mbs) { - switch(mbs) { - case RECOVERY: - case HPREC: - case MPREC: - case SUMMON: - case PUPPET: - case DRAGONBLOOD: - case MONSTER_RIDING: - case MORPH: - case HYPERBODYHP: - case HYPERBODYMP: - return true; + switch(mbs) { //HPREC and MPREC are supposed to be singleton + case COUPON_EXP1: + case COUPON_EXP2: + case COUPON_EXP3: + case COUPON_EXP4: + case COUPON_DRP1: + case COUPON_DRP2: + case COUPON_DRP3: + case WATK: + case WDEF: + case MATK: + case MDEF: + case ACC: + case AVOID: + case SPEED: + case JUMP: + return false; default: - return false; + return true; } } @@ -6003,7 +6025,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { switch (job.getId()) { case 100: case 1100: - case 2100://? + case 2100: tstr = 35; tap = ((getLevel() - 10) * levelap) + 14; tsp += ((getLevel() - 10) * 3); diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java index 76e119187e..2b0fcb4f11 100644 --- a/src/client/command/Commands.java +++ b/src/client/command/Commands.java @@ -1133,19 +1133,19 @@ public class Commands { short quantity = 1; if(sub.length >= 3) quantity = Short.parseShort(sub[2]); + if (ItemConstants.isPet(itemId)) { + player.message("You cannot create a pet with this command."); + break; + } + if (sub[0].equals("item")) { - int petid = -1; - if (ItemConstants.isPet(itemId)) { - petid = MaplePet.createPet(itemId); - } - - byte flag = 0; + byte flag = 0; if(player.gmLevel() < 3) { flag |= ItemConstants.ACCOUNT_SHARING; flag |= ItemConstants.UNTRADEABLE; } - MapleInventoryManipulator.addById(c, itemId, quantity, player.getName(), petid, flag, -1); + MapleInventoryManipulator.addById(c, itemId, quantity, player.getName(), -1, flag, -1); } else { Item toDrop; if (MapleItemInformationProvider.getInstance().getInventoryType(itemId) == MapleInventoryType.EQUIP) { @@ -2127,20 +2127,17 @@ public class Commands { break; } - int itemid = 0; - short multiply = 0; - - itemid = Integer.parseInt(sub[1]); - multiply = Short.parseShort(sub[2]); + int itemid = Integer.parseInt(sub[1]); + short multiply = Short.parseShort(sub[2]); MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - Item it = ii.getEquipById(itemid); - it.setOwner(player.getName()); MapleInventoryType type = ii.getInventoryType(itemid); if (type.equals(MapleInventoryType.EQUIP)) { + Item it = ii.getEquipById(itemid); + it.setOwner(player.getName()); + hardsetItemStats((Equip) it, multiply); MapleInventoryManipulator.addFromDrop(c, it); - } else { player.dropMessage("Make sure it's an equippable item."); } diff --git a/src/client/inventory/MaplePet.java b/src/client/inventory/MaplePet.java index 66f2c2ffda..63095bdaa1 100644 --- a/src/client/inventory/MaplePet.java +++ b/src/client/inventory/MaplePet.java @@ -60,6 +60,7 @@ public class MaplePet extends Item { public static MaplePet loadFromDb(int itemid, short position, int petid) { try { + System.out.println("fetching " + petid); MaplePet ret = new MaplePet(itemid, position, petid); Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT name, level, closeness, fullness, summoned FROM pets WHERE petid = ?"); // Get pet details.. diff --git a/src/net/server/guild/MapleAlliance.java b/src/net/server/guild/MapleAlliance.java index 2a806bd517..abbb6ed386 100644 --- a/src/net/server/guild/MapleAlliance.java +++ b/src/net/server/guild/MapleAlliance.java @@ -331,18 +331,21 @@ public class MapleAlliance { public boolean addGuild(int gid) { synchronized (guilds) { if(guilds.size() == capacity || getGuildIndex(gid) > -1) return false; + guilds.add(gid); + return true; } - return true; } private int getGuildIndex(int gid) { - for (int i = 0; i < guilds.size(); i++) { - if (guilds.get(i) == gid) { - return i; + synchronized (guilds) { + for (int i = 0; i < guilds.size(); i++) { + if (guilds.get(i) == gid) { + return i; + } } + return -1; } - return -1; } public void setRankTitle(String[] ranks) { @@ -354,13 +357,15 @@ public class MapleAlliance { } public List getGuilds() { - List guilds_ = new LinkedList<>(); - for (int guild : guilds) { - if (guild != -1) { - guilds_.add(guild); + synchronized(guilds) { + List guilds_ = new LinkedList<>(); + for (int guild : guilds) { + if (guild != -1) { + guilds_.add(guild); + } } + return guilds_; } - return guilds_; } public String getAllianceNotice() { @@ -396,14 +401,16 @@ public class MapleAlliance { } public MapleGuildCharacter getLeader() { - for(Integer gId: guilds) { - MapleGuild guild = Server.getInstance().getGuild(gId); - MapleGuildCharacter mgc = guild.getMGC(guild.getLeaderId()); - - if(mgc.getAllianceRank() == 1) return mgc; + synchronized(guilds) { + for(Integer gId: guilds) { + MapleGuild guild = Server.getInstance().getGuild(gId); + MapleGuildCharacter mgc = guild.getMGC(guild.getLeaderId()); + + if(mgc.getAllianceRank() == 1) return mgc; + } + + return null; } - - return null; } public void dropMessage(String message) { @@ -411,9 +418,11 @@ public class MapleAlliance { } public void dropMessage(int type, String message) { - for(Integer gId: guilds) { - MapleGuild guild = Server.getInstance().getGuild(gId); - guild.dropMessage(type, message); + synchronized(guilds) { + for(Integer gId: guilds) { + MapleGuild guild = Server.getInstance().getGuild(gId); + guild.dropMessage(type, message); + } } } diff --git a/src/net/server/guild/MapleGuild.java b/src/net/server/guild/MapleGuild.java index cc729cb849..32b8bbd6f9 100644 --- a/src/net/server/guild/MapleGuild.java +++ b/src/net/server/guild/MapleGuild.java @@ -35,6 +35,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + import net.server.Server; import net.server.channel.Channel; import tools.DatabaseConnection; @@ -47,7 +50,10 @@ public class MapleGuild { private enum BCOp { NONE, DISBAND, EMBLEMCHANGE } + private final List members; + private final Lock membersLock = new ReentrantLock(true); + private String rankTitles[] = new String[5]; // 1 = master, 2 = jr, 5 = lowest member private String name, notice; private int id, gp, logo, logoColor, leader, capacity, logoBG, logoBGColor, signature, allianceId; @@ -122,7 +128,9 @@ public class MapleGuild { l.clear(); } } - synchronized (members) { + + membersLock.lock(); + try { for (MapleGuildCharacter mgc : members) { if (!mgc.isOnline()) { continue; @@ -131,7 +139,10 @@ public class MapleGuild { if (ch != null) ch.add(mgc.getId()); //Unable to connect to Channel... error was here } + } finally { + membersLock.unlock(); } + bDirty = false; } @@ -169,7 +180,13 @@ public class MapleGuild { ps.setInt(1, this.id); ps.execute(); ps.close(); - this.broadcast(MaplePacketCreator.guildDisband(this.id)); + + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.guildDisband(this.id)); + } finally { + membersLock.unlock(); + } } con.close(); @@ -238,7 +255,12 @@ public class MapleGuild { } public java.util.Collection getMembers() { - return java.util.Collections.unmodifiableCollection(members); + membersLock.lock(); + try { + return java.util.Collections.unmodifiableCollection(members); + } finally { + membersLock.unlock(); + } } public int getCapacity() { @@ -282,13 +304,18 @@ public class MapleGuild { } public void guildMessage(final byte[] serverNotice) { - for (MapleGuildCharacter mgc : members) { - for (Channel cs : Server.getInstance().getChannelsFromWorld(world)) { - if (cs.getPlayerStorage().getCharacterById(mgc.getId()) != null) { - cs.getPlayerStorage().getCharacterById(mgc.getId()).getClient().announce(serverNotice); - break; + membersLock.lock(); + try { + for (MapleGuildCharacter mgc : members) { + for (Channel cs : Server.getInstance().getChannelsFromWorld(world)) { + if (cs.getPlayerStorage().getCharacterById(mgc.getId()) != null) { + cs.getPlayerStorage().getCharacterById(mgc.getId()).getClient().announce(serverNotice); + break; + } } } + } finally { + membersLock.unlock(); } } @@ -297,9 +324,15 @@ public class MapleGuild { } public void dropMessage(int type, String message) { - for (MapleGuildCharacter mgc : members) { - if(mgc.getCharacter() != null) - mgc.getCharacter().dropMessage(type, message); + membersLock.lock(); + try { + for (MapleGuildCharacter mgc : members) { + if(mgc.getCharacter() != null) { + mgc.getCharacter().dropMessage(type, message); + } + } + } finally { + membersLock.unlock(); } } @@ -308,25 +341,35 @@ public class MapleGuild { } public final void setOnline(int cid, boolean online, int channel) { - boolean bBroadcast = true; - for (MapleGuildCharacter mgc : members) { - if (mgc.getId() == cid) { - if (mgc.isOnline() && online) { - bBroadcast = false; + membersLock.lock(); + try { + boolean bBroadcast = true; + for (MapleGuildCharacter mgc : members) { + if (mgc.getId() == cid) { + if (mgc.isOnline() && online) { + bBroadcast = false; + } + mgc.setOnline(online); + mgc.setChannel(channel); + break; } - mgc.setOnline(online); - mgc.setChannel(channel); - break; } + if (bBroadcast) { + this.broadcast(MaplePacketCreator.guildMemberOnline(id, cid, online), cid); + } + bDirty = true; + } finally { + membersLock.unlock(); } - if (bBroadcast) { - this.broadcast(MaplePacketCreator.guildMemberOnline(id, cid, online), cid); - } - bDirty = true; } public void guildChat(String name, int cid, String message) { - this.broadcast(MaplePacketCreator.multiChat(name, message, 2), cid); + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.multiChat(name, message, 2), cid); + } finally { + membersLock.unlock(); + } } public String getRankTitle(int rank) { @@ -377,7 +420,8 @@ public class MapleGuild { } public int addGuildMember(MapleGuildCharacter mgc, MapleCharacter chr) { - synchronized (members) { + membersLock.lock(); + try { if (members.size() >= capacity) { return 0; } @@ -389,21 +433,28 @@ public class MapleGuild { break; } } + + this.broadcast(MaplePacketCreator.newGuildMember(mgc)); + return 1; + } finally { + membersLock.unlock(); } - this.broadcast(MaplePacketCreator.newGuildMember(mgc)); - return 1; } public void leaveGuild(MapleGuildCharacter mgc) { - this.broadcast(MaplePacketCreator.memberLeft(mgc, false)); - synchronized (members) { + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.memberLeft(mgc, false)); members.remove(mgc); bDirty = true; + } finally { + membersLock.unlock(); } } public void expelMember(MapleGuildCharacter initiator, String name, int cid) { - synchronized (members) { + membersLock.lock(); + try { java.util.Iterator itr = members.iterator(); MapleGuildCharacter mgc; while (itr.hasNext()) { @@ -441,15 +492,22 @@ public class MapleGuild { } } System.out.println("Unable to find member with name " + name + " and id " + cid); + } finally { + membersLock.unlock(); } } public void changeRank(int cid, int newRank) { - for (MapleGuildCharacter mgc : members) { - if (cid == mgc.getId()) { - changeRank(mgc, newRank); - return; + membersLock.lock(); + try { + for (MapleGuildCharacter mgc : members) { + if (cid == mgc.getId()) { + changeRank(mgc, newRank); + return; + } } + } finally { + membersLock.unlock(); } } @@ -467,24 +525,39 @@ public class MapleGuild { return; } - this.broadcast(MaplePacketCreator.changeRank(mgc)); - return; + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.changeRank(mgc)); + } finally { + membersLock.unlock(); + } } public void setGuildNotice(String notice) { this.notice = notice; writeToDB(false); - this.broadcast(MaplePacketCreator.guildNotice(this.id, notice)); + + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.guildNotice(this.id, notice)); + } finally { + membersLock.unlock(); + } } public void memberLevelJobUpdate(MapleGuildCharacter mgc) { - for (MapleGuildCharacter member : members) { - if (mgc.equals(member)) { - member.setJobId(mgc.getJobId()); - member.setLevel(mgc.getLevel()); - this.broadcast(MaplePacketCreator.guildMemberLevelJobUpdate(mgc)); - break; + membersLock.lock(); + try { + for (MapleGuildCharacter member : members) { + if (mgc.equals(member)) { + member.setJobId(mgc.getJobId()); + member.setLevel(mgc.getLevel()); + this.broadcast(MaplePacketCreator.guildMemberLevelJobUpdate(mgc)); + break; + } } + } finally { + membersLock.unlock(); } } @@ -507,7 +580,14 @@ public class MapleGuild { public void changeRankTitle(String[] ranks) { System.arraycopy(ranks, 0, rankTitles, 0, 5); - this.broadcast(MaplePacketCreator.rankTitleChange(this.id, ranks)); + + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.rankTitleChange(this.id, ranks)); + } finally { + membersLock.unlock(); + } + this.writeToDB(false); } @@ -519,8 +599,13 @@ public class MapleGuild { else MapleAlliance.disbandAlliance(allianceId); } - this.writeToDB(true); - this.broadcast(null, -1, BCOp.DISBAND); + membersLock.lock(); + try { + this.writeToDB(true); + this.broadcast(null, -1, BCOp.DISBAND); + } finally { + membersLock.unlock(); + } } public void setGuildEmblem(short bg, byte bgcolor, short logo, byte logocolor) { @@ -529,16 +614,27 @@ public class MapleGuild { this.logo = logo; this.logoColor = logocolor; this.writeToDB(false); - this.broadcast(null, -1, BCOp.EMBLEMCHANGE); + + membersLock.lock(); + try { + this.broadcast(null, -1, BCOp.EMBLEMCHANGE); + } finally { + membersLock.unlock(); + } } public MapleGuildCharacter getMGC(int cid) { - for (MapleGuildCharacter mgc : members) { - if (mgc.getId() == cid) { - return mgc; + membersLock.lock(); + try { + for (MapleGuildCharacter mgc : members) { + if (mgc.getId() == cid) { + return mgc; + } } + return null; + } finally { + membersLock.unlock(); } - return null; } public boolean increaseCapacity() { @@ -547,7 +643,14 @@ public class MapleGuild { } capacity += 5; this.writeToDB(false); - this.broadcast(MaplePacketCreator.guildCapacityChange(this.id, this.capacity)); + + membersLock.lock(); + try { + this.broadcast(MaplePacketCreator.guildCapacityChange(this.id, this.capacity)); + } finally { + membersLock.unlock(); + } + return true; } @@ -614,10 +717,15 @@ public class MapleGuild { public void resetAllianceGuildPlayersRank() { try { - for(MapleGuildCharacter mgc: members) { - if(mgc.isOnline()) { - mgc.setAllianceRank(5); + membersLock.lock(); + try { + for(MapleGuildCharacter mgc: members) { + if(mgc.isOnline()) { + mgc.setAllianceRank(5); + } } + } finally { + membersLock.unlock(); } Connection con = DatabaseConnection.getConnection(); @@ -633,7 +741,7 @@ public class MapleGuild { } } - public int getIncreaseGuildCost(int size) { + public static int getIncreaseGuildCost(int size) { return 500000 * (size - 6) / 6; } } diff --git a/src/server/MaplePlayerShop.java b/src/server/MaplePlayerShop.java index 41ae11ae74..8a401f3184 100644 --- a/src/server/MaplePlayerShop.java +++ b/src/server/MaplePlayerShop.java @@ -80,8 +80,11 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } public boolean hasFreeSlot() { - synchronized (visitors) { + visitorLock.lock(); + try { return visitors[0] == null || visitors[1] == null || visitors[2] == null; + } finally { + visitorLock.unlock(); } } @@ -90,7 +93,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } private void addVisitor(MapleCharacter visitor) { - synchronized (visitors) { + visitorLock.lock(); + try { for (int i = 0; i < 3; i++) { if (visitors[i] == null) { visitors[i] = visitor; @@ -101,6 +105,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { break; } } + } finally { + visitorLock.unlock(); } } @@ -109,13 +115,19 @@ public class MaplePlayerShop extends AbstractMapleMapObject { owner.getMap().removeMapObject(this); owner.setPlayerShop(null); } - for (int i = 0; i < 3; i++) { - if (visitors[i] != null && visitors[i].getId() == visitor.getId()) { - visitors[i] = null; - visitor.setSlot(-1); - this.broadcast(MaplePacketCreator.getPlayerShopRemoveVisitor(i + 1)); - return; + + visitorLock.lock(); + try { + for (int i = 0; i < 3; i++) { + if (visitors[i] != null && visitors[i].getId() == visitor.getId()) { + visitors[i] = null; + visitor.setSlot(-1); + this.broadcast(MaplePacketCreator.getPlayerShopRemoveVisitor(i + 1)); + return; + } } + } finally { + visitorLock.unlock(); } } @@ -124,7 +136,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { owner.getMap().removeMapObject(this); owner.setPlayerShop(null); } else { - synchronized (visitors) { + visitorLock.lock(); + try { for (int i = 0; i < 3; i++) { if (visitors[i] != null && visitors[i].getId() == visitor.getId()) { visitor.setSlot(-1); //absolutely cant remove player slot for late players without dc'ing them... heh @@ -143,6 +156,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { return; } } + } finally { + visitorLock.unlock(); } if(this.getOwner().getPlayerShop() != null) visitor.getMap().broadcastMessage(MaplePacketCreator.addCharBox(this.getOwner(), 4)); @@ -150,8 +165,11 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } public boolean isVisitor(MapleCharacter visitor) { - synchronized (visitors) { + visitorLock.lock(); + try { return visitors[0] == visitor || visitors[1] == visitor || visitors[2] == visitor; + } finally { + visitorLock.unlock(); } } @@ -187,7 +205,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject { synchronized (c.getPlayer()) { if (c.getPlayer().getMeso() >= (long) pItem.getPrice() * quantity) { if (MapleInventoryManipulator.addFromDrop(c, newItem, false)) { - c.getPlayer().gainMeso(-pItem.getPrice() * quantity, true); + c.getPlayer().gainMeso(-pItem.getPrice() * quantity, false); owner.gainMeso(pItem.getPrice() * quantity, true); pItem.setBundles((short) (pItem.getBundles() - quantity)); if (pItem.getBundles() < 1) { @@ -209,17 +227,21 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } public void broadcastToVisitors(final byte[] packet) { - synchronized (visitors) { + visitorLock.lock(); + try { for (int i = 0; i < 3; i++) { if (visitors[i] != null) { visitors[i].getClient().announce(packet); } } + } finally { + visitorLock.unlock(); } } public void broadcastRestoreToVisitors() { - synchronized (visitors) { + visitorLock.lock(); + try { for (int i = 0; i < 3; i++) { if (visitors[i] != null) { visitors[i].getClient().announce(MaplePacketCreator.getPlayerShopRemoveVisitor(i + 1)); @@ -233,12 +255,16 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } recoverChatLog(); + } finally { + visitorLock.unlock(); } } public void removeVisitors() { List visitorList = new ArrayList<>(3); - synchronized (visitors) { + + visitorLock.lock(); + try { try { for (int i = 0; i < 3; i++) { if (visitors[i] != null) { @@ -249,6 +275,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } catch (Exception e) { e.printStackTrace(); } + } finally { + visitorLock.unlock(); } for(MapleCharacter mc : visitorList) forceRemoveVisitor(mc); @@ -412,7 +440,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { return false; } - synchronized (visitors) { + visitorLock.lock(); + try { if (this.hasFreeSlot() && !this.isVisitor(chr)) { this.addVisitor(chr); chr.setPlayerShop(this); @@ -422,6 +451,8 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } return false; + } finally { + visitorLock.unlock(); } } diff --git a/tools/MapleArrowFetcher/build.xml b/tools/MapleArrowFetcher/build.xml new file mode 100644 index 0000000000..60e0649bb4 --- /dev/null +++ b/tools/MapleArrowFetcher/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project MapleArrowFetcher. + + + diff --git a/tools/MapleArrowFetcher/lib/arrow_drop_data.sql b/tools/MapleArrowFetcher/lib/arrow_drop_data.sql new file mode 100644 index 0000000000..ae250a17e3 --- /dev/null +++ b/tools/MapleArrowFetcher/lib/arrow_drop_data.sql @@ -0,0 +1,766 @@ + # SQL File autogenerated from the MapleArrowFetcher feature by Ronan Lana. + # Generated data takes into account mob stats such as level and boss for the raw arrow ranges. + # Only current arrows entries on the DB it was compiled are being updated here. + +UPDATE drop_data +SET minimum_quantity = CASE + WHEN dropperid = 100100 AND itemid = 2060000 THEN 1 + WHEN dropperid = 100100 AND itemid = 2061000 THEN 1 + WHEN dropperid = 100101 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100101 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100120 AND itemid = 2060000 THEN 1 + WHEN dropperid = 100120 AND itemid = 2061000 THEN 1 + WHEN dropperid = 100121 AND itemid = 2060000 THEN 5 + WHEN dropperid = 100123 AND itemid = 2061000 THEN 13 + WHEN dropperid = 100124 AND itemid = 2060000 THEN 17 + WHEN dropperid = 100124 AND itemid = 2061000 THEN 17 + WHEN dropperid = 120100 AND itemid = 2060000 THEN 3 + WHEN dropperid = 120100 AND itemid = 2061000 THEN 3 + WHEN dropperid = 130100 AND itemid = 2060000 THEN 7 + WHEN dropperid = 130100 AND itemid = 2061000 THEN 7 + WHEN dropperid = 130101 AND itemid = 2060000 THEN 7 + WHEN dropperid = 130101 AND itemid = 2061000 THEN 7 + WHEN dropperid = 210100 AND itemid = 2060000 THEN 11 + WHEN dropperid = 210100 AND itemid = 2061000 THEN 11 + WHEN dropperid = 1110100 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1110100 AND itemid = 2061000 THEN 29 + WHEN dropperid = 1110101 AND itemid = 2060000 THEN 19 + WHEN dropperid = 1110101 AND itemid = 2061000 THEN 19 + WHEN dropperid = 1110130 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1110130 AND itemid = 2061000 THEN 29 + WHEN dropperid = 1120100 AND itemid = 2060000 THEN 23 + WHEN dropperid = 1120100 AND itemid = 2061000 THEN 23 + WHEN dropperid = 1130100 AND itemid = 2060000 THEN 33 + WHEN dropperid = 1130100 AND itemid = 2061000 THEN 33 + WHEN dropperid = 1140100 AND itemid = 2060000 THEN 36 + WHEN dropperid = 1140100 AND itemid = 2061000 THEN 36 + WHEN dropperid = 1140130 AND itemid = 2060000 THEN 36 + WHEN dropperid = 1140130 AND itemid = 2061000 THEN 36 + WHEN dropperid = 1210100 AND itemid = 2060000 THEN 13 + WHEN dropperid = 1210100 AND itemid = 2061000 THEN 13 + WHEN dropperid = 1210101 AND itemid = 2060000 THEN 19 + WHEN dropperid = 1210101 AND itemid = 2061000 THEN 19 + WHEN dropperid = 1210102 AND itemid = 2060000 THEN 15 + WHEN dropperid = 1210102 AND itemid = 2061000 THEN 15 + WHEN dropperid = 1210103 AND itemid = 2060000 THEN 29 + WHEN dropperid = 1210103 AND itemid = 2061000 THEN 29 + WHEN dropperid = 2100100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2100100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 2100101 AND itemid = 2060000 THEN 40 + WHEN dropperid = 2100101 AND itemid = 2061000 THEN 40 + WHEN dropperid = 2100102 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2100102 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2100103 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2100103 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2100104 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2100104 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2100105 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2100105 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2100106 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2100106 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2100107 AND itemid = 2060000 THEN 52 + WHEN dropperid = 2100107 AND itemid = 2061000 THEN 52 + WHEN dropperid = 2100108 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2100108 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2110200 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2110200 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2110300 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2110300 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2110301 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2110301 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2130100 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2130100 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2220000 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2220000 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2220100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2220100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 2230100 AND itemid = 2060000 THEN 52 + WHEN dropperid = 2230100 AND itemid = 2061000 THEN 52 + WHEN dropperid = 2230101 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230101 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230102 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2230102 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2230103 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230103 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230104 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2230104 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2230105 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230105 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230106 AND itemid = 2060000 THEN 48 + WHEN dropperid = 2230106 AND itemid = 2061000 THEN 48 + WHEN dropperid = 2230107 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230107 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230108 AND itemid = 2060000 THEN 42 + WHEN dropperid = 2230108 AND itemid = 2061000 THEN 42 + WHEN dropperid = 2230109 AND itemid = 2060000 THEN 54 + WHEN dropperid = 2230109 AND itemid = 2061000 THEN 54 + WHEN dropperid = 2230110 AND itemid = 2060000 THEN 44 + WHEN dropperid = 2230110 AND itemid = 2061000 THEN 44 + WHEN dropperid = 2230111 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230111 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230131 AND itemid = 2060000 THEN 46 + WHEN dropperid = 2230131 AND itemid = 2061000 THEN 46 + WHEN dropperid = 2230200 AND itemid = 2060000 THEN 56 + WHEN dropperid = 2230200 AND itemid = 2061000 THEN 56 + WHEN dropperid = 2300100 AND itemid = 2060000 THEN 38 + WHEN dropperid = 2300100 AND itemid = 2061000 THEN 38 + WHEN dropperid = 3000000 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000000 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3000005 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000005 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3000006 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3000006 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3100101 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3100101 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3100102 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3100102 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3110101 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110101 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110102 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110102 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110300 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110300 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110301 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3110301 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3110302 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3110302 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3110303 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3110303 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3210100 AND itemid = 2060005 THEN 10 + WHEN dropperid = 3210203 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210203 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210204 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210204 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210205 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210205 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210206 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210206 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210207 AND itemid = 2060000 THEN 66 + WHEN dropperid = 3210207 AND itemid = 2060005 THEN 11 + WHEN dropperid = 3210207 AND itemid = 2061000 THEN 66 + WHEN dropperid = 3210208 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210208 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210450 AND itemid = 2060000 THEN 70 + WHEN dropperid = 3210450 AND itemid = 2061000 THEN 70 + WHEN dropperid = 3210800 AND itemid = 2060005 THEN 12 + WHEN dropperid = 3220000 AND itemid = 2060000 THEN 95 + WHEN dropperid = 3220000 AND itemid = 2061000 THEN 95 + WHEN dropperid = 3230100 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230100 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230103 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230103 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3230200 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230200 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230302 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3230302 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3230303 AND itemid = 2060000 THEN 72 + WHEN dropperid = 3230303 AND itemid = 2061000 THEN 72 + WHEN dropperid = 3230304 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230304 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3230305 AND itemid = 2060000 THEN 75 + WHEN dropperid = 3230305 AND itemid = 2061000 THEN 75 + WHEN dropperid = 3230306 AND itemid = 2060000 THEN 72 + WHEN dropperid = 3230306 AND itemid = 2061000 THEN 72 + WHEN dropperid = 3230307 AND itemid = 2060000 THEN 60 + WHEN dropperid = 3230307 AND itemid = 2061000 THEN 60 + WHEN dropperid = 3230308 AND itemid = 2060000 THEN 75 + WHEN dropperid = 3230308 AND itemid = 2061000 THEN 75 + WHEN dropperid = 3230400 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3230400 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3230405 AND itemid = 2060000 THEN 73 + WHEN dropperid = 3230405 AND itemid = 2061000 THEN 73 + WHEN dropperid = 3300000 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3300000 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3300001 AND itemid = 2060000 THEN 58 + WHEN dropperid = 3300001 AND itemid = 2061000 THEN 58 + WHEN dropperid = 3300002 AND itemid = 2060000 THEN 60 + WHEN dropperid = 3300002 AND itemid = 2061000 THEN 60 + WHEN dropperid = 3300003 AND itemid = 2060000 THEN 62 + WHEN dropperid = 3300003 AND itemid = 2061000 THEN 62 + WHEN dropperid = 3300004 AND itemid = 2060000 THEN 64 + WHEN dropperid = 3300004 AND itemid = 2061000 THEN 64 + WHEN dropperid = 3300006 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3300006 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3300007 AND itemid = 2060000 THEN 68 + WHEN dropperid = 3300007 AND itemid = 2061000 THEN 68 + WHEN dropperid = 3300008 AND itemid = 2060000 THEN 103 + WHEN dropperid = 3300008 AND itemid = 2061000 THEN 103 + WHEN dropperid = 4110300 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4110300 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4110301 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4110301 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4130103 AND itemid = 2060000 THEN 128 + WHEN dropperid = 4130103 AND itemid = 2061000 THEN 128 + WHEN dropperid = 4230103 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230103 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230106 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230106 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230108 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230108 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230109 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230109 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230110 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230110 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230111 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230111 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230112 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230112 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230113 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230113 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230114 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230114 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230115 AND itemid = 2060000 THEN 89 + WHEN dropperid = 4230115 AND itemid = 2061000 THEN 89 + WHEN dropperid = 4230116 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230116 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230117 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230117 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230118 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230118 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230119 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230119 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230120 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230120 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230121 AND itemid = 2060000 THEN 89 + WHEN dropperid = 4230121 AND itemid = 2061000 THEN 89 + WHEN dropperid = 4230123 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230123 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230124 AND itemid = 2060000 THEN 81 + WHEN dropperid = 4230124 AND itemid = 2061000 THEN 81 + WHEN dropperid = 4230125 AND itemid = 2060000 THEN 85 + WHEN dropperid = 4230125 AND itemid = 2061000 THEN 85 + WHEN dropperid = 4230126 AND itemid = 2060000 THEN 91 + WHEN dropperid = 4230126 AND itemid = 2061000 THEN 91 + WHEN dropperid = 4230201 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230201 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230300 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230300 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230400 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230400 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230500 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230500 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4230501 AND itemid = 2060000 THEN 79 + WHEN dropperid = 4230501 AND itemid = 2061000 THEN 79 + WHEN dropperid = 4230502 AND itemid = 2060000 THEN 83 + WHEN dropperid = 4230502 AND itemid = 2061000 THEN 83 + WHEN dropperid = 4230503 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230503 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230504 AND itemid = 2060000 THEN 87 + WHEN dropperid = 4230504 AND itemid = 2061000 THEN 87 + WHEN dropperid = 4230600 AND itemid = 2060000 THEN 77 + WHEN dropperid = 4230600 AND itemid = 2061000 THEN 77 + WHEN dropperid = 4240000 AND itemid = 2060000 THEN 95 + WHEN dropperid = 4240000 AND itemid = 2061000 THEN 95 + WHEN dropperid = 5120100 AND itemid = 2060000 THEN 147 + WHEN dropperid = 5120100 AND itemid = 2061000 THEN 147 + WHEN dropperid = 5130104 AND itemid = 2060000 THEN 107 + WHEN dropperid = 5130104 AND itemid = 2061000 THEN 107 + WHEN dropperid = 5140000 AND itemid = 2060000 THEN 112 + WHEN dropperid = 5140000 AND itemid = 2061000 THEN 112 + WHEN dropperid = 5150000 AND itemid = 2060000 THEN 114 + WHEN dropperid = 5150000 AND itemid = 2061000 THEN 114 + WHEN dropperid = 5200000 AND itemid = 2060001 THEN 22 + WHEN dropperid = 5200000 AND itemid = 2061001 THEN 22 + WHEN dropperid = 5200001 AND itemid = 2060001 THEN 29 + WHEN dropperid = 5200001 AND itemid = 2061001 THEN 29 + WHEN dropperid = 5200002 AND itemid = 2060001 THEN 29 + WHEN dropperid = 5200002 AND itemid = 2061001 THEN 29 + WHEN dropperid = 5220000 AND itemid = 2060000 THEN 149 + WHEN dropperid = 5220000 AND itemid = 2061000 THEN 149 + WHEN dropperid = 5220002 AND itemid = 2060000 THEN 136 + WHEN dropperid = 5220002 AND itemid = 2061000 THEN 136 + WHEN dropperid = 5220003 AND itemid = 2060000 THEN 160 + WHEN dropperid = 5220003 AND itemid = 2061000 THEN 160 + WHEN dropperid = 5400000 AND itemid = 2060001 THEN 34 + WHEN dropperid = 5400000 AND itemid = 2061001 THEN 34 + WHEN dropperid = 6220000 AND itemid = 2060000 THEN 177 + WHEN dropperid = 6220000 AND itemid = 2061000 THEN 177 + WHEN dropperid = 7120103 AND itemid = 2060003 THEN 34 + WHEN dropperid = 7220000 AND itemid = 2060001 THEN 96 + WHEN dropperid = 7220000 AND itemid = 2061001 THEN 96 + WHEN dropperid = 7220001 AND itemid = 2060001 THEN 95 + WHEN dropperid = 7220001 AND itemid = 2061001 THEN 95 + WHEN dropperid = 7220002 AND itemid = 2060001 THEN 104 + WHEN dropperid = 7220002 AND itemid = 2061001 THEN 104 + WHEN dropperid = 8220000 AND itemid = 2060001 THEN 113 + WHEN dropperid = 8220000 AND itemid = 2061001 THEN 113 + WHEN dropperid = 8220001 AND itemid = 2060001 THEN 122 + WHEN dropperid = 8220001 AND itemid = 2061001 THEN 122 + WHEN dropperid = 9300011 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9300011 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9300060 AND itemid = 2060000 THEN 81 + WHEN dropperid = 9300060 AND itemid = 2061000 THEN 81 + WHEN dropperid = 9300131 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9300131 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9300132 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9300132 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9300133 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9300160 AND itemid = 2060000 THEN 122 + WHEN dropperid = 9300160 AND itemid = 2061000 THEN 122 + WHEN dropperid = 9300161 AND itemid = 2060000 THEN 122 + WHEN dropperid = 9300161 AND itemid = 2061000 THEN 122 + WHEN dropperid = 9300274 AND itemid = 2060000 THEN 15 + WHEN dropperid = 9300274 AND itemid = 2061000 THEN 15 + WHEN dropperid = 9300332 AND itemid = 2060000 THEN 77 + WHEN dropperid = 9300334 AND itemid = 2060000 THEN 95 + WHEN dropperid = 9300341 AND itemid = 2060000 THEN 11 + WHEN dropperid = 9300341 AND itemid = 2061000 THEN 11 + WHEN dropperid = 9300342 AND itemid = 2060000 THEN 15 + WHEN dropperid = 9300342 AND itemid = 2061000 THEN 15 + WHEN dropperid = 9300343 AND itemid = 2060000 THEN 13 + WHEN dropperid = 9300343 AND itemid = 2061000 THEN 13 + WHEN dropperid = 9303005 AND itemid = 2060001 THEN 25 + WHEN dropperid = 9303005 AND itemid = 2061001 THEN 25 + WHEN dropperid = 9303008 AND itemid = 2060001 THEN 25 + WHEN dropperid = 9303008 AND itemid = 2061001 THEN 25 + WHEN dropperid = 9303009 AND itemid = 2060001 THEN 49 + WHEN dropperid = 9303009 AND itemid = 2061001 THEN 49 + WHEN dropperid = 9400000 AND itemid = 2060001 THEN 24 + WHEN dropperid = 9400009 AND itemid = 2060001 THEN 194 + WHEN dropperid = 9400011 AND itemid = 2060002 THEN 25 + WHEN dropperid = 9400100 AND itemid = 2060003 THEN 21 + WHEN dropperid = 9400101 AND itemid = 2061003 THEN 22 + WHEN dropperid = 9400204 AND itemid = 2060003 THEN 26 + WHEN dropperid = 9400239 AND itemid = 2060000 THEN 46 + WHEN dropperid = 9400239 AND itemid = 2061000 THEN 46 + WHEN dropperid = 9400244 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9400244 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9400248 AND itemid = 2060000 THEN 46 + WHEN dropperid = 9400248 AND itemid = 2061000 THEN 46 + WHEN dropperid = 9400540 AND itemid = 2060004 THEN 9 + WHEN dropperid = 9400540 AND itemid = 2061004 THEN 9 + WHEN dropperid = 9400541 AND itemid = 2060004 THEN 9 + WHEN dropperid = 9400541 AND itemid = 2061004 THEN 9 + WHEN dropperid = 9400542 AND itemid = 2060004 THEN 14 + WHEN dropperid = 9400542 AND itemid = 2061004 THEN 14 + WHEN dropperid = 9400543 AND itemid = 2060004 THEN 15 + WHEN dropperid = 9400543 AND itemid = 2061004 THEN 15 + WHEN dropperid = 9400547 AND itemid = 2060000 THEN 52 + WHEN dropperid = 9400547 AND itemid = 2061000 THEN 52 + WHEN dropperid = 9400548 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9400548 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9400550 AND itemid = 2060000 THEN 52 + WHEN dropperid = 9400550 AND itemid = 2061000 THEN 52 + WHEN dropperid = 9400558 AND itemid = 2060000 THEN 58 + WHEN dropperid = 9400558 AND itemid = 2061000 THEN 58 + WHEN dropperid = 9400563 AND itemid = 2060000 THEN 77 + WHEN dropperid = 9400563 AND itemid = 2061000 THEN 77 + WHEN dropperid = 9400638 AND itemid = 2060000 THEN 38 + WHEN dropperid = 9400638 AND itemid = 2061000 THEN 38 + WHEN dropperid = 9420500 AND itemid = 2060000 THEN 54 + WHEN dropperid = 9420500 AND itemid = 2061000 THEN 54 + WHEN dropperid = 9420502 AND itemid = 2060000 THEN 35 + WHEN dropperid = 9420502 AND itemid = 2061000 THEN 35 + WHEN dropperid = 9420506 AND itemid = 2060000 THEN 44 + WHEN dropperid = 9420506 AND itemid = 2061000 THEN 44 + WHEN dropperid = 9420508 AND itemid = 2060000 THEN 83 + WHEN dropperid = 9420508 AND itemid = 2061000 THEN 83 + WHEN dropperid = 9420527 AND itemid = 2060001 THEN 43 + WHEN dropperid = 9420527 AND itemid = 2061001 THEN 43 + WHEN dropperid = 9420531 AND itemid = 2060001 THEN 57 + WHEN dropperid = 9420531 AND itemid = 2061001 THEN 57 + WHEN dropperid = 9500112 AND itemid = 2060001 THEN 34 + WHEN dropperid = 9500112 AND itemid = 2061001 THEN 34 + WHEN dropperid = 9500119 AND itemid = 2060000 THEN 75 + WHEN dropperid = 9500119 AND itemid = 2061000 THEN 75 + WHEN dropperid = 9500120 AND itemid = 2060000 THEN 87 + WHEN dropperid = 9500120 AND itemid = 2061000 THEN 87 + WHEN dropperid = 9500122 AND itemid = 2060000 THEN 95 + WHEN dropperid = 9500123 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9500123 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9500308 AND itemid = 2060000 THEN 136 + WHEN dropperid = 9500308 AND itemid = 2061000 THEN 136 + WHEN dropperid = 9500310 AND itemid = 2060000 THEN 160 + WHEN dropperid = 9500310 AND itemid = 2061000 THEN 160 + WHEN dropperid = 9500312 AND itemid = 2060001 THEN 95 + WHEN dropperid = 9500312 AND itemid = 2061001 THEN 95 + WHEN dropperid = 9500313 AND itemid = 2060001 THEN 96 + WHEN dropperid = 9500313 AND itemid = 2061001 THEN 96 + WHEN dropperid = 9500314 AND itemid = 2060001 THEN 104 + WHEN dropperid = 9500314 AND itemid = 2061001 THEN 104 + WHEN dropperid = 9500321 AND itemid = 2060001 THEN 9 + WHEN dropperid = 9500321 AND itemid = 2061001 THEN 9 + WHEN dropperid = 9500366 AND itemid = 2060000 THEN 29 + WHEN dropperid = 9500369 AND itemid = 2060000 THEN 29 + ELSE minimum_quantity END, + maximum_quantity = CASE + WHEN dropperid = 100100 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100100 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100101 AND itemid = 2060000 THEN 9 + WHEN dropperid = 100101 AND itemid = 2061000 THEN 9 + WHEN dropperid = 100120 AND itemid = 2060000 THEN 3 + WHEN dropperid = 100120 AND itemid = 2061000 THEN 3 + WHEN dropperid = 100121 AND itemid = 2060000 THEN 15 + WHEN dropperid = 100123 AND itemid = 2061000 THEN 39 + WHEN dropperid = 100124 AND itemid = 2060000 THEN 51 + WHEN dropperid = 100124 AND itemid = 2061000 THEN 51 + WHEN dropperid = 120100 AND itemid = 2060000 THEN 9 + WHEN dropperid = 120100 AND itemid = 2061000 THEN 9 + WHEN dropperid = 130100 AND itemid = 2060000 THEN 21 + WHEN dropperid = 130100 AND itemid = 2061000 THEN 21 + WHEN dropperid = 130101 AND itemid = 2060000 THEN 21 + WHEN dropperid = 130101 AND itemid = 2061000 THEN 21 + WHEN dropperid = 210100 AND itemid = 2060000 THEN 33 + WHEN dropperid = 210100 AND itemid = 2061000 THEN 33 + WHEN dropperid = 1110100 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1110100 AND itemid = 2061000 THEN 87 + WHEN dropperid = 1110101 AND itemid = 2060000 THEN 57 + WHEN dropperid = 1110101 AND itemid = 2061000 THEN 57 + WHEN dropperid = 1110130 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1110130 AND itemid = 2061000 THEN 87 + WHEN dropperid = 1120100 AND itemid = 2060000 THEN 69 + WHEN dropperid = 1120100 AND itemid = 2061000 THEN 69 + WHEN dropperid = 1130100 AND itemid = 2060000 THEN 99 + WHEN dropperid = 1130100 AND itemid = 2061000 THEN 99 + WHEN dropperid = 1140100 AND itemid = 2060000 THEN 108 + WHEN dropperid = 1140100 AND itemid = 2061000 THEN 108 + WHEN dropperid = 1140130 AND itemid = 2060000 THEN 108 + WHEN dropperid = 1140130 AND itemid = 2061000 THEN 108 + WHEN dropperid = 1210100 AND itemid = 2060000 THEN 39 + WHEN dropperid = 1210100 AND itemid = 2061000 THEN 39 + WHEN dropperid = 1210101 AND itemid = 2060000 THEN 57 + WHEN dropperid = 1210101 AND itemid = 2061000 THEN 57 + WHEN dropperid = 1210102 AND itemid = 2060000 THEN 45 + WHEN dropperid = 1210102 AND itemid = 2061000 THEN 45 + WHEN dropperid = 1210103 AND itemid = 2060000 THEN 87 + WHEN dropperid = 1210103 AND itemid = 2061000 THEN 87 + WHEN dropperid = 2100100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2100100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 2100101 AND itemid = 2060000 THEN 120 + WHEN dropperid = 2100101 AND itemid = 2061000 THEN 120 + WHEN dropperid = 2100102 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2100102 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2100103 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2100103 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2100104 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2100104 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2100105 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2100105 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2100106 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2100106 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2100107 AND itemid = 2060000 THEN 156 + WHEN dropperid = 2100107 AND itemid = 2061000 THEN 156 + WHEN dropperid = 2100108 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2100108 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2110200 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2110200 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2110300 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2110300 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2110301 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2110301 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2130100 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2130100 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2220000 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2220000 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2220100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2220100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 2230100 AND itemid = 2060000 THEN 156 + WHEN dropperid = 2230100 AND itemid = 2061000 THEN 156 + WHEN dropperid = 2230101 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230101 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230102 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2230102 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2230103 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230103 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230104 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2230104 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2230105 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230105 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230106 AND itemid = 2060000 THEN 144 + WHEN dropperid = 2230106 AND itemid = 2061000 THEN 144 + WHEN dropperid = 2230107 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230107 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230108 AND itemid = 2060000 THEN 126 + WHEN dropperid = 2230108 AND itemid = 2061000 THEN 126 + WHEN dropperid = 2230109 AND itemid = 2060000 THEN 162 + WHEN dropperid = 2230109 AND itemid = 2061000 THEN 162 + WHEN dropperid = 2230110 AND itemid = 2060000 THEN 132 + WHEN dropperid = 2230110 AND itemid = 2061000 THEN 132 + WHEN dropperid = 2230111 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230111 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230131 AND itemid = 2060000 THEN 138 + WHEN dropperid = 2230131 AND itemid = 2061000 THEN 138 + WHEN dropperid = 2230200 AND itemid = 2060000 THEN 168 + WHEN dropperid = 2230200 AND itemid = 2061000 THEN 168 + WHEN dropperid = 2300100 AND itemid = 2060000 THEN 114 + WHEN dropperid = 2300100 AND itemid = 2061000 THEN 114 + WHEN dropperid = 3000000 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000000 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3000005 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000005 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3000006 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3000006 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3100101 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3100101 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3100102 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3100102 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3110101 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110101 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110102 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110102 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110300 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110300 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110301 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3110301 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3110302 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3110302 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3110303 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3110303 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3210100 AND itemid = 2060005 THEN 31 + WHEN dropperid = 3210203 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210203 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210204 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210204 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210205 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210205 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210206 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210206 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210207 AND itemid = 2060000 THEN 198 + WHEN dropperid = 3210207 AND itemid = 2060005 THEN 33 + WHEN dropperid = 3210207 AND itemid = 2061000 THEN 198 + WHEN dropperid = 3210208 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210208 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210450 AND itemid = 2060000 THEN 210 + WHEN dropperid = 3210450 AND itemid = 2061000 THEN 210 + WHEN dropperid = 3210800 AND itemid = 2060005 THEN 36 + WHEN dropperid = 3220000 AND itemid = 2060000 THEN 285 + WHEN dropperid = 3220000 AND itemid = 2061000 THEN 285 + WHEN dropperid = 3230100 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230100 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230103 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230103 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3230200 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230200 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230302 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3230302 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3230303 AND itemid = 2060000 THEN 216 + WHEN dropperid = 3230303 AND itemid = 2061000 THEN 216 + WHEN dropperid = 3230304 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230304 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3230305 AND itemid = 2060000 THEN 225 + WHEN dropperid = 3230305 AND itemid = 2061000 THEN 225 + WHEN dropperid = 3230306 AND itemid = 2060000 THEN 216 + WHEN dropperid = 3230306 AND itemid = 2061000 THEN 216 + WHEN dropperid = 3230307 AND itemid = 2060000 THEN 180 + WHEN dropperid = 3230307 AND itemid = 2061000 THEN 180 + WHEN dropperid = 3230308 AND itemid = 2060000 THEN 225 + WHEN dropperid = 3230308 AND itemid = 2061000 THEN 225 + WHEN dropperid = 3230400 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3230400 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3230405 AND itemid = 2060000 THEN 219 + WHEN dropperid = 3230405 AND itemid = 2061000 THEN 219 + WHEN dropperid = 3300000 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3300000 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3300001 AND itemid = 2060000 THEN 174 + WHEN dropperid = 3300001 AND itemid = 2061000 THEN 174 + WHEN dropperid = 3300002 AND itemid = 2060000 THEN 180 + WHEN dropperid = 3300002 AND itemid = 2061000 THEN 180 + WHEN dropperid = 3300003 AND itemid = 2060000 THEN 186 + WHEN dropperid = 3300003 AND itemid = 2061000 THEN 186 + WHEN dropperid = 3300004 AND itemid = 2060000 THEN 192 + WHEN dropperid = 3300004 AND itemid = 2061000 THEN 192 + WHEN dropperid = 3300006 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3300006 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3300007 AND itemid = 2060000 THEN 204 + WHEN dropperid = 3300007 AND itemid = 2061000 THEN 204 + WHEN dropperid = 3300008 AND itemid = 2060000 THEN 309 + WHEN dropperid = 3300008 AND itemid = 2061000 THEN 309 + WHEN dropperid = 4110300 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4110300 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4110301 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4110301 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4130103 AND itemid = 2060000 THEN 384 + WHEN dropperid = 4130103 AND itemid = 2061000 THEN 384 + WHEN dropperid = 4230103 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230103 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230106 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230106 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230108 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230108 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230109 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230109 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230110 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230110 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230111 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230111 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230112 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230112 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230113 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230113 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230114 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230114 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230115 AND itemid = 2060000 THEN 267 + WHEN dropperid = 4230115 AND itemid = 2061000 THEN 267 + WHEN dropperid = 4230116 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230116 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230117 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230117 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230118 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230118 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230119 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230119 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230120 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230120 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230121 AND itemid = 2060000 THEN 267 + WHEN dropperid = 4230121 AND itemid = 2061000 THEN 267 + WHEN dropperid = 4230123 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230123 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230124 AND itemid = 2060000 THEN 243 + WHEN dropperid = 4230124 AND itemid = 2061000 THEN 243 + WHEN dropperid = 4230125 AND itemid = 2060000 THEN 255 + WHEN dropperid = 4230125 AND itemid = 2061000 THEN 255 + WHEN dropperid = 4230126 AND itemid = 2060000 THEN 273 + WHEN dropperid = 4230126 AND itemid = 2061000 THEN 273 + WHEN dropperid = 4230201 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230201 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230300 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230300 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230400 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230400 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230500 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230500 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4230501 AND itemid = 2060000 THEN 237 + WHEN dropperid = 4230501 AND itemid = 2061000 THEN 237 + WHEN dropperid = 4230502 AND itemid = 2060000 THEN 249 + WHEN dropperid = 4230502 AND itemid = 2061000 THEN 249 + WHEN dropperid = 4230503 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230503 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230504 AND itemid = 2060000 THEN 261 + WHEN dropperid = 4230504 AND itemid = 2061000 THEN 261 + WHEN dropperid = 4230600 AND itemid = 2060000 THEN 231 + WHEN dropperid = 4230600 AND itemid = 2061000 THEN 231 + WHEN dropperid = 4240000 AND itemid = 2060000 THEN 285 + WHEN dropperid = 4240000 AND itemid = 2061000 THEN 285 + WHEN dropperid = 5120100 AND itemid = 2060000 THEN 441 + WHEN dropperid = 5120100 AND itemid = 2061000 THEN 441 + WHEN dropperid = 5130104 AND itemid = 2060000 THEN 321 + WHEN dropperid = 5130104 AND itemid = 2061000 THEN 321 + WHEN dropperid = 5140000 AND itemid = 2060000 THEN 336 + WHEN dropperid = 5140000 AND itemid = 2061000 THEN 336 + WHEN dropperid = 5150000 AND itemid = 2060000 THEN 342 + WHEN dropperid = 5150000 AND itemid = 2061000 THEN 342 + WHEN dropperid = 5200000 AND itemid = 2060001 THEN 66 + WHEN dropperid = 5200000 AND itemid = 2061001 THEN 66 + WHEN dropperid = 5200001 AND itemid = 2060001 THEN 87 + WHEN dropperid = 5200001 AND itemid = 2061001 THEN 87 + WHEN dropperid = 5200002 AND itemid = 2060001 THEN 87 + WHEN dropperid = 5200002 AND itemid = 2061001 THEN 87 + WHEN dropperid = 5220000 AND itemid = 2060000 THEN 447 + WHEN dropperid = 5220000 AND itemid = 2061000 THEN 447 + WHEN dropperid = 5220002 AND itemid = 2060000 THEN 408 + WHEN dropperid = 5220002 AND itemid = 2061000 THEN 408 + WHEN dropperid = 5220003 AND itemid = 2060000 THEN 480 + WHEN dropperid = 5220003 AND itemid = 2061000 THEN 480 + WHEN dropperid = 5400000 AND itemid = 2060001 THEN 102 + WHEN dropperid = 5400000 AND itemid = 2061001 THEN 102 + WHEN dropperid = 6220000 AND itemid = 2060000 THEN 531 + WHEN dropperid = 6220000 AND itemid = 2061000 THEN 531 + WHEN dropperid = 7120103 AND itemid = 2060003 THEN 102 + WHEN dropperid = 7220000 AND itemid = 2060001 THEN 289 + WHEN dropperid = 7220000 AND itemid = 2061001 THEN 289 + WHEN dropperid = 7220001 AND itemid = 2060001 THEN 285 + WHEN dropperid = 7220001 AND itemid = 2061001 THEN 285 + WHEN dropperid = 7220002 AND itemid = 2060001 THEN 313 + WHEN dropperid = 7220002 AND itemid = 2061001 THEN 313 + WHEN dropperid = 8220000 AND itemid = 2060001 THEN 339 + WHEN dropperid = 8220000 AND itemid = 2061001 THEN 339 + WHEN dropperid = 8220001 AND itemid = 2060001 THEN 367 + WHEN dropperid = 8220001 AND itemid = 2061001 THEN 367 + WHEN dropperid = 9300011 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9300011 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9300060 AND itemid = 2060000 THEN 243 + WHEN dropperid = 9300060 AND itemid = 2061000 THEN 243 + WHEN dropperid = 9300131 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9300131 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9300132 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9300132 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9300133 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9300160 AND itemid = 2060000 THEN 366 + WHEN dropperid = 9300160 AND itemid = 2061000 THEN 366 + WHEN dropperid = 9300161 AND itemid = 2060000 THEN 366 + WHEN dropperid = 9300161 AND itemid = 2061000 THEN 366 + WHEN dropperid = 9300274 AND itemid = 2060000 THEN 45 + WHEN dropperid = 9300274 AND itemid = 2061000 THEN 45 + WHEN dropperid = 9300332 AND itemid = 2060000 THEN 231 + WHEN dropperid = 9300334 AND itemid = 2060000 THEN 285 + WHEN dropperid = 9300341 AND itemid = 2060000 THEN 33 + WHEN dropperid = 9300341 AND itemid = 2061000 THEN 33 + WHEN dropperid = 9300342 AND itemid = 2060000 THEN 45 + WHEN dropperid = 9300342 AND itemid = 2061000 THEN 45 + WHEN dropperid = 9300343 AND itemid = 2060000 THEN 39 + WHEN dropperid = 9300343 AND itemid = 2061000 THEN 39 + WHEN dropperid = 9303005 AND itemid = 2060001 THEN 75 + WHEN dropperid = 9303005 AND itemid = 2061001 THEN 75 + WHEN dropperid = 9303008 AND itemid = 2060001 THEN 75 + WHEN dropperid = 9303008 AND itemid = 2061001 THEN 75 + WHEN dropperid = 9303009 AND itemid = 2060001 THEN 148 + WHEN dropperid = 9303009 AND itemid = 2061001 THEN 148 + WHEN dropperid = 9400000 AND itemid = 2060001 THEN 72 + WHEN dropperid = 9400009 AND itemid = 2060001 THEN 583 + WHEN dropperid = 9400011 AND itemid = 2060002 THEN 77 + WHEN dropperid = 9400100 AND itemid = 2060003 THEN 65 + WHEN dropperid = 9400101 AND itemid = 2061003 THEN 68 + WHEN dropperid = 9400204 AND itemid = 2060003 THEN 80 + WHEN dropperid = 9400239 AND itemid = 2060000 THEN 138 + WHEN dropperid = 9400239 AND itemid = 2061000 THEN 138 + WHEN dropperid = 9400244 AND itemid = 2060000 THEN 342 + WHEN dropperid = 9400244 AND itemid = 2061000 THEN 342 + WHEN dropperid = 9400248 AND itemid = 2060000 THEN 138 + WHEN dropperid = 9400248 AND itemid = 2061000 THEN 138 + WHEN dropperid = 9400540 AND itemid = 2060004 THEN 28 + WHEN dropperid = 9400540 AND itemid = 2061004 THEN 28 + WHEN dropperid = 9400541 AND itemid = 2060004 THEN 28 + WHEN dropperid = 9400541 AND itemid = 2061004 THEN 28 + WHEN dropperid = 9400542 AND itemid = 2060004 THEN 42 + WHEN dropperid = 9400542 AND itemid = 2061004 THEN 42 + WHEN dropperid = 9400543 AND itemid = 2060004 THEN 47 + WHEN dropperid = 9400543 AND itemid = 2061004 THEN 47 + WHEN dropperid = 9400547 AND itemid = 2060000 THEN 156 + WHEN dropperid = 9400547 AND itemid = 2061000 THEN 156 + WHEN dropperid = 9400548 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9400548 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9400550 AND itemid = 2060000 THEN 156 + WHEN dropperid = 9400550 AND itemid = 2061000 THEN 156 + WHEN dropperid = 9400558 AND itemid = 2060000 THEN 174 + WHEN dropperid = 9400558 AND itemid = 2061000 THEN 174 + WHEN dropperid = 9400563 AND itemid = 2060000 THEN 231 + WHEN dropperid = 9400563 AND itemid = 2061000 THEN 231 + WHEN dropperid = 9400638 AND itemid = 2060000 THEN 114 + WHEN dropperid = 9400638 AND itemid = 2061000 THEN 114 + WHEN dropperid = 9420500 AND itemid = 2060000 THEN 162 + WHEN dropperid = 9420500 AND itemid = 2061000 THEN 162 + WHEN dropperid = 9420502 AND itemid = 2060000 THEN 105 + WHEN dropperid = 9420502 AND itemid = 2061000 THEN 105 + WHEN dropperid = 9420506 AND itemid = 2060000 THEN 132 + WHEN dropperid = 9420506 AND itemid = 2061000 THEN 132 + WHEN dropperid = 9420508 AND itemid = 2060000 THEN 249 + WHEN dropperid = 9420508 AND itemid = 2061000 THEN 249 + WHEN dropperid = 9420527 AND itemid = 2060001 THEN 130 + WHEN dropperid = 9420527 AND itemid = 2061001 THEN 130 + WHEN dropperid = 9420531 AND itemid = 2060001 THEN 171 + WHEN dropperid = 9420531 AND itemid = 2061001 THEN 171 + WHEN dropperid = 9500112 AND itemid = 2060001 THEN 102 + WHEN dropperid = 9500112 AND itemid = 2061001 THEN 102 + WHEN dropperid = 9500119 AND itemid = 2060000 THEN 225 + WHEN dropperid = 9500119 AND itemid = 2061000 THEN 225 + WHEN dropperid = 9500120 AND itemid = 2060000 THEN 261 + WHEN dropperid = 9500120 AND itemid = 2061000 THEN 261 + WHEN dropperid = 9500122 AND itemid = 2060000 THEN 285 + WHEN dropperid = 9500123 AND itemid = 2060000 THEN 342 + WHEN dropperid = 9500123 AND itemid = 2061000 THEN 342 + WHEN dropperid = 9500308 AND itemid = 2060000 THEN 408 + WHEN dropperid = 9500308 AND itemid = 2061000 THEN 408 + WHEN dropperid = 9500310 AND itemid = 2060000 THEN 480 + WHEN dropperid = 9500310 AND itemid = 2061000 THEN 480 + WHEN dropperid = 9500312 AND itemid = 2060001 THEN 285 + WHEN dropperid = 9500312 AND itemid = 2061001 THEN 285 + WHEN dropperid = 9500313 AND itemid = 2060001 THEN 289 + WHEN dropperid = 9500313 AND itemid = 2061001 THEN 289 + WHEN dropperid = 9500314 AND itemid = 2060001 THEN 313 + WHEN dropperid = 9500314 AND itemid = 2061001 THEN 313 + WHEN dropperid = 9500321 AND itemid = 2060001 THEN 28 + WHEN dropperid = 9500321 AND itemid = 2061001 THEN 28 + WHEN dropperid = 9500366 AND itemid = 2060000 THEN 87 + WHEN dropperid = 9500369 AND itemid = 2060000 THEN 87 + ELSE maximum_quantity END +; diff --git a/tools/MapleArrowFetcher/lib/mysql-connector-java-bin.jar b/tools/MapleArrowFetcher/lib/mysql-connector-java-bin.jar new file mode 100644 index 0000000000..0539039f71 Binary files /dev/null and b/tools/MapleArrowFetcher/lib/mysql-connector-java-bin.jar differ diff --git a/tools/MapleArrowFetcher/manifest.mf b/tools/MapleArrowFetcher/manifest.mf new file mode 100644 index 0000000000..328e8e5bc3 --- /dev/null +++ b/tools/MapleArrowFetcher/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/tools/MapleArrowFetcher/src/life/Element.java b/tools/MapleArrowFetcher/src/life/Element.java new file mode 100644 index 0000000000..5520ba3501 --- /dev/null +++ b/tools/MapleArrowFetcher/src/life/Element.java @@ -0,0 +1,46 @@ +/* + 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 life; + +public enum Element { + NEUTRAL, FIRE, ICE, LIGHTING, POISON, HOLY, DARK; + + public static Element getFromChar(char c) { + switch (Character.toUpperCase(c)) { + case 'F': + return FIRE; + case 'I': + return ICE; + case 'L': + return LIGHTING; + case 'S': + return POISON; + case 'H': + return HOLY; + case 'D': + return DARK; + case 'P': + return NEUTRAL; + } + throw new IllegalArgumentException("unknown elemnt char " + c); + } +} diff --git a/tools/MapleArrowFetcher/src/life/ElementalEffectiveness.java b/tools/MapleArrowFetcher/src/life/ElementalEffectiveness.java new file mode 100644 index 0000000000..f8d23ef5c7 --- /dev/null +++ b/tools/MapleArrowFetcher/src/life/ElementalEffectiveness.java @@ -0,0 +1,41 @@ +/* + 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 life; + +public enum ElementalEffectiveness { + NORMAL, IMMUNE, STRONG, WEAK, NEUTRAL; + + public static ElementalEffectiveness getByNumber(int num) { + switch (num) { + case 1: + return IMMUNE; + case 2: + return STRONG; + case 3: + return WEAK; + case 4: + return NEUTRAL; + default: + throw new IllegalArgumentException("Unkown effectiveness: " + num); + } + } +} diff --git a/tools/MapleArrowFetcher/src/life/MapleLifeFactory.java b/tools/MapleArrowFetcher/src/life/MapleLifeFactory.java new file mode 100644 index 0000000000..23ccd67e43 --- /dev/null +++ b/tools/MapleArrowFetcher/src/life/MapleLifeFactory.java @@ -0,0 +1,240 @@ +/* +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 life; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import provider.MapleData; +import provider.MapleDataDirectoryEntry; +import provider.MapleDataFileEntry; +import provider.MapleDataProvider; +import provider.MapleDataProviderFactory; +import provider.MapleDataTool; +import provider.wz.MapleDataType; +import tools.Pair; + +public class MapleLifeFactory { + private static String wzPath = "../../wz"; + private static MapleDataProvider data = MapleDataProviderFactory.getDataProvider(new File(wzPath + "/Mob.wz")); + private final static MapleDataProvider stringDataWZ = MapleDataProviderFactory.getDataProvider(new File(wzPath + "/String.wz")); + private static MapleData mobStringData = stringDataWZ.getData("Mob.img"); + private static MapleData npcStringData = stringDataWZ.getData("Npc.img"); + private static Map monsterStats = new HashMap<>(); + + private static int getMonsterId(String fileName) { + return Integer.parseInt(fileName.substring(0, 7)); + } + + public static Map getAllMonsterStats() { + MapleDataDirectoryEntry root = data.getRoot(); + + System.out.print("Parsing mob stats... "); + for (MapleDataFileEntry mFile : root.getFiles()) { + try { + String fileName = mFile.getName(); + + //System.out.println("Parsing '" + fileName + "'"); + MapleData monsterData = data.getData(fileName); + if (monsterData == null) { + continue; + } + + Integer mid = getMonsterId(fileName); + + MapleData monsterInfoData = monsterData.getChildByPath("info"); + MapleMonsterStats stats = new MapleMonsterStats(); + stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData)); + stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1); + stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData)); + stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData)); + stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData)); + stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData)); + stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0)); + stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0)); + stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData)); + stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0)); + stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0); + stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0); + stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0); + stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0); + stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO")); + stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1)); + stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0)); + stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0); + + MapleData special = monsterInfoData.getChildByPath("coolDamage"); + if (special != null) { + int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData); + int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0); + stats.setCool(new Pair<>(coolDmg, coolProb)); + } + special = monsterInfoData.getChildByPath("loseItem"); + if (special != null) { + for (MapleData liData : special.getChildren()) { + stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x")))); + } + } + special = monsterInfoData.getChildByPath("selfDestruction"); + if (special != null) { + stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1))); + } + MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack"); + int firstAttack = 0; + if (firstAttackData != null) { + if (firstAttackData.getType() == MapleDataType.FLOAT) { + firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData)); + } else { + firstAttack = MapleDataTool.getInt(firstAttackData); + } + } + stats.setFirstAttack(firstAttack > 0); + stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000); + + stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0)); + stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0)); + + for (MapleData idata : monsterData) { + if (!idata.getName().equals("info")) { + int delay = 0; + for (MapleData pic : idata.getChildren()) { + delay += MapleDataTool.getIntConvert("delay", pic, 0); + } + stats.setAnimationTime(idata.getName(), delay); + } + } + MapleData reviveInfo = monsterInfoData.getChildByPath("revive"); + if (reviveInfo != null) { + List revives = new LinkedList<>(); + for (MapleData data_ : reviveInfo) { + revives.add(MapleDataTool.getInt(data_)); + } + stats.setRevives(revives); + } + decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, "")); + MapleData monsterSkillData = monsterInfoData.getChildByPath("skill"); + if (monsterSkillData != null) { + int i = 0; + List> skills = new ArrayList<>(); + while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) { + skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0)))); + i++; + } + stats.setSkills(skills); + } + MapleData banishData = monsterInfoData.getChildByPath("ban"); + if (banishData != null) { + stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp"))); + } + + monsterStats.put(mid, stats); + } catch(NullPointerException npe) { + //System.out.println("[SEVERE] " + mFile.getName() + " failed to load. Issue: " + npe.getMessage() + "\n\n"); + } + } + + System.out.println("done!"); + return monsterStats; + } + + private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) { + for (int i = 0; i < elemAttr.length(); i += 2) { + stats.setEffectiveness(Element.getFromChar(elemAttr.charAt(i)), ElementalEffectiveness.getByNumber(Integer.valueOf(String.valueOf(elemAttr.charAt(i + 1))))); + } + } + + public static class BanishInfo { + + private int map; + private String portal, msg; + + public BanishInfo(String msg, int map, String portal) { + this.msg = msg; + this.map = map; + this.portal = portal; + } + + public int getMap() { + return map; + } + + public String getPortal() { + return portal; + } + + public String getMsg() { + return msg; + } + } + + public static class loseItem { + + private int id; + private byte chance, x; + + private loseItem(int id, byte chance, byte x) { + this.id = id; + this.chance = chance; + this.x = x; + } + + public int getId() { + return id; + } + + public byte getChance() { + return chance; + } + + public byte getX() { + return x; + } + } + + public static class selfDestruction { + + private byte action; + private int removeAfter; + private int hp; + + private selfDestruction(byte action, int removeAfter, int hp) { + this.action = action; + this.removeAfter = removeAfter; + this.hp = hp; + } + + public int getHp() { + return hp; + } + + public byte getAction() { + return action; + } + + public int removeAfter() { + return removeAfter; + } + } +} diff --git a/tools/MapleArrowFetcher/src/life/MapleMonsterStats.java b/tools/MapleArrowFetcher/src/life/MapleMonsterStats.java new file mode 100644 index 0000000000..42b091545d --- /dev/null +++ b/tools/MapleArrowFetcher/src/life/MapleMonsterStats.java @@ -0,0 +1,336 @@ +/* + 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 life; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import life.MapleLifeFactory.BanishInfo; +import life.MapleLifeFactory.loseItem; +import life.MapleLifeFactory.selfDestruction; +import tools.Pair; + +/** + * @author Frz + */ +public class MapleMonsterStats { + private boolean changeable; + private int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive, removeAfter; + private boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss; + private String name; + private Map animationTimes = new HashMap(); + private Map resistance = new HashMap(); + private List revives = Collections.emptyList(); + private byte tagColor, tagBgColor; + private List> skills = new ArrayList>(); + private Pair cool = null; + private BanishInfo banish = null; + private List loseItem = null; + private selfDestruction selfDestruction = null; + private boolean friendly; + + public void setChange(boolean change) { + this.changeable = change; + } + + public boolean isChangeable() { + return changeable; + } + + public int getExp() { + return exp; + } + + public void setExp(int exp) { + this.exp = exp; + } + + public int getHp() { + return hp; + } + + public void setHp(int hp) { + this.hp = hp; + } + + public int getMp() { + return mp; + } + + public void setMp(int mp) { + this.mp = mp; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int removeAfter() { + return removeAfter; + } + + public void setRemoveAfter(int removeAfter) { + this.removeAfter = removeAfter; + } + + public int getDropPeriod() { + return dropPeriod; + } + + public void setDropPeriod(int dropPeriod) { + this.dropPeriod = dropPeriod; + } + + public void setBoss(boolean boss) { + this.boss = boss; + } + + public boolean isBoss() { + return boss; + } + + public void setFfaLoot(boolean ffaLoot) { + this.ffaLoot = ffaLoot; + } + + public boolean isFfaLoot() { + return ffaLoot; + } + + public void setAnimationTime(String name, int delay) { + animationTimes.put(name, delay); + } + + public int getAnimationTime(String name) { + Integer ret = animationTimes.get(name); + if (ret == null) { + return 500; + } + return ret.intValue(); + } + + public boolean isMobile() { + return animationTimes.containsKey("move") || animationTimes.containsKey("fly"); + } + + public List getRevives() { + return revives; + } + + public void setRevives(List revives) { + this.revives = revives; + } + + public void setUndead(boolean undead) { + this.undead = undead; + } + + public boolean getUndead() { + return undead; + } + + public void setEffectiveness(Element e, ElementalEffectiveness ee) { + resistance.put(e, ee); + } + + public ElementalEffectiveness getEffectiveness(Element e) { + ElementalEffectiveness elementalEffectiveness = resistance.get(e); + if (elementalEffectiveness == null) { + return ElementalEffectiveness.NORMAL; + } else { + return elementalEffectiveness; + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte getTagColor() { + return tagColor; + } + + public void setTagColor(int tagColor) { + this.tagColor = (byte) tagColor; + } + + public byte getTagBgColor() { + return tagBgColor; + } + + public void setTagBgColor(int tagBgColor) { + this.tagBgColor = (byte) tagBgColor; + } + + public void setSkills(List> skills) { + for (Pair skill : skills) { + this.skills.add(skill); + } + } + + public List> getSkills() { + return Collections.unmodifiableList(this.skills); + } + + public int getNoSkills() { + return this.skills.size(); + } + + public boolean hasSkill(int skillId, int level) { + for (Pair skill : skills) { + if (skill.getLeft() == skillId && skill.getRight() == level) { + return true; + } + } + return false; + } + + public void setFirstAttack(boolean firstAttack) { + this.firstAttack = firstAttack; + } + + public boolean isFirstAttack() { + return firstAttack; + } + + public void setBuffToGive(int buff) { + this.buffToGive = buff; + } + + public int getBuffToGive() { + return buffToGive; + } + + void removeEffectiveness(Element e) { + resistance.remove(e); + } + + public BanishInfo getBanishInfo() { + return banish; + } + + public void setBanishInfo(BanishInfo banish) { + this.banish = banish; + } + + public int getPADamage() { + return PADamage; + } + + public void setPADamage(int PADamage) { + this.PADamage = PADamage; + } + + public int getCP() { + return cp; + } + + public void setCP(int cp) { + this.cp = cp; + } + + public List loseItem() { + return loseItem; + } + + public void addLoseItem(loseItem li) { + if (loseItem == null) { + loseItem = new LinkedList(); + } + loseItem.add(li); + } + + public selfDestruction selfDestruction() { + return selfDestruction; + } + + public void setSelfDestruction(selfDestruction sd) { + this.selfDestruction = sd; + } + + public void setExplosiveReward(boolean isExplosiveReward) { + this.isExplosiveReward = isExplosiveReward; + } + + public boolean isExplosiveReward() { + return isExplosiveReward; + } + + public void setRemoveOnMiss(boolean removeOnMiss) { + this.removeOnMiss = removeOnMiss; + } + + public boolean removeOnMiss() { + return removeOnMiss; + } + + public void setCool(Pair cool) { + this.cool = cool; + } + + public Pair getCool() { + return cool; + } + + public int getPDDamage() { + return PDDamage; + } + + public int getMADamage() { + return MADamage; + } + + public int getMDDamage() { + return MDDamage; + } + + public boolean isFriendly() { + return friendly; + } + + public void setFriendly(boolean value) { + this.friendly = value; + } + + public void setPDDamage(int PDDamage) { + this.PDDamage = PDDamage; + } + + public void setMADamage(int MADamage) { + this.MADamage = MADamage; + } + + public void setMDDamage(int MDDamage) { + this.MDDamage = MDDamage; + } +} diff --git a/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java b/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java new file mode 100644 index 0000000000..d749506573 --- /dev/null +++ b/tools/MapleArrowFetcher/src/maplearrowfetcher/MapleArrowFetcher.java @@ -0,0 +1,221 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package maplearrowfetcher; + +import life.MapleLifeFactory; +import life.MapleMonsterStats; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import java.io.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import tools.DatabaseConnection; +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. + * + * The arrow quantity range is calculated accordingly with the target mob stats, such + * as level and if it's a boss or not. + * + */ + +public class MapleArrowFetcher { + + /** + * @param args the command line arguments + */ + + private static PrintWriter printWriter; + private static String newFile = "lib/arrow_drop_data.sql"; + + private static int[] arrowWeight = new int[6]; + + private static int minArrowId = 2060000; + private static int maxArrowId = 2061004; + + private static Map mobStats; + private static Map> mobRange = new HashMap<>(); + + private static Pair calcArrowRange(int level, boolean boss) { + int minRange, maxRange; + + // MIN range + minRange = (int)(1.895883884 * Math.exp(0.02673101054) * level * (boss ? 1.4 : 1.0)); + + // MAX range + maxRange = 3 * minRange; + + return new Pair<>(minRange, maxRange); + } + + private static void calcAllMobsArrowRange() { + System.out.print("Calculating range... "); + + for(Entry mobStat : mobStats.entrySet()) { + MapleMonsterStats mms = mobStat.getValue(); + Pair arrowRange; + + arrowRange = calcArrowRange(mms.getLevel(), mms.isBoss()); + mobRange.put(mobStat.getKey(), arrowRange); + } + + System.out.println("done!"); + } + + private static void printSqlHeader() { + printWriter.println(" # SQL File autogenerated from the MapleArrowFetcher feature by Ronan Lana."); + printWriter.println(" # Generated data takes into account mob stats such as level and boss for the raw arrow ranges."); + printWriter.println(" # Only current arrows entries on the DB it was compiled are being updated here."); + printWriter.println(); + + printWriter.println("UPDATE drop_data"); + printWriter.println("SET minimum_quantity = CASE"); + } + + private static void printSqlMiddle() { + printWriter.println(" ELSE minimum_quantity END,"); + printWriter.println(" maximum_quantity = CASE"); + } + + private static void printSqlFooter() { + printWriter.println(" ELSE maximum_quantity END"); + printWriter.println(";"); + } + + private static void updateSqlMobArrowMinEntry(int[] entry) { + printWriter.println(" WHEN dropperid = " + entry[0] + " AND itemid = " + entry[1] + " THEN " + entry[2]); + } + + private static void updateSqlMobArrowMaxEntry(int[] entry) { + printWriter.println(" WHEN dropperid = " + entry[0] + " AND itemid = " + entry[1] + " THEN " + entry[3]); + } + + private static List getArrowEntryValues(Map> existingEntries) { + List entryValues = new ArrayList<>(200); + + List>> listEntries = new ArrayList<>(existingEntries.entrySet()); + + Collections.sort(listEntries, new Comparator>>() { + @Override + public int compare(Entry> o1, Entry> o2) { + int val1 = o1.getKey(); + int val2 = o2.getKey(); + return (val1 < val2 ? -1 : (val1 == val2 ? 0 : 1)); + } + }); + + for(Entry> ee : listEntries) { + int mobid = ee.getKey(); + Pair mr = mobRange.get(mobid); + + for(Integer itemid : ee.getValue()) { + int itemWeight = (itemid % 10) + 1; + + int[] values = new int[4]; + values[0] = mobid; + values[1] = itemid; + + values[2] = (int) Math.ceil(mr.getLeft() / itemWeight); // weighted min quantity + values[3] = (int) Math.ceil(mr.getRight() / itemWeight); // weighted max quantity + + entryValues.add(values); + } + } + + return entryValues; + } + + private static void updateMobsArrowRange() { + System.out.print("Generating updated ranges... "); + Connection con = DatabaseConnection.getConnection(); + Map> existingEntries = new HashMap<>(200); + + try { + // select all arrow drop entries on the DB, to update their values + PreparedStatement ps = con.prepareStatement("SELECT dropperid, itemid FROM drop_data WHERE itemid >= " + minArrowId + " AND itemid <= " + maxArrowId + " ORDER BY itemid;"); + ResultSet rs = ps.executeQuery(); + + if (rs.isBeforeFirst()) { + while(rs.next()) { + int mobid = rs.getInt(1); + int itemid = rs.getInt(2); + + if(mobRange.containsKey(mobid)) { + List em = existingEntries.get(mobid); + + if(em == null) { + em = new ArrayList<>(2); + existingEntries.put(mobid, em); + } + + em.add(itemid); + } + } + + if(!existingEntries.isEmpty()) { + List entryValues = getArrowEntryValues(existingEntries); + + printWriter = new PrintWriter(newFile, "UTF-8"); + printSqlHeader(); + + for(int[] arrowEntry : entryValues) { + updateSqlMobArrowMinEntry(arrowEntry); + } + + printSqlMiddle(); + + for(int[] arrowEntry : entryValues) { + updateSqlMobArrowMaxEntry(arrowEntry); + } + + printSqlFooter(); + + printWriter.close(); + } else { + throw new Exception("NO DATA"); + } + + } else { + throw new Exception("NO DATA"); + } + + rs.close(); + ps.close(); + con.close(); + + System.out.println("done!"); + + } catch(Exception e) { + if(e.getMessage() != null && e.getMessage().equals("NO DATA")) { + System.out.println("failed! The DB has no arrow entry to be updated."); + } else { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) { + // load mob stats from WZ + mobStats = MapleLifeFactory.getAllMonsterStats(); + + calcAllMobsArrowRange(); + updateMobsArrowRange(); + } +} diff --git a/tools/MapleArrowFetcher/src/provider/MapleCanvas.java b/tools/MapleArrowFetcher/src/provider/MapleCanvas.java new file mode 100644 index 0000000000..10ab682196 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleData.java b/tools/MapleArrowFetcher/src/provider/MapleData.java new file mode 100644 index 0000000000..4d90a93804 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataDirectoryEntry.java b/tools/MapleArrowFetcher/src/provider/MapleDataDirectoryEntry.java new file mode 100644 index 0000000000..cb043e0c94 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataEntity.java b/tools/MapleArrowFetcher/src/provider/MapleDataEntity.java new file mode 100644 index 0000000000..03ff77649c --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataEntry.java b/tools/MapleArrowFetcher/src/provider/MapleDataEntry.java new file mode 100644 index 0000000000..62db6d0abe --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataFileEntry.java b/tools/MapleArrowFetcher/src/provider/MapleDataFileEntry.java new file mode 100644 index 0000000000..902130a612 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataProvider.java b/tools/MapleArrowFetcher/src/provider/MapleDataProvider.java new file mode 100644 index 0000000000..5237b7ac37 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataProviderFactory.java b/tools/MapleArrowFetcher/src/provider/MapleDataProviderFactory.java new file mode 100644 index 0000000000..14753d4406 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/MapleDataTool.java b/tools/MapleArrowFetcher/src/provider/MapleDataTool.java new file mode 100644 index 0000000000..25f4c7f817 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/FileStoredPngMapleCanvas.java b/tools/MapleArrowFetcher/src/provider/wz/FileStoredPngMapleCanvas.java new file mode 100644 index 0000000000..21736c2c16 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/ImgMapleSound.java b/tools/MapleArrowFetcher/src/provider/wz/ImgMapleSound.java new file mode 100644 index 0000000000..8add2ccb36 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/ListWZFile.java b/tools/MapleArrowFetcher/src/provider/wz/ListWZFile.java new file mode 100644 index 0000000000..1672a08c59 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/MapleDataType.java b/tools/MapleArrowFetcher/src/provider/wz/MapleDataType.java new file mode 100644 index 0000000000..e074d57d14 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/PNGMapleCanvas.java b/tools/MapleArrowFetcher/src/provider/wz/PNGMapleCanvas.java new file mode 100644 index 0000000000..97c2303804 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZDirectoryEntry.java b/tools/MapleArrowFetcher/src/provider/wz/WZDirectoryEntry.java new file mode 100644 index 0000000000..d24b8cb2b9 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZEntry.java b/tools/MapleArrowFetcher/src/provider/wz/WZEntry.java new file mode 100644 index 0000000000..1e921b2082 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZFile.java b/tools/MapleArrowFetcher/src/provider/wz/WZFile.java new file mode 100644 index 0000000000..c6c0abf537 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZFileEntry.java b/tools/MapleArrowFetcher/src/provider/wz/WZFileEntry.java new file mode 100644 index 0000000000..792371d9cf --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZIMGEntry.java b/tools/MapleArrowFetcher/src/provider/wz/WZIMGEntry.java new file mode 100644 index 0000000000..385d785183 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZIMGFile.java b/tools/MapleArrowFetcher/src/provider/wz/WZIMGFile.java new file mode 100644 index 0000000000..bec06c78bd --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/WZTool.java b/tools/MapleArrowFetcher/src/provider/wz/WZTool.java new file mode 100644 index 0000000000..85e1c8d90b --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/XMLDomMapleData.java b/tools/MapleArrowFetcher/src/provider/wz/XMLDomMapleData.java new file mode 100644 index 0000000000..151a04c2fd --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/provider/wz/XMLWZFile.java b/tools/MapleArrowFetcher/src/provider/wz/XMLWZFile.java new file mode 100644 index 0000000000..2a7694fdc9 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/DatabaseConnection.java b/tools/MapleArrowFetcher/src/tools/DatabaseConnection.java new file mode 100644 index 0000000000..27ea52da04 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/HexTool.java b/tools/MapleArrowFetcher/src/tools/HexTool.java new file mode 100644 index 0000000000..8cc0c8aa84 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/Pair.java b/tools/MapleArrowFetcher/src/tools/Pair.java new file mode 100644 index 0000000000..f88718cbe3 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/ByteArrayByteStream.java b/tools/MapleArrowFetcher/src/tools/data/input/ByteArrayByteStream.java new file mode 100644 index 0000000000..eac7de21ea --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/ByteInputStream.java b/tools/MapleArrowFetcher/src/tools/data/input/ByteInputStream.java new file mode 100644 index 0000000000..107f71843e --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/GenericLittleEndianAccessor.java b/tools/MapleArrowFetcher/src/tools/data/input/GenericLittleEndianAccessor.java new file mode 100644 index 0000000000..d08a9b8374 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java b/tools/MapleArrowFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java new file mode 100644 index 0000000000..fdd147d796 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/InputStreamByteStream.java b/tools/MapleArrowFetcher/src/tools/data/input/InputStreamByteStream.java new file mode 100644 index 0000000000..70aef3489f --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/LittleEndianAccessor.java b/tools/MapleArrowFetcher/src/tools/data/input/LittleEndianAccessor.java new file mode 100644 index 0000000000..f991dbf537 --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/RandomAccessByteStream.java b/tools/MapleArrowFetcher/src/tools/data/input/RandomAccessByteStream.java new file mode 100644 index 0000000000..c0004be17f --- /dev/null +++ b/tools/MapleArrowFetcher/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/MapleArrowFetcher/src/tools/data/input/SeekableInputStreamBytestream.java b/tools/MapleArrowFetcher/src/tools/data/input/SeekableInputStreamBytestream.java new file mode 100644 index 0000000000..f4922dc876 --- /dev/null +++ b/tools/MapleArrowFetcher/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 + + 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 interface to a stream of bytes. This stream can be + * seeked. + * + * @author Frz + * @version 1.0 + * @since 299 + */ +public interface SeekableInputStreamBytestream extends ByteInputStream { + /** + * Seeks the stream by the specified offset. + * + * @param offset + * Number of bytes to seek. + * @throws IOException + */ + void seek(long offset) throws IOException; + + /** + * Gets the current position of the stream. + * + * @return The stream position as a long integer. + * @throws IOException + */ + long getPosition() throws IOException; +} diff --git a/tools/MapleArrowFetcher/src/tools/data/input/SeekableLittleEndianAccessor.java b/tools/MapleArrowFetcher/src/tools/data/input/SeekableLittleEndianAccessor.java new file mode 100644 index 0000000000..16b2317f7a --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/input/SeekableLittleEndianAccessor.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 tools.data.input; + +public interface SeekableLittleEndianAccessor extends LittleEndianAccessor { + void seek(long offset); + long getPosition(); +} diff --git a/tools/MapleArrowFetcher/src/tools/data/output/BAOSByteOutputStream.java b/tools/MapleArrowFetcher/src/tools/data/output/BAOSByteOutputStream.java new file mode 100644 index 0000000000..80cbc9301e --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/output/BAOSByteOutputStream.java @@ -0,0 +1,56 @@ +/* + 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.output; + +import java.io.ByteArrayOutputStream; + +/** + * Uses a byte array to output a stream of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 352 + */ +class BAOSByteOutputStream implements ByteOutputStream { + private ByteArrayOutputStream baos; + + /** + * Class constructor - Wraps the stream around a Java BAOS. + * + * @param baos The ByteArrayOutputStream to wrap this around. + */ + BAOSByteOutputStream(ByteArrayOutputStream baos) { + super(); + this.baos = baos; + } + + /** + * Writes a byte to the stream. + * + * @param b The byte to write to the stream. + * @see tools.data.output.ByteOutputStream#writeByte(byte) + */ + @Override + public void writeByte(byte b) { + baos.write(b); + } +} diff --git a/tools/MapleArrowFetcher/src/tools/data/output/ByteOutputStream.java b/tools/MapleArrowFetcher/src/tools/data/output/ByteOutputStream.java new file mode 100644 index 0000000000..0df7ca7753 --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/output/ByteOutputStream.java @@ -0,0 +1,38 @@ +/* + 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.output; + +/** + * Provides an interface to an output stream of bytes. + * + * @author Frz + * @since Revision 323 + * @version 1.0 + */ +interface ByteOutputStream { + /** + * Writes a byte to the stream. + * + * @param b The byte to write. + */ + void writeByte(byte b); +} diff --git a/tools/MapleArrowFetcher/src/tools/data/output/GenericLittleEndianWriter.java b/tools/MapleArrowFetcher/src/tools/data/output/GenericLittleEndianWriter.java new file mode 100644 index 0000000000..e804fd8000 --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/output/GenericLittleEndianWriter.java @@ -0,0 +1,183 @@ +/* + 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.output; + +import java.awt.Point; +import java.nio.charset.Charset; + +/** + * Provides a generic writer of a little-endian sequence of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 323 + */ +public class GenericLittleEndianWriter implements LittleEndianWriter { + private static Charset ASCII = Charset.forName("US-ASCII"); + private ByteOutputStream bos; + + /** + * Class constructor - Protected to prevent instantiation with no arguments. + */ + protected GenericLittleEndianWriter() { + // Blah! + } + + /** + * Sets the byte-output stream for this instance of the object. + * + * @param bos The new output stream to set. + */ + void setByteOutputStream(ByteOutputStream bos) { + this.bos = bos; + } + + /** + * Write an array of bytes to the stream. + * + * @param b The bytes to write. + */ + @Override + public void write(byte[] b) { + for (int x = 0; x < b.length; x++) { + bos.writeByte(b[x]); + } + } + + /** + * Write a byte to the stream. + * + * @param b The byte to write. + */ + @Override + public void write(byte b) { + bos.writeByte(b); + } + + /** + * Write a byte in integer form to the stream. + * + * @param b The byte as an Integer to write. + */ + @Override + public void write(int b) { + bos.writeByte((byte) b); + } + + @Override + public void skip(int b) { + write(new byte[b]); + } + + /** + * Write a short integer to the stream. + * + * @param i The short integer to write. + */ + @Override + public void writeShort(int i) { + bos.writeByte((byte) (i & 0xFF)); + bos.writeByte((byte) ((i >>> 8) & 0xFF)); + } + + /** + * Writes an integer to the stream. + * + * @param i The integer to write. + */ + @Override + public void writeInt(int i) { + bos.writeByte((byte) (i & 0xFF)); + bos.writeByte((byte) ((i >>> 8) & 0xFF)); + bos.writeByte((byte) ((i >>> 16) & 0xFF)); + bos.writeByte((byte) ((i >>> 24) & 0xFF)); + } + + /** + * Writes an ASCII string the the stream. + * + * @param s The ASCII string to write. + */ + @Override + public void writeAsciiString(String s) { + write(s.getBytes(ASCII)); + } + + /** + * Writes a maple-convention ASCII string to the stream. + * + * @param s The ASCII string to use maple-convention to write. + */ + @Override + public void writeMapleAsciiString(String s) { + writeShort((short) s.length()); + writeAsciiString(s); + } + + /** + * Writes a null-terminated ASCII string to the stream. + * + * @param s The ASCII string to write. + */ + @Override + public void writeNullTerminatedAsciiString(String s) { + writeAsciiString(s); + write(0); + } + + /** + * Write a long integer to the stream. + * @param l The long integer to write. + */ + @Override + public void writeLong(long l) { + bos.writeByte((byte) (l & 0xFF)); + bos.writeByte((byte) ((l >>> 8) & 0xFF)); + bos.writeByte((byte) ((l >>> 16) & 0xFF)); + bos.writeByte((byte) ((l >>> 24) & 0xFF)); + bos.writeByte((byte) ((l >>> 32) & 0xFF)); + bos.writeByte((byte) ((l >>> 40) & 0xFF)); + bos.writeByte((byte) ((l >>> 48) & 0xFF)); + bos.writeByte((byte) ((l >>> 56) & 0xFF)); + } + + /** + * Writes a 2D 4 byte position information + * + * @param s The Point position to write. + */ + @Override + public void writePos(Point s) { + writeShort(s.x); + writeShort(s.y); + } + + /** + * Writes a boolean true ? 1 : 0 + * + * @param b The boolean to write. + */ + @Override + public void writeBool(final boolean b) { + write(b ? 1 : 0); + } +} diff --git a/tools/MapleArrowFetcher/src/tools/data/output/LittleEndianWriter.java b/tools/MapleArrowFetcher/src/tools/data/output/LittleEndianWriter.java new file mode 100644 index 0000000000..f17bd7c72e --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/output/LittleEndianWriter.java @@ -0,0 +1,114 @@ +/* + 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.output; + +import java.awt.Point; + +/** + * Provides an interface to a writer class that writes a little-endian sequence + * of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 323 + */ +public interface LittleEndianWriter { + + /** + * Write an array of bytes to the sequence. + * + * @param b The bytes to write. + */ + public void write(byte b[]); + + /** + * Write a byte to the sequence. + * + * @param b The byte to write. + */ + public void write(byte b); + + /** + * Write a byte in integer form to the sequence. + * + * @param b The byte as an Integer to write. + */ + public void write(int b); + + public void skip(int b); + + /** + * Writes an integer to the sequence. + * + * @param i The integer to write. + */ + public void writeInt(int i); + + /** + * Write a short integer to the sequence. + * + * @param s The short integer to write. + */ + public void writeShort(int s); + + /** + * Write a long integer to the sequence. + * + * @param l The long integer to write. + */ + public void writeLong(long l); + + /** + * Writes an ASCII string the the sequence. + * + * @param s The ASCII string to write. + */ + void writeAsciiString(String s); + + /** + * Writes a null-terminated ASCII string to the sequence. + * + * @param s The ASCII string to write. + */ + void writeNullTerminatedAsciiString(String s); + + /** + * Writes a maple-convention ASCII string to the sequence. + * + * @param s The ASCII string to use maple-convention to write. + */ + void writeMapleAsciiString(String s); + + /** + * Writes a 2D 4 byte position information + * + * @param s The Point position to write. + */ + void writePos(Point s); + + /** + * Writes a boolean true ? 1 : 0 + * + * @param b The boolean to write. + */ + void writeBool(final boolean b); +} diff --git a/tools/MapleArrowFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java b/tools/MapleArrowFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java new file mode 100644 index 0000000000..b02365ec62 --- /dev/null +++ b/tools/MapleArrowFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java @@ -0,0 +1,73 @@ +/* + 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.output; + +import java.io.ByteArrayOutputStream; +import tools.HexTool; + +/** + * Writes a maplestory-packet little-endian stream of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 352 + */ +public class MaplePacketLittleEndianWriter extends GenericLittleEndianWriter { + private ByteArrayOutputStream baos; + + /** + * Constructor - initializes this stream with a default size. + */ + public MaplePacketLittleEndianWriter() { + this(32); + } + + /** + * Constructor - initializes this stream with size size. + * + * @param size The size of the underlying stream. + */ + public MaplePacketLittleEndianWriter(int size) { + this.baos = new ByteArrayOutputStream(size); + setByteOutputStream(new BAOSByteOutputStream(baos)); + } + + /** + * Gets a MaplePacket instance representing this + * sequence of bytes. + * + * @return A MaplePacket with the bytes in this stream. + */ + public byte[] getPacket() { + return baos.toByteArray(); + } + + /** + * Changes this packet into a human-readable hexadecimal stream of bytes. + * + * @return This packet as hex digits. + */ + @Override + public String toString() { + return HexTool.toString(baos.toByteArray()); + } +} diff --git a/tools/MapleMesoFetcher/build.xml b/tools/MapleMesoFetcher/build.xml new file mode 100644 index 0000000000..8c94f0120f --- /dev/null +++ b/tools/MapleMesoFetcher/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project MapleMesoFetcher. + + + diff --git a/tools/MapleMesoFetcher/lib/meso_drop_data.sql b/tools/MapleMesoFetcher/lib/meso_drop_data.sql new file mode 100644 index 0000000000..4908feff3a --- /dev/null +++ b/tools/MapleMesoFetcher/lib/meso_drop_data.sql @@ -0,0 +1,447 @@ + # SQL File autogenerated from the MapleMesoFetcher feature by Ronan Lana. + # Generated data takes into account mob stats such as level and boss for the meso ranges. + # Only mobs with 4 or more items with no meso entry on the DB it was compiled are presented here. + + INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES +(100122, 0, 14, 20, 0, 400000), +(100123, 0, 19, 29, 0, 400000), +(100124, 0, 25, 37, 0, 400000), +(100130, 0, 2, 4, 0, 400000), +(100131, 0, 8, 12, 0, 400000), +(100132, 0, 14, 20, 0, 400000), +(100133, 0, 19, 29, 0, 400000), +(100134, 0, 25, 37, 0, 400000), +(1110130, 0, 42, 62, 0, 400000), +(1140130, 0, 54, 79, 0, 400000), +(2100100, 0, 56, 83, 0, 400000), +(2100101, 0, 59, 87, 0, 400000), +(2100106, 0, 68, 100, 0, 400000), +(2100107, 0, 76, 112, 0, 400000), +(2100108, 0, 82, 121, 0, 400000), +(2110300, 0, 68, 100, 0, 400000), +(2110301, 0, 82, 121, 0, 400000), +(2230105, 0, 65, 96, 0, 400000), +(2230107, 0, 68, 100, 0, 400000), +(2230110, 0, 65, 96, 0, 400000), +(2230111, 0, 68, 100, 0, 400000), +(2230131, 0, 68, 100, 0, 400000), +(3000005, 0, 85, 125, 0, 400000), +(3100101, 0, 91, 133, 0, 400000), +(3100102, 0, 85, 125, 0, 400000), +(3110301, 0, 91, 133, 0, 400000), +(3110302, 0, 99, 146, 0, 400000), +(3110303, 0, 108, 158, 0, 400000), +(3220000, 0, 297, 1460, 0, 400000), +(3220001, 0, 324, 1580, 0, 400000), +(3300000, 0, 85, 125, 0, 400000), +(3300001, 0, 85, 125, 0, 400000), +(3300002, 0, 88, 129, 0, 400000), +(3300003, 0, 91, 133, 0, 400000), +(3300004, 0, 93, 137, 0, 400000), +(3300005, 0, 99, 146, 0, 400000), +(3300006, 0, 99, 146, 0, 400000), +(3300007, 0, 99, 146, 0, 400000), +(3300008, 0, 324, 1580, 0, 400000), +(4110300, 0, 119, 175, 0, 400000), +(4110301, 0, 128, 187, 0, 400000), +(4130103, 0, 399, 1960, 0, 400000), +(4220000, 0, 384, 1870, 0, 400000), +(4230122, 0, 119, 175, 0, 400000), +(4230125, 0, 125, 183, 0, 400000), +(4230400, 0, 128, 187, 0, 400000), +(4230502, 0, 122, 179, 0, 400000), +(4230503, 0, 128, 187, 0, 400000), +(4230504, 0, 128, 187, 0, 400000), +(4230600, 0, 113, 167, 0, 400000), +(4240000, 0, 139, 204, 0, 400000), +(4250000, 0, 119, 175, 0, 400000), +(4250001, 0, 131, 192, 0, 400000), +(5110300, 0, 142, 208, 0, 400000), +(5120500, 0, 159, 233, 0, 400000), +(5120501, 0, 150, 221, 0, 400000), +(5120502, 0, 153, 225, 0, 400000), +(5120505, 0, 165, 242, 0, 400000), +(5120506, 0, 156, 229, 0, 400000), +(5130105, 0, 159, 233, 0, 400000), +(5130108, 0, 162, 238, 0, 400000), +(5220000, 0, 468, 2290, 0, 400000), +(5220002, 0, 426, 2080, 0, 400000), +(5220003, 0, 504, 2460, 0, 400000), +(5220004, 0, 426, 2080, 0, 400000), +(5250000, 0, 156, 229, 0, 400000), +(5250001, 0, 145, 213, 0, 400000), +(5250002, 0, 162, 238, 0, 400000), +(6110300, 0, 185, 271, 0, 400000), +(6130102, 0, 170, 250, 0, 400000), +(6130103, 0, 170, 250, 0, 400000), +(6130203, 0, 170, 250, 0, 400000), +(6130207, 0, 176, 258, 0, 400000), +(6130209, 0, 187, 275, 0, 400000), +(6220000, 0, 555, 2710, 0, 400000), +(6220001, 0, 555, 2710, 0, 400000), +(6230100, 0, 176, 258, 0, 400000), +(6230401, 0, 179, 263, 0, 400000), +(6300005, 0, 555, 2710, 0, 400000), +(6400006, 0, 375, 1830, 0, 400000), +(6400008, 0, 468, 2290, 0, 400000), +(6400009, 0, 468, 2290, 0, 400000), +(7110300, 0, 213, 313, 0, 400000), +(7110301, 0, 207, 304, 0, 400000), +(7120103, 0, 199, 292, 0, 400000), +(7120104, 0, 202, 296, 0, 400000), +(7120106, 0, 213, 313, 0, 400000), +(7120107, 0, 213, 313, 0, 400000), +(7120108, 0, 219, 321, 0, 400000), +(7120109, 0, 225, 329, 0, 400000), +(7130000, 0, 207, 304, 0, 400000), +(7130002, 0, 205, 300, 0, 400000), +(7130003, 0, 216, 317, 0, 400000), +(7130004, 0, 222, 325, 0, 400000), +(7130102, 0, 222, 325, 0, 400000), +(7130103, 0, 207, 304, 0, 400000), +(7130400, 0, 597, 2920, 0, 400000), +(7130401, 0, 597, 2920, 0, 400000), +(7130402, 0, 597, 2920, 0, 400000), +(7130601, 0, 216, 317, 0, 400000), +(7220000, 0, 606, 2960, 0, 400000), +(7220001, 0, 597, 2920, 0, 400000), +(7220002, 0, 657, 3210, 0, 400000), +(8110300, 0, 227, 334, 0, 400000), +(8120102, 0, 233, 342, 0, 400000), +(8120103, 0, 239, 350, 0, 400000), +(8120104, 0, 244, 359, 0, 400000), +(8120105, 0, 250, 367, 0, 400000), +(8120106, 0, 253, 371, 0, 400000), +(8120107, 0, 253, 371, 0, 400000), +(8140000, 0, 227, 334, 0, 400000), +(8140100, 0, 233, 342, 0, 400000), +(8140511, 0, 615, 1130, 0, 400000), +(8140512, 0, 628, 1154, 0, 400000), +(8140600, 0, 622, 1142, 0, 400000), +(8140702, 0, 642, 1179, 0, 400000), +(8140703, 0, 655, 1204, 0, 400000), +(8141300, 0, 635, 1167, 0, 400000), +(8150000, 0, 2028, 12410, 0, 400000), +(8150100, 0, 676, 1241, 0, 400000), +(8150101, 0, 689, 1266, 0, 400000), +(8150200, 0, 676, 1241, 0, 400000), +(8150201, 0, 710, 1303, 0, 400000), +(8150300, 0, 655, 1204, 0, 400000), +(8150301, 0, 683, 1254, 0, 400000), +(8150302, 0, 696, 1279, 0, 400000), +(8190001, 0, 710, 1303, 0, 400000), +(8220003, 0, 2433, 14900, 0, 400000), +(8220005, 0, 2655, 16260, 0, 400000), +(8220006, 0, 2859, 17510, 0, 400000), +(8220007, 0, 1824, 11170, 0, 400000), +(8220009, 0, 726, 3550, 0, 400000), +(8830000, 0, 2130, 13030, 0, 400000), +(9001009, 0, 681, 3340, 0, 400000), +(9001011, 0, 99, 146, 0, 400000), +(9200016, 0, 85, 125, 0, 400000), +(9200019, 0, 165, 242, 0, 400000), +(9300011, 0, 111, 162, 0, 400000), +(9300058, 0, 19, 29, 0, 400000), +(9300059, 0, 28, 41, 0, 400000), +(9300060, 0, 119, 175, 0, 400000), +(9300078, 0, 710, 1303, 0, 400000), +(9300080, 0, 193, 284, 0, 400000), +(9300096, 0, 250, 367, 0, 400000), +(9300105, 0, 537, 2630, 0, 400000), +(9300106, 0, 579, 2840, 0, 400000), +(9300127, 0, 85, 125, 0, 400000), +(9300129, 0, 85, 125, 0, 400000), +(9300131, 0, 111, 162, 0, 400000), +(9300132, 0, 85, 125, 0, 400000), +(9300133, 0, 85, 125, 0, 400000), +(9300134, 0, 85, 125, 0, 400000), +(9300136, 0, 255, 1250, 0, 400000), +(9300139, 0, 690, 3380, 0, 400000), +(9300155, 0, 19, 29, 0, 400000), +(9300160, 0, 384, 1870, 0, 400000), +(9300161, 0, 384, 1870, 0, 400000), +(9300163, 0, 811, 1490, 0, 400000), +(9300164, 0, 811, 1490, 0, 400000), +(9300165, 0, 811, 1490, 0, 400000), +(9300182, 0, 726, 3550, 0, 400000), +(9300184, 0, 168, 830, 0, 400000), +(9300185, 0, 297, 1460, 0, 400000), +(9300186, 0, 324, 1580, 0, 400000), +(9300187, 0, 339, 1670, 0, 400000), +(9300188, 0, 426, 2080, 0, 400000), +(9300189, 0, 426, 2080, 0, 400000), +(9300190, 0, 468, 2290, 0, 400000), +(9300191, 0, 510, 2500, 0, 400000), +(9300192, 0, 477, 2330, 0, 400000), +(9300193, 0, 504, 2460, 0, 400000), +(9300194, 0, 555, 2710, 0, 400000), +(9300195, 0, 555, 2710, 0, 400000), +(9300196, 0, 555, 2710, 0, 400000), +(9300197, 0, 555, 2710, 0, 400000), +(9300198, 0, 510, 2500, 0, 400000), +(9300199, 0, 597, 2920, 0, 400000), +(9300200, 0, 606, 2960, 0, 400000), +(9300201, 0, 726, 3550, 0, 400000), +(9300202, 0, 657, 3210, 0, 400000), +(9300203, 0, 681, 3340, 0, 400000), +(9300204, 0, 708, 3460, 0, 400000), +(9300205, 0, 690, 3380, 0, 400000), +(9300206, 0, 726, 3550, 0, 400000), +(9300207, 0, 726, 3550, 0, 400000), +(9300208, 0, 1824, 11170, 0, 400000), +(9300209, 0, 1824, 11170, 0, 400000), +(9300210, 0, 2028, 12410, 0, 400000), +(9300211, 0, 2130, 13030, 0, 400000), +(9300212, 0, 2130, 13030, 0, 400000), +(9300213, 0, 2433, 14900, 0, 400000), +(9300214, 0, 2535, 15520, 0, 400000), +(9300215, 0, 3042, 18620, 0, 400000), +(9300217, 0, 5, 8, 0, 400000), +(9300218, 0, 11, 16, 0, 400000), +(9300219, 0, 11, 16, 0, 400000), +(9300220, 0, 48, 71, 0, 400000), +(9300221, 0, 71, 104, 0, 400000), +(9300222, 0, 79, 116, 0, 400000), +(9300223, 0, 17, 25, 0, 400000), +(9300224, 0, 105, 154, 0, 400000), +(9300225, 0, 105, 154, 0, 400000), +(9300226, 0, 113, 167, 0, 400000), +(9300227, 0, 105, 154, 0, 400000), +(9300228, 0, 136, 200, 0, 400000), +(9300229, 0, 22, 33, 0, 400000), +(9300230, 0, 116, 171, 0, 400000), +(9300231, 0, 131, 192, 0, 400000), +(9300232, 0, 96, 142, 0, 400000), +(9300233, 0, 113, 167, 0, 400000), +(9300234, 0, 91, 133, 0, 400000), +(9300235, 0, 148, 217, 0, 400000), +(9300236, 0, 159, 233, 0, 400000), +(9300237, 0, 168, 246, 0, 400000), +(9300238, 0, 68, 100, 0, 400000), +(9300239, 0, 119, 175, 0, 400000), +(9300240, 0, 128, 187, 0, 400000), +(9300241, 0, 193, 284, 0, 400000), +(9300242, 0, 199, 292, 0, 400000), +(9300243, 0, 159, 233, 0, 400000), +(9300244, 0, 159, 233, 0, 400000), +(9300245, 0, 170, 250, 0, 400000), +(9300246, 0, 176, 258, 0, 400000), +(9300247, 0, 185, 271, 0, 400000), +(9300248, 0, 187, 275, 0, 400000), +(9300249, 0, 199, 292, 0, 400000), +(9300250, 0, 213, 313, 0, 400000), +(9300251, 0, 207, 304, 0, 400000), +(9300252, 0, 128, 187, 0, 400000), +(9300253, 0, 142, 208, 0, 400000), +(9300254, 0, 207, 304, 0, 400000), +(9300255, 0, 133, 196, 0, 400000), +(9300256, 0, 170, 250, 0, 400000), +(9300257, 0, 170, 250, 0, 400000), +(9300258, 0, 185, 271, 0, 400000), +(9300259, 0, 56, 83, 0, 400000), +(9300260, 0, 227, 334, 0, 400000), +(9300261, 0, 250, 367, 0, 400000), +(9300262, 0, 250, 367, 0, 400000), +(9300263, 0, 250, 367, 0, 400000), +(9300264, 0, 696, 1279, 0, 400000), +(9300265, 0, 683, 1254, 0, 400000), +(9300266, 0, 606, 2960, 0, 400000), +(9300267, 0, 681, 3340, 0, 400000), +(9300268, 0, 606, 2960, 0, 400000), +(9300269, 0, 168, 830, 0, 400000), +(9300270, 0, 227, 334, 0, 400000), +(9300274, 0, 22, 33, 0, 400000), +(9300289, 0, 1824, 11170, 0, 400000), +(9300294, 0, 2028, 12410, 0, 400000), +(9300315, 0, 435, 2130, 0, 400000), +(9300316, 0, 450, 2210, 0, 400000), +(9300317, 0, 468, 2290, 0, 400000), +(9300318, 0, 486, 2380, 0, 400000), +(9300319, 0, 504, 2460, 0, 400000), +(9300320, 0, 519, 2540, 0, 400000), +(9300321, 0, 537, 2630, 0, 400000), +(9300322, 0, 555, 2710, 0, 400000), +(9300332, 0, 113, 167, 0, 400000), +(9300334, 0, 139, 204, 0, 400000), +(9300335, 0, 116, 171, 0, 400000), +(9300336, 0, 131, 192, 0, 400000), +(9300337, 0, 131, 192, 0, 400000), +(9300367, 0, 84, 410, 0, 400000), +(9300368, 0, 168, 830, 0, 400000), +(9300369, 0, 255, 1250, 0, 400000), +(9300370, 0, 339, 1670, 0, 400000), +(9300371, 0, 426, 2080, 0, 400000), +(9300372, 0, 510, 2500, 0, 400000), +(9300373, 0, 597, 2920, 0, 400000), +(9300374, 0, 681, 3340, 0, 400000), +(9300375, 0, 1824, 11170, 0, 400000), +(9300376, 0, 1824, 11170, 0, 400000), +(9300377, 0, 2229, 13660, 0, 400000), +(9303000, 0, 28, 41, 0, 400000), +(9303001, 0, 28, 41, 0, 400000), +(9303003, 0, 28, 41, 0, 400000), +(9303004, 0, 28, 41, 0, 400000), +(9303005, 0, 74, 108, 0, 400000), +(9303006, 0, 74, 108, 0, 400000), +(9303007, 0, 74, 108, 0, 400000), +(9303008, 0, 74, 108, 0, 400000), +(9303009, 0, 145, 213, 0, 400000), +(9303010, 0, 145, 213, 0, 400000), +(9303011, 0, 145, 213, 0, 400000), +(9303013, 0, 230, 338, 0, 400000), +(9303014, 0, 230, 338, 0, 400000), +(9303016, 0, 230, 338, 0, 400000), +(9400009, 0, 1352, 2483, 0, 400000), +(9400012, 0, 170, 250, 0, 400000), +(9400120, 0, 1926, 11790, 0, 400000), +(9400122, 0, 1926, 11790, 0, 400000), +(9400200, 0, 156, 229, 0, 400000), +(9400203, 0, 113, 167, 0, 400000), +(9400205, 0, 1824, 11170, 0, 400000), +(9400238, 0, 85, 125, 0, 400000), +(9400239, 0, 68, 100, 0, 400000), +(9400241, 0, 19, 29, 0, 400000), +(9400242, 0, 28, 41, 0, 400000), +(9400243, 0, 156, 229, 0, 400000), +(9400244, 0, 168, 246, 0, 400000), +(9400245, 0, 68, 100, 0, 400000), +(9400246, 0, 62, 91, 0, 400000), +(9400247, 0, 85, 125, 0, 400000), +(9400248, 0, 68, 100, 0, 400000), +(9400500, 0, 6, 40, 0, 400000), +(9400501, 0, 14, 20, 0, 400000), +(9400502, 0, 42, 200, 0, 400000), +(9400503, 0, 42, 200, 0, 400000), +(9400504, 0, 2, 4, 0, 400000), +(9400538, 0, 54, 79, 0, 400000), +(9400539, 0, 59, 87, 0, 400000), +(9400540, 0, 71, 104, 0, 400000), +(9400541, 0, 71, 104, 0, 400000), +(9400542, 0, 102, 150, 0, 400000), +(9400543, 0, 116, 171, 0, 400000), +(9400544, 0, 142, 208, 0, 400000), +(9400546, 0, 125, 183, 0, 400000), +(9400547, 0, 76, 112, 0, 400000), +(9400548, 0, 85, 125, 0, 400000), +(9400550, 0, 76, 112, 0, 400000), +(9400556, 0, 59, 87, 0, 400000), +(9400558, 0, 85, 125, 0, 400000), +(9400560, 0, 142, 208, 0, 400000), +(9400561, 0, 170, 250, 0, 400000), +(9400562, 0, 170, 250, 0, 400000), +(9400563, 0, 113, 167, 0, 400000), +(9400565, 0, 59, 87, 0, 400000), +(9400570, 0, 42, 62, 0, 400000), +(9400571, 0, 426, 2080, 0, 400000), +(9400573, 0, 113, 167, 0, 400000), +(9400574, 0, 676, 1241, 0, 400000), +(9400576, 0, 199, 292, 0, 400000), +(9400578, 0, 608, 1117, 0, 400000), +(9400579, 0, 676, 1241, 0, 400000), +(9400580, 0, 642, 1179, 0, 400000), +(9400581, 0, 227, 334, 0, 400000), +(9400582, 0, 811, 1490, 0, 400000), +(9400609, 0, 213, 1040, 0, 400000), +(9400612, 0, 213, 1040, 0, 400000), +(9400633, 0, 273, 1330, 0, 400000), +(9400644, 0, 28, 41, 0, 400000), +(9410014, 0, 242, 355, 0, 400000), +(9410015, 0, 726, 3550, 0, 400000), +(9420507, 0, 136, 200, 0, 400000), +(9420527, 0, 128, 187, 0, 400000), +(9420528, 0, 133, 196, 0, 400000), +(9420529, 0, 148, 217, 0, 400000), +(9420530, 0, 159, 233, 0, 400000), +(9420531, 0, 168, 246, 0, 400000), +(9420532, 0, 168, 246, 0, 400000), +(9420533, 0, 173, 254, 0, 400000), +(9420534, 0, 185, 271, 0, 400000), +(9420535, 0, 193, 284, 0, 400000), +(9420536, 0, 205, 300, 0, 400000), +(9420537, 0, 213, 313, 0, 400000), +(9420538, 0, 233, 342, 0, 400000), +(9420539, 0, 247, 363, 0, 400000), +(9420545, 0, 168, 246, 0, 400000), +(9420550, 0, 168, 246, 0, 400000), +(9500101, 0, 19, 29, 0, 400000), +(9500102, 0, 22, 33, 0, 400000), +(9500103, 0, 42, 62, 0, 400000), +(9500104, 0, 34, 50, 0, 400000), +(9500105, 0, 42, 62, 0, 400000), +(9500106, 0, 62, 91, 0, 400000), +(9500107, 0, 85, 125, 0, 400000), +(9500108, 0, 91, 133, 0, 400000), +(9500109, 0, 91, 133, 0, 400000), +(9500110, 0, 99, 146, 0, 400000), +(9500111, 0, 99, 146, 0, 400000), +(9500112, 0, 99, 146, 0, 400000), +(9500113, 0, 102, 150, 0, 400000), +(9500115, 0, 105, 154, 0, 400000), +(9500116, 0, 113, 167, 0, 400000), +(9500117, 0, 102, 150, 0, 400000), +(9500118, 0, 111, 162, 0, 400000), +(9500119, 0, 111, 162, 0, 400000), +(9500120, 0, 128, 187, 0, 400000), +(9500121, 0, 136, 200, 0, 400000), +(9500122, 0, 139, 204, 0, 400000), +(9500123, 0, 168, 246, 0, 400000), +(9500124, 0, 510, 2500, 0, 400000), +(9500125, 0, 170, 250, 0, 400000), +(9500126, 0, 182, 267, 0, 400000), +(9500127, 0, 190, 279, 0, 400000), +(9500128, 0, 193, 284, 0, 400000), +(9500129, 0, 199, 292, 0, 400000), +(9500130, 0, 597, 2920, 0, 400000), +(9500131, 0, 207, 304, 0, 400000), +(9500132, 0, 213, 313, 0, 400000), +(9500134, 0, 227, 334, 0, 400000), +(9500135, 0, 242, 355, 0, 400000), +(9500136, 0, 662, 1217, 0, 400000), +(9500137, 0, 642, 1179, 0, 400000), +(9500138, 0, 608, 1117, 0, 400000), +(9500139, 0, 681, 3340, 0, 400000), +(9500140, 0, 2028, 12410, 0, 400000), +(9500156, 0, 136, 200, 0, 400000), +(9500157, 0, 99, 146, 0, 400000), +(9500158, 0, 597, 2920, 0, 400000), +(9500159, 0, 597, 2920, 0, 400000), +(9500160, 0, 597, 2920, 0, 400000), +(9500161, 0, 227, 334, 0, 400000), +(9500162, 0, 227, 334, 0, 400000), +(9500163, 0, 236, 346, 0, 400000), +(9500164, 0, 250, 367, 0, 400000), +(9500165, 0, 250, 367, 0, 400000), +(9500166, 0, 250, 367, 0, 400000), +(9500178, 0, 113, 167, 0, 400000), +(9500180, 0, 1824, 11170, 0, 400000), +(9500181, 0, 1824, 11170, 0, 400000), +(9500306, 0, 168, 830, 0, 400000), +(9500307, 0, 297, 1460, 0, 400000), +(9500308, 0, 426, 2080, 0, 400000), +(9500309, 0, 468, 2290, 0, 400000), +(9500310, 0, 504, 2460, 0, 400000), +(9500311, 0, 555, 2710, 0, 400000), +(9500312, 0, 597, 2920, 0, 400000), +(9500313, 0, 606, 2960, 0, 400000), +(9500314, 0, 657, 3210, 0, 400000), +(9500317, 0, 84, 410, 0, 400000), +(9500318, 0, 339, 1670, 0, 400000), +(9500319, 0, 597, 2920, 0, 400000), +(9500321, 0, 28, 41, 0, 400000), +(9500326, 0, 384, 1870, 0, 400000), +(9500327, 0, 255, 1250, 0, 400000), +(9500328, 0, 297, 1460, 0, 400000), +(9500331, 0, 468, 2290, 0, 400000), +(9500332, 0, 384, 1870, 0, 400000), +(9500333, 0, 426, 2080, 0, 400000), +(9500334, 0, 468, 2290, 0, 400000), +(9500335, 0, 426, 2080, 0, 400000), +(9500366, 0, 42, 62, 0, 400000), +(9500367, 0, 42, 62, 0, 400000), +(9500368, 0, 42, 62, 0, 400000), +(9500369, 0, 42, 62, 0, 400000), +(9500370, 0, 42, 62, 0, 400000), +(9500371, 0, 42, 62, 0, 400000), +(9500372, 0, 42, 62, 0, 400000); + + DELETE FROM drop_data WHERE dropperid >= 9300184 AND dropperid <= 9300215 AND itemid = 0; diff --git a/tools/MapleMesoFetcher/lib/mysql-connector-java-bin.jar b/tools/MapleMesoFetcher/lib/mysql-connector-java-bin.jar new file mode 100644 index 0000000000..0539039f71 Binary files /dev/null and b/tools/MapleMesoFetcher/lib/mysql-connector-java-bin.jar differ diff --git a/tools/MapleMesoFetcher/manifest.mf b/tools/MapleMesoFetcher/manifest.mf new file mode 100644 index 0000000000..328e8e5bc3 --- /dev/null +++ b/tools/MapleMesoFetcher/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/tools/MapleMesoFetcher/src/life/Element.java b/tools/MapleMesoFetcher/src/life/Element.java new file mode 100644 index 0000000000..5520ba3501 --- /dev/null +++ b/tools/MapleMesoFetcher/src/life/Element.java @@ -0,0 +1,46 @@ +/* + 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 life; + +public enum Element { + NEUTRAL, FIRE, ICE, LIGHTING, POISON, HOLY, DARK; + + public static Element getFromChar(char c) { + switch (Character.toUpperCase(c)) { + case 'F': + return FIRE; + case 'I': + return ICE; + case 'L': + return LIGHTING; + case 'S': + return POISON; + case 'H': + return HOLY; + case 'D': + return DARK; + case 'P': + return NEUTRAL; + } + throw new IllegalArgumentException("unknown elemnt char " + c); + } +} diff --git a/tools/MapleMesoFetcher/src/life/ElementalEffectiveness.java b/tools/MapleMesoFetcher/src/life/ElementalEffectiveness.java new file mode 100644 index 0000000000..f8d23ef5c7 --- /dev/null +++ b/tools/MapleMesoFetcher/src/life/ElementalEffectiveness.java @@ -0,0 +1,41 @@ +/* + 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 life; + +public enum ElementalEffectiveness { + NORMAL, IMMUNE, STRONG, WEAK, NEUTRAL; + + public static ElementalEffectiveness getByNumber(int num) { + switch (num) { + case 1: + return IMMUNE; + case 2: + return STRONG; + case 3: + return WEAK; + case 4: + return NEUTRAL; + default: + throw new IllegalArgumentException("Unkown effectiveness: " + num); + } + } +} diff --git a/tools/MapleMesoFetcher/src/life/MapleLifeFactory.java b/tools/MapleMesoFetcher/src/life/MapleLifeFactory.java new file mode 100644 index 0000000000..23ccd67e43 --- /dev/null +++ b/tools/MapleMesoFetcher/src/life/MapleLifeFactory.java @@ -0,0 +1,240 @@ +/* +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 life; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import provider.MapleData; +import provider.MapleDataDirectoryEntry; +import provider.MapleDataFileEntry; +import provider.MapleDataProvider; +import provider.MapleDataProviderFactory; +import provider.MapleDataTool; +import provider.wz.MapleDataType; +import tools.Pair; + +public class MapleLifeFactory { + private static String wzPath = "../../wz"; + private static MapleDataProvider data = MapleDataProviderFactory.getDataProvider(new File(wzPath + "/Mob.wz")); + private final static MapleDataProvider stringDataWZ = MapleDataProviderFactory.getDataProvider(new File(wzPath + "/String.wz")); + private static MapleData mobStringData = stringDataWZ.getData("Mob.img"); + private static MapleData npcStringData = stringDataWZ.getData("Npc.img"); + private static Map monsterStats = new HashMap<>(); + + private static int getMonsterId(String fileName) { + return Integer.parseInt(fileName.substring(0, 7)); + } + + public static Map getAllMonsterStats() { + MapleDataDirectoryEntry root = data.getRoot(); + + System.out.print("Parsing mob stats... "); + for (MapleDataFileEntry mFile : root.getFiles()) { + try { + String fileName = mFile.getName(); + + //System.out.println("Parsing '" + fileName + "'"); + MapleData monsterData = data.getData(fileName); + if (monsterData == null) { + continue; + } + + Integer mid = getMonsterId(fileName); + + MapleData monsterInfoData = monsterData.getChildByPath("info"); + MapleMonsterStats stats = new MapleMonsterStats(); + stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData)); + stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1); + stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData)); + stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData)); + stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData)); + stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData)); + stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0)); + stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0)); + stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData)); + stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0)); + stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0); + stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0); + stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0); + stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0); + stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO")); + stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1)); + stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0)); + stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0); + + MapleData special = monsterInfoData.getChildByPath("coolDamage"); + if (special != null) { + int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData); + int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0); + stats.setCool(new Pair<>(coolDmg, coolProb)); + } + special = monsterInfoData.getChildByPath("loseItem"); + if (special != null) { + for (MapleData liData : special.getChildren()) { + stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x")))); + } + } + special = monsterInfoData.getChildByPath("selfDestruction"); + if (special != null) { + stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1))); + } + MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack"); + int firstAttack = 0; + if (firstAttackData != null) { + if (firstAttackData.getType() == MapleDataType.FLOAT) { + firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData)); + } else { + firstAttack = MapleDataTool.getInt(firstAttackData); + } + } + stats.setFirstAttack(firstAttack > 0); + stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000); + + stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0)); + stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0)); + + for (MapleData idata : monsterData) { + if (!idata.getName().equals("info")) { + int delay = 0; + for (MapleData pic : idata.getChildren()) { + delay += MapleDataTool.getIntConvert("delay", pic, 0); + } + stats.setAnimationTime(idata.getName(), delay); + } + } + MapleData reviveInfo = monsterInfoData.getChildByPath("revive"); + if (reviveInfo != null) { + List revives = new LinkedList<>(); + for (MapleData data_ : reviveInfo) { + revives.add(MapleDataTool.getInt(data_)); + } + stats.setRevives(revives); + } + decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, "")); + MapleData monsterSkillData = monsterInfoData.getChildByPath("skill"); + if (monsterSkillData != null) { + int i = 0; + List> skills = new ArrayList<>(); + while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) { + skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0)))); + i++; + } + stats.setSkills(skills); + } + MapleData banishData = monsterInfoData.getChildByPath("ban"); + if (banishData != null) { + stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp"))); + } + + monsterStats.put(mid, stats); + } catch(NullPointerException npe) { + //System.out.println("[SEVERE] " + mFile.getName() + " failed to load. Issue: " + npe.getMessage() + "\n\n"); + } + } + + System.out.println("done!"); + return monsterStats; + } + + private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) { + for (int i = 0; i < elemAttr.length(); i += 2) { + stats.setEffectiveness(Element.getFromChar(elemAttr.charAt(i)), ElementalEffectiveness.getByNumber(Integer.valueOf(String.valueOf(elemAttr.charAt(i + 1))))); + } + } + + public static class BanishInfo { + + private int map; + private String portal, msg; + + public BanishInfo(String msg, int map, String portal) { + this.msg = msg; + this.map = map; + this.portal = portal; + } + + public int getMap() { + return map; + } + + public String getPortal() { + return portal; + } + + public String getMsg() { + return msg; + } + } + + public static class loseItem { + + private int id; + private byte chance, x; + + private loseItem(int id, byte chance, byte x) { + this.id = id; + this.chance = chance; + this.x = x; + } + + public int getId() { + return id; + } + + public byte getChance() { + return chance; + } + + public byte getX() { + return x; + } + } + + public static class selfDestruction { + + private byte action; + private int removeAfter; + private int hp; + + private selfDestruction(byte action, int removeAfter, int hp) { + this.action = action; + this.removeAfter = removeAfter; + this.hp = hp; + } + + public int getHp() { + return hp; + } + + public byte getAction() { + return action; + } + + public int removeAfter() { + return removeAfter; + } + } +} diff --git a/tools/MapleMesoFetcher/src/life/MapleMonsterStats.java b/tools/MapleMesoFetcher/src/life/MapleMonsterStats.java new file mode 100644 index 0000000000..42b091545d --- /dev/null +++ b/tools/MapleMesoFetcher/src/life/MapleMonsterStats.java @@ -0,0 +1,336 @@ +/* + 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 life; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import life.MapleLifeFactory.BanishInfo; +import life.MapleLifeFactory.loseItem; +import life.MapleLifeFactory.selfDestruction; +import tools.Pair; + +/** + * @author Frz + */ +public class MapleMonsterStats { + private boolean changeable; + private int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive, removeAfter; + private boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss; + private String name; + private Map animationTimes = new HashMap(); + private Map resistance = new HashMap(); + private List revives = Collections.emptyList(); + private byte tagColor, tagBgColor; + private List> skills = new ArrayList>(); + private Pair cool = null; + private BanishInfo banish = null; + private List loseItem = null; + private selfDestruction selfDestruction = null; + private boolean friendly; + + public void setChange(boolean change) { + this.changeable = change; + } + + public boolean isChangeable() { + return changeable; + } + + public int getExp() { + return exp; + } + + public void setExp(int exp) { + this.exp = exp; + } + + public int getHp() { + return hp; + } + + public void setHp(int hp) { + this.hp = hp; + } + + public int getMp() { + return mp; + } + + public void setMp(int mp) { + this.mp = mp; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int removeAfter() { + return removeAfter; + } + + public void setRemoveAfter(int removeAfter) { + this.removeAfter = removeAfter; + } + + public int getDropPeriod() { + return dropPeriod; + } + + public void setDropPeriod(int dropPeriod) { + this.dropPeriod = dropPeriod; + } + + public void setBoss(boolean boss) { + this.boss = boss; + } + + public boolean isBoss() { + return boss; + } + + public void setFfaLoot(boolean ffaLoot) { + this.ffaLoot = ffaLoot; + } + + public boolean isFfaLoot() { + return ffaLoot; + } + + public void setAnimationTime(String name, int delay) { + animationTimes.put(name, delay); + } + + public int getAnimationTime(String name) { + Integer ret = animationTimes.get(name); + if (ret == null) { + return 500; + } + return ret.intValue(); + } + + public boolean isMobile() { + return animationTimes.containsKey("move") || animationTimes.containsKey("fly"); + } + + public List getRevives() { + return revives; + } + + public void setRevives(List revives) { + this.revives = revives; + } + + public void setUndead(boolean undead) { + this.undead = undead; + } + + public boolean getUndead() { + return undead; + } + + public void setEffectiveness(Element e, ElementalEffectiveness ee) { + resistance.put(e, ee); + } + + public ElementalEffectiveness getEffectiveness(Element e) { + ElementalEffectiveness elementalEffectiveness = resistance.get(e); + if (elementalEffectiveness == null) { + return ElementalEffectiveness.NORMAL; + } else { + return elementalEffectiveness; + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte getTagColor() { + return tagColor; + } + + public void setTagColor(int tagColor) { + this.tagColor = (byte) tagColor; + } + + public byte getTagBgColor() { + return tagBgColor; + } + + public void setTagBgColor(int tagBgColor) { + this.tagBgColor = (byte) tagBgColor; + } + + public void setSkills(List> skills) { + for (Pair skill : skills) { + this.skills.add(skill); + } + } + + public List> getSkills() { + return Collections.unmodifiableList(this.skills); + } + + public int getNoSkills() { + return this.skills.size(); + } + + public boolean hasSkill(int skillId, int level) { + for (Pair skill : skills) { + if (skill.getLeft() == skillId && skill.getRight() == level) { + return true; + } + } + return false; + } + + public void setFirstAttack(boolean firstAttack) { + this.firstAttack = firstAttack; + } + + public boolean isFirstAttack() { + return firstAttack; + } + + public void setBuffToGive(int buff) { + this.buffToGive = buff; + } + + public int getBuffToGive() { + return buffToGive; + } + + void removeEffectiveness(Element e) { + resistance.remove(e); + } + + public BanishInfo getBanishInfo() { + return banish; + } + + public void setBanishInfo(BanishInfo banish) { + this.banish = banish; + } + + public int getPADamage() { + return PADamage; + } + + public void setPADamage(int PADamage) { + this.PADamage = PADamage; + } + + public int getCP() { + return cp; + } + + public void setCP(int cp) { + this.cp = cp; + } + + public List loseItem() { + return loseItem; + } + + public void addLoseItem(loseItem li) { + if (loseItem == null) { + loseItem = new LinkedList(); + } + loseItem.add(li); + } + + public selfDestruction selfDestruction() { + return selfDestruction; + } + + public void setSelfDestruction(selfDestruction sd) { + this.selfDestruction = sd; + } + + public void setExplosiveReward(boolean isExplosiveReward) { + this.isExplosiveReward = isExplosiveReward; + } + + public boolean isExplosiveReward() { + return isExplosiveReward; + } + + public void setRemoveOnMiss(boolean removeOnMiss) { + this.removeOnMiss = removeOnMiss; + } + + public boolean removeOnMiss() { + return removeOnMiss; + } + + public void setCool(Pair cool) { + this.cool = cool; + } + + public Pair getCool() { + return cool; + } + + public int getPDDamage() { + return PDDamage; + } + + public int getMADamage() { + return MADamage; + } + + public int getMDDamage() { + return MDDamage; + } + + public boolean isFriendly() { + return friendly; + } + + public void setFriendly(boolean value) { + this.friendly = value; + } + + public void setPDDamage(int PDDamage) { + this.PDDamage = PDDamage; + } + + public void setMADamage(int MADamage) { + this.MADamage = MADamage; + } + + public void setMDDamage(int MDDamage) { + this.MDDamage = MDDamage; + } +} diff --git a/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java b/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java new file mode 100644 index 0000000000..380db25050 --- /dev/null +++ b/tools/MapleMesoFetcher/src/maplemesofetcher/MapleMesoFetcher.java @@ -0,0 +1,200 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package maplemesofetcher; + +import life.MapleLifeFactory; +import life.MapleMonsterStats; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import java.io.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import tools.DatabaseConnection; +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. + * + * The meso range is calculated accordingly with the target mob stats, such as level + * and if it's a boss or not, similarly as how it has been done for the actual meso + * drops. + * + */ + +public class MapleMesoFetcher { + + /** + * @param args the command line arguments + */ + + private static PrintWriter printWriter; + private static String newFile = "lib/meso_drop_data.sql"; + + private static boolean permitMesosOnDojoBosses = false; + + private static float correctionFactor = 11.0f; + private static int minItems = 4; + + private static int mesoid = 0; + private static int chance = 400000; + + private static Map mobStats; + private static Map> mobRange = new HashMap<>(); + + private static Pair calcMesoRange90(int level, boolean boss) { + int minRange, maxRange; + + // MIN range + minRange = (int)(72.70814714 * Math.exp(0.02284640619) * level / correctionFactor); + + // MAX range + maxRange = (int)(133.8194881 * Math.exp(0.02059225059) * level / correctionFactor); + + // boss perks + if(boss) { + minRange *= 3; + maxRange *= 10; + } + + return new Pair<>(minRange, maxRange); + } + + private static Pair calcMesoRange(int level, boolean boss) { + int minRange, maxRange; + + // MIN range + minRange = (int)(30.32032228 * Math.exp(0.0328114493) * level / correctionFactor); + + // MAX range + maxRange = (int)(44.45878459 * Math.exp(0.03289611686) * level / correctionFactor); + + // boss perks + if(boss) { + minRange *= 3; + maxRange *= 10; + } + + return new Pair<>(minRange, maxRange); + } + + private static void calcAllMobsMesoRange() { + System.out.print("Calculating range... "); + + for(Entry mobStat : mobStats.entrySet()) { + MapleMonsterStats mms = mobStat.getValue(); + Pair mesoRange; + + if(mms.getLevel() < 90) { + mesoRange = calcMesoRange(mms.getLevel(), mms.isBoss()); + } else { + mesoRange = calcMesoRange90(mms.getLevel(), mms.isBoss()); + } + + mobRange.put(mobStat.getKey(), mesoRange); + } + + System.out.println("done!"); + } + + private static void printSqlHeader() { + printWriter.println(" # SQL File autogenerated from the MapleMesoFetcher feature by Ronan Lana."); + printWriter.println(" # Generated data takes into account mob stats such as level and boss for the meso ranges."); + printWriter.println(" # Only mobs with " + minItems + " or more items with no meso entry on the DB it was compiled are presented here."); + printWriter.println(); + + printWriter.println(" INSERT IGNORE INTO drop_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES"); + } + + private static void printSqlExceptions() { + if(!permitMesosOnDojoBosses) { + printWriter.println("\r\n DELETE FROM drop_data WHERE dropperid >= 9300184 AND dropperid <= 9300215 AND itemid = " + mesoid + ";"); + } + } + + private static void printSqlMobMesoRange(int mobid) { + Pair mobmeso = mobRange.get(mobid); + printWriter.println("(" + mobid + ", " + mesoid + ", " + mobmeso.left + ", " + mobmeso.right + ", 0, " + chance + "),"); + } + + private static void printSqlMobMesoRangeFinal(int mobid) { + Pair mobmeso = mobRange.get(mobid); + printWriter.println("(" + mobid + ", " + mesoid + ", " + mobmeso.left + ", " + mobmeso.right + ", 0, " + chance + ");"); + } + + private static void generateMissingMobsMesoRange() { + System.out.print("Generating missing ranges... "); + Connection con = DatabaseConnection.getConnection(); + List existingMobs = new ArrayList<>(200); + + try { + // select all mobs which doesn't drop mesos and have a fair amount of items dropping (meaning they are not an event mob) + PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE dropperid NOT IN (SELECT DISTINCT dropperid FROM drop_data WHERE itemid = 0) GROUP BY dropperid HAVING count(*) >= " + minItems + ";"); + ResultSet rs = ps.executeQuery(); + + if (rs.isBeforeFirst()) { + while(rs.next()) { + int mobid = rs.getInt(1); + + if(mobRange.containsKey(mobid)) { + existingMobs.add(mobid); + } + } + + if(!existingMobs.isEmpty()) { + printWriter = new PrintWriter(newFile, "UTF-8"); + printSqlHeader(); + + for(int i = 0; i < existingMobs.size() - 1; i++) + printSqlMobMesoRange(existingMobs.get(i)); + + printSqlMobMesoRangeFinal(existingMobs.get(existingMobs.size() - 1)); + + printSqlExceptions(); + + printWriter.close(); + } else { + throw new Exception("ALREADY UPDATED"); + } + + } else { + throw new Exception("ALREADY UPDATED"); + } + + rs.close(); + ps.close(); + con.close(); + + System.out.println("done!"); + + } catch(Exception e) { + if(e.getMessage() != null && e.getMessage().equals("ALREADY UPDATED")) { + System.out.println("done! The DB is already up-to-date, no file generated."); + } else { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) { + // load mob stats from WZ + mobStats = MapleLifeFactory.getAllMonsterStats(); + + calcAllMobsMesoRange(); + generateMissingMobsMesoRange(); + } + +} diff --git a/tools/MapleMesoFetcher/src/provider/MapleCanvas.java b/tools/MapleMesoFetcher/src/provider/MapleCanvas.java new file mode 100644 index 0000000000..10ab682196 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleData.java b/tools/MapleMesoFetcher/src/provider/MapleData.java new file mode 100644 index 0000000000..4d90a93804 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataDirectoryEntry.java b/tools/MapleMesoFetcher/src/provider/MapleDataDirectoryEntry.java new file mode 100644 index 0000000000..cb043e0c94 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataEntity.java b/tools/MapleMesoFetcher/src/provider/MapleDataEntity.java new file mode 100644 index 0000000000..03ff77649c --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataEntry.java b/tools/MapleMesoFetcher/src/provider/MapleDataEntry.java new file mode 100644 index 0000000000..62db6d0abe --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataFileEntry.java b/tools/MapleMesoFetcher/src/provider/MapleDataFileEntry.java new file mode 100644 index 0000000000..902130a612 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataProvider.java b/tools/MapleMesoFetcher/src/provider/MapleDataProvider.java new file mode 100644 index 0000000000..5237b7ac37 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataProviderFactory.java b/tools/MapleMesoFetcher/src/provider/MapleDataProviderFactory.java new file mode 100644 index 0000000000..14753d4406 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/MapleDataTool.java b/tools/MapleMesoFetcher/src/provider/MapleDataTool.java new file mode 100644 index 0000000000..25f4c7f817 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/FileStoredPngMapleCanvas.java b/tools/MapleMesoFetcher/src/provider/wz/FileStoredPngMapleCanvas.java new file mode 100644 index 0000000000..21736c2c16 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/ImgMapleSound.java b/tools/MapleMesoFetcher/src/provider/wz/ImgMapleSound.java new file mode 100644 index 0000000000..8add2ccb36 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/ListWZFile.java b/tools/MapleMesoFetcher/src/provider/wz/ListWZFile.java new file mode 100644 index 0000000000..1672a08c59 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/MapleDataType.java b/tools/MapleMesoFetcher/src/provider/wz/MapleDataType.java new file mode 100644 index 0000000000..e074d57d14 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/PNGMapleCanvas.java b/tools/MapleMesoFetcher/src/provider/wz/PNGMapleCanvas.java new file mode 100644 index 0000000000..97c2303804 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZDirectoryEntry.java b/tools/MapleMesoFetcher/src/provider/wz/WZDirectoryEntry.java new file mode 100644 index 0000000000..d24b8cb2b9 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZEntry.java b/tools/MapleMesoFetcher/src/provider/wz/WZEntry.java new file mode 100644 index 0000000000..1e921b2082 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZFile.java b/tools/MapleMesoFetcher/src/provider/wz/WZFile.java new file mode 100644 index 0000000000..c6c0abf537 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZFileEntry.java b/tools/MapleMesoFetcher/src/provider/wz/WZFileEntry.java new file mode 100644 index 0000000000..792371d9cf --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZIMGEntry.java b/tools/MapleMesoFetcher/src/provider/wz/WZIMGEntry.java new file mode 100644 index 0000000000..385d785183 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZIMGFile.java b/tools/MapleMesoFetcher/src/provider/wz/WZIMGFile.java new file mode 100644 index 0000000000..bec06c78bd --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/WZTool.java b/tools/MapleMesoFetcher/src/provider/wz/WZTool.java new file mode 100644 index 0000000000..85e1c8d90b --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/XMLDomMapleData.java b/tools/MapleMesoFetcher/src/provider/wz/XMLDomMapleData.java new file mode 100644 index 0000000000..151a04c2fd --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/provider/wz/XMLWZFile.java b/tools/MapleMesoFetcher/src/provider/wz/XMLWZFile.java new file mode 100644 index 0000000000..2a7694fdc9 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/DatabaseConnection.java b/tools/MapleMesoFetcher/src/tools/DatabaseConnection.java new file mode 100644 index 0000000000..27ea52da04 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/HexTool.java b/tools/MapleMesoFetcher/src/tools/HexTool.java new file mode 100644 index 0000000000..8cc0c8aa84 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/Pair.java b/tools/MapleMesoFetcher/src/tools/Pair.java new file mode 100644 index 0000000000..f88718cbe3 --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/Pair.java @@ -0,0 +1,121 @@ +/* +This file is part of the OdinMS Maple Story Server +Copyright (C) 2008 ~ 2010 Patrick Huy +Matthias Butz +Jan Christian Meyer + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License version 3 +as published by the Free Software Foundation. You may not use, modify +or distribute this program under any other version of the +GNU Affero General Public License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + */ +package tools; + +/** + * Represents a pair of values. + * + * @author Frz + * @since Revision 333 + * @version 1.0 + * + * @param The type of the left value. + * @param The type of the right value. + */ +public class Pair { + + public E left; + public F right; + + /** + * Class constructor - pairs two objects together. + * + * @param left The left object. + * @param right The right object. + */ + public Pair(E left, F right) { + this.left = left; + this.right = right; + } + + /** + * Gets the left value. + * + * @return The left value. + */ + public E getLeft() { + return left; + } + + /** + * Gets the right value. + * + * @return The right value. + */ + public F getRight() { + return right; + } + + /** + * Turns the pair into a string. + * + * @return Each value of the pair as a string joined by a colon. + */ + @Override + public String toString() { + return left.toString() + ":" + right.toString(); + } + + /** + * Gets the hash code of this pair. + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((left == null) ? 0 : left.hashCode()); + result = prime * result + ((right == null) ? 0 : right.hashCode()); + return result; + } + + /** + * Checks to see if two pairs are equal. + */ + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Pair other = (Pair) obj; + if (left == null) { + if (other.left != null) { + return false; + } + } else if (!left.equals(other.left)) { + return false; + } + if (right == null) { + if (other.right != null) { + return false; + } + } else if (!right.equals(other.right)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/tools/MapleMesoFetcher/src/tools/data/input/ByteArrayByteStream.java b/tools/MapleMesoFetcher/src/tools/data/input/ByteArrayByteStream.java new file mode 100644 index 0000000000..eac7de21ea --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/ByteInputStream.java b/tools/MapleMesoFetcher/src/tools/data/input/ByteInputStream.java new file mode 100644 index 0000000000..107f71843e --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/GenericLittleEndianAccessor.java b/tools/MapleMesoFetcher/src/tools/data/input/GenericLittleEndianAccessor.java new file mode 100644 index 0000000000..d08a9b8374 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java b/tools/MapleMesoFetcher/src/tools/data/input/GenericSeekableLittleEndianAccessor.java new file mode 100644 index 0000000000..fdd147d796 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/InputStreamByteStream.java b/tools/MapleMesoFetcher/src/tools/data/input/InputStreamByteStream.java new file mode 100644 index 0000000000..70aef3489f --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/LittleEndianAccessor.java b/tools/MapleMesoFetcher/src/tools/data/input/LittleEndianAccessor.java new file mode 100644 index 0000000000..f991dbf537 --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/RandomAccessByteStream.java b/tools/MapleMesoFetcher/src/tools/data/input/RandomAccessByteStream.java new file mode 100644 index 0000000000..c0004be17f --- /dev/null +++ b/tools/MapleMesoFetcher/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/MapleMesoFetcher/src/tools/data/input/SeekableInputStreamBytestream.java b/tools/MapleMesoFetcher/src/tools/data/input/SeekableInputStreamBytestream.java new file mode 100644 index 0000000000..f4922dc876 --- /dev/null +++ b/tools/MapleMesoFetcher/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 + + 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 interface to a stream of bytes. This stream can be + * seeked. + * + * @author Frz + * @version 1.0 + * @since 299 + */ +public interface SeekableInputStreamBytestream extends ByteInputStream { + /** + * Seeks the stream by the specified offset. + * + * @param offset + * Number of bytes to seek. + * @throws IOException + */ + void seek(long offset) throws IOException; + + /** + * Gets the current position of the stream. + * + * @return The stream position as a long integer. + * @throws IOException + */ + long getPosition() throws IOException; +} diff --git a/tools/MapleMesoFetcher/src/tools/data/input/SeekableLittleEndianAccessor.java b/tools/MapleMesoFetcher/src/tools/data/input/SeekableLittleEndianAccessor.java new file mode 100644 index 0000000000..16b2317f7a --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/input/SeekableLittleEndianAccessor.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 tools.data.input; + +public interface SeekableLittleEndianAccessor extends LittleEndianAccessor { + void seek(long offset); + long getPosition(); +} diff --git a/tools/MapleMesoFetcher/src/tools/data/output/BAOSByteOutputStream.java b/tools/MapleMesoFetcher/src/tools/data/output/BAOSByteOutputStream.java new file mode 100644 index 0000000000..80cbc9301e --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/output/BAOSByteOutputStream.java @@ -0,0 +1,56 @@ +/* + 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.output; + +import java.io.ByteArrayOutputStream; + +/** + * Uses a byte array to output a stream of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 352 + */ +class BAOSByteOutputStream implements ByteOutputStream { + private ByteArrayOutputStream baos; + + /** + * Class constructor - Wraps the stream around a Java BAOS. + * + * @param baos The ByteArrayOutputStream to wrap this around. + */ + BAOSByteOutputStream(ByteArrayOutputStream baos) { + super(); + this.baos = baos; + } + + /** + * Writes a byte to the stream. + * + * @param b The byte to write to the stream. + * @see tools.data.output.ByteOutputStream#writeByte(byte) + */ + @Override + public void writeByte(byte b) { + baos.write(b); + } +} diff --git a/tools/MapleMesoFetcher/src/tools/data/output/ByteOutputStream.java b/tools/MapleMesoFetcher/src/tools/data/output/ByteOutputStream.java new file mode 100644 index 0000000000..0df7ca7753 --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/output/ByteOutputStream.java @@ -0,0 +1,38 @@ +/* + 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.output; + +/** + * Provides an interface to an output stream of bytes. + * + * @author Frz + * @since Revision 323 + * @version 1.0 + */ +interface ByteOutputStream { + /** + * Writes a byte to the stream. + * + * @param b The byte to write. + */ + void writeByte(byte b); +} diff --git a/tools/MapleMesoFetcher/src/tools/data/output/GenericLittleEndianWriter.java b/tools/MapleMesoFetcher/src/tools/data/output/GenericLittleEndianWriter.java new file mode 100644 index 0000000000..e804fd8000 --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/output/GenericLittleEndianWriter.java @@ -0,0 +1,183 @@ +/* + 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.output; + +import java.awt.Point; +import java.nio.charset.Charset; + +/** + * Provides a generic writer of a little-endian sequence of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 323 + */ +public class GenericLittleEndianWriter implements LittleEndianWriter { + private static Charset ASCII = Charset.forName("US-ASCII"); + private ByteOutputStream bos; + + /** + * Class constructor - Protected to prevent instantiation with no arguments. + */ + protected GenericLittleEndianWriter() { + // Blah! + } + + /** + * Sets the byte-output stream for this instance of the object. + * + * @param bos The new output stream to set. + */ + void setByteOutputStream(ByteOutputStream bos) { + this.bos = bos; + } + + /** + * Write an array of bytes to the stream. + * + * @param b The bytes to write. + */ + @Override + public void write(byte[] b) { + for (int x = 0; x < b.length; x++) { + bos.writeByte(b[x]); + } + } + + /** + * Write a byte to the stream. + * + * @param b The byte to write. + */ + @Override + public void write(byte b) { + bos.writeByte(b); + } + + /** + * Write a byte in integer form to the stream. + * + * @param b The byte as an Integer to write. + */ + @Override + public void write(int b) { + bos.writeByte((byte) b); + } + + @Override + public void skip(int b) { + write(new byte[b]); + } + + /** + * Write a short integer to the stream. + * + * @param i The short integer to write. + */ + @Override + public void writeShort(int i) { + bos.writeByte((byte) (i & 0xFF)); + bos.writeByte((byte) ((i >>> 8) & 0xFF)); + } + + /** + * Writes an integer to the stream. + * + * @param i The integer to write. + */ + @Override + public void writeInt(int i) { + bos.writeByte((byte) (i & 0xFF)); + bos.writeByte((byte) ((i >>> 8) & 0xFF)); + bos.writeByte((byte) ((i >>> 16) & 0xFF)); + bos.writeByte((byte) ((i >>> 24) & 0xFF)); + } + + /** + * Writes an ASCII string the the stream. + * + * @param s The ASCII string to write. + */ + @Override + public void writeAsciiString(String s) { + write(s.getBytes(ASCII)); + } + + /** + * Writes a maple-convention ASCII string to the stream. + * + * @param s The ASCII string to use maple-convention to write. + */ + @Override + public void writeMapleAsciiString(String s) { + writeShort((short) s.length()); + writeAsciiString(s); + } + + /** + * Writes a null-terminated ASCII string to the stream. + * + * @param s The ASCII string to write. + */ + @Override + public void writeNullTerminatedAsciiString(String s) { + writeAsciiString(s); + write(0); + } + + /** + * Write a long integer to the stream. + * @param l The long integer to write. + */ + @Override + public void writeLong(long l) { + bos.writeByte((byte) (l & 0xFF)); + bos.writeByte((byte) ((l >>> 8) & 0xFF)); + bos.writeByte((byte) ((l >>> 16) & 0xFF)); + bos.writeByte((byte) ((l >>> 24) & 0xFF)); + bos.writeByte((byte) ((l >>> 32) & 0xFF)); + bos.writeByte((byte) ((l >>> 40) & 0xFF)); + bos.writeByte((byte) ((l >>> 48) & 0xFF)); + bos.writeByte((byte) ((l >>> 56) & 0xFF)); + } + + /** + * Writes a 2D 4 byte position information + * + * @param s The Point position to write. + */ + @Override + public void writePos(Point s) { + writeShort(s.x); + writeShort(s.y); + } + + /** + * Writes a boolean true ? 1 : 0 + * + * @param b The boolean to write. + */ + @Override + public void writeBool(final boolean b) { + write(b ? 1 : 0); + } +} diff --git a/tools/MapleMesoFetcher/src/tools/data/output/LittleEndianWriter.java b/tools/MapleMesoFetcher/src/tools/data/output/LittleEndianWriter.java new file mode 100644 index 0000000000..f17bd7c72e --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/output/LittleEndianWriter.java @@ -0,0 +1,114 @@ +/* + 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.output; + +import java.awt.Point; + +/** + * Provides an interface to a writer class that writes a little-endian sequence + * of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 323 + */ +public interface LittleEndianWriter { + + /** + * Write an array of bytes to the sequence. + * + * @param b The bytes to write. + */ + public void write(byte b[]); + + /** + * Write a byte to the sequence. + * + * @param b The byte to write. + */ + public void write(byte b); + + /** + * Write a byte in integer form to the sequence. + * + * @param b The byte as an Integer to write. + */ + public void write(int b); + + public void skip(int b); + + /** + * Writes an integer to the sequence. + * + * @param i The integer to write. + */ + public void writeInt(int i); + + /** + * Write a short integer to the sequence. + * + * @param s The short integer to write. + */ + public void writeShort(int s); + + /** + * Write a long integer to the sequence. + * + * @param l The long integer to write. + */ + public void writeLong(long l); + + /** + * Writes an ASCII string the the sequence. + * + * @param s The ASCII string to write. + */ + void writeAsciiString(String s); + + /** + * Writes a null-terminated ASCII string to the sequence. + * + * @param s The ASCII string to write. + */ + void writeNullTerminatedAsciiString(String s); + + /** + * Writes a maple-convention ASCII string to the sequence. + * + * @param s The ASCII string to use maple-convention to write. + */ + void writeMapleAsciiString(String s); + + /** + * Writes a 2D 4 byte position information + * + * @param s The Point position to write. + */ + void writePos(Point s); + + /** + * Writes a boolean true ? 1 : 0 + * + * @param b The boolean to write. + */ + void writeBool(final boolean b); +} diff --git a/tools/MapleMesoFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java b/tools/MapleMesoFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java new file mode 100644 index 0000000000..b02365ec62 --- /dev/null +++ b/tools/MapleMesoFetcher/src/tools/data/output/MaplePacketLittleEndianWriter.java @@ -0,0 +1,73 @@ +/* + 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.output; + +import java.io.ByteArrayOutputStream; +import tools.HexTool; + +/** + * Writes a maplestory-packet little-endian stream of bytes. + * + * @author Frz + * @version 1.0 + * @since Revision 352 + */ +public class MaplePacketLittleEndianWriter extends GenericLittleEndianWriter { + private ByteArrayOutputStream baos; + + /** + * Constructor - initializes this stream with a default size. + */ + public MaplePacketLittleEndianWriter() { + this(32); + } + + /** + * Constructor - initializes this stream with size size. + * + * @param size The size of the underlying stream. + */ + public MaplePacketLittleEndianWriter(int size) { + this.baos = new ByteArrayOutputStream(size); + setByteOutputStream(new BAOSByteOutputStream(baos)); + } + + /** + * Gets a MaplePacket instance representing this + * sequence of bytes. + * + * @return A MaplePacket with the bytes in this stream. + */ + public byte[] getPacket() { + return baos.toByteArray(); + } + + /** + * Changes this packet into a human-readable hexadecimal stream of bytes. + * + * @return This packet as hex digits. + */ + @Override + public String toString() { + return HexTool.toString(baos.toByteArray()); + } +} diff --git a/tools/MobBookUpdate/nbproject/private/private.properties b/tools/MobBookUpdate/nbproject/private/private.properties index 67c9c27960..adc8a8f46a 100644 --- a/tools/MobBookUpdate/nbproject/private/private.properties +++ b/tools/MobBookUpdate/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/wz/Map.wz/Map/Map9/914000200.img.xml b/wz/Map.wz/Map/Map9/914000200.img.xml index 25df13e9ca..c610adbf09 100644 --- a/wz/Map.wz/Map/Map9/914000200.img.xml +++ b/wz/Map.wz/Map/Map9/914000200.img.xml @@ -1 +1,1686 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wz/Mob.wz/9300295.img.xml b/wz/Mob.wz/9300295.img.xml index a527f6ada5..fa4b5e9f04 100644 --- a/wz/Mob.wz/9300295.img.xml +++ b/wz/Mob.wz/9300295.img.xml @@ -22,7 +22,7 @@ - + diff --git a/wz/Mob.wz/9300296.img.xml b/wz/Mob.wz/9300296.img.xml index 673edfaf9d..797eeb3eb9 100644 --- a/wz/Mob.wz/9300296.img.xml +++ b/wz/Mob.wz/9300296.img.xml @@ -23,7 +23,7 @@ - + diff --git a/wz/String.wz/Map.img.xml b/wz/String.wz/Map.img.xml index b6bcbf4fa8..11ee13d785 100644 --- a/wz/String.wz/Map.img.xml +++ b/wz/String.wz/Map.img.xml @@ -1 +1,17720 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wz/String.wz/Skill.img.xml b/wz/String.wz/Skill.img.xml index 1c971d2b04..84d5a33308 100644 --- a/wz/String.wz/Skill.img.xml +++ b/wz/String.wz/Skill.img.xml @@ -1 +1,12727 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +